294 lines
9.9 KiB
Python
294 lines
9.9 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# Created on 2018年7月26日
|
||
|
# author: Irony
|
||
|
# site: https://github.com/892768447
|
||
|
# email: 892768447@qq.com
|
||
|
# file: QGraphicsView练习.QGraphicsItem.ttt
|
||
|
# description:
|
||
|
|
||
|
__Author__ = """By: Irony
|
||
|
QQ: 892768447
|
||
|
Email: 892768447@qq.com"""
|
||
|
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||
|
__Version__ = 1.0
|
||
|
|
||
|
import sys
|
||
|
|
||
|
from PyQt5.QtCore import Qt, QRectF, QPointF
|
||
|
from PyQt5.QtGui import QBrush, QPainterPath, QPainter, QColor, QPen, QPixmap
|
||
|
from PyQt5.QtWidgets import QGraphicsRectItem, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem
|
||
|
|
||
|
|
||
|
class GraphicsRectItem(QGraphicsRectItem):
|
||
|
|
||
|
handleTopLeft = 1
|
||
|
handleTopMiddle = 2
|
||
|
handleTopRight = 3
|
||
|
handleMiddleLeft = 4
|
||
|
handleMiddleRight = 5
|
||
|
handleBottomLeft = 6
|
||
|
handleBottomMiddle = 7
|
||
|
handleBottomRight = 8
|
||
|
|
||
|
handleSize = +8.0
|
||
|
handleSpace = -4.0
|
||
|
|
||
|
handleCursors = {
|
||
|
handleTopLeft: Qt.SizeFDiagCursor,
|
||
|
handleTopMiddle: Qt.SizeVerCursor,
|
||
|
handleTopRight: Qt.SizeBDiagCursor,
|
||
|
handleMiddleLeft: Qt.SizeHorCursor,
|
||
|
handleMiddleRight: Qt.SizeHorCursor,
|
||
|
handleBottomLeft: Qt.SizeBDiagCursor,
|
||
|
handleBottomMiddle: Qt.SizeVerCursor,
|
||
|
handleBottomRight: Qt.SizeFDiagCursor,
|
||
|
}
|
||
|
|
||
|
def __init__(self, *args):
|
||
|
"""
|
||
|
Initialize the shape.
|
||
|
"""
|
||
|
super().__init__(*args)
|
||
|
self.handles = {}
|
||
|
self.handleSelected = None
|
||
|
self.mousePressPos = None
|
||
|
self.mousePressRect = None
|
||
|
self.setAcceptHoverEvents(True)
|
||
|
self.setFlag(QGraphicsItem.ItemIsMovable, True)
|
||
|
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
|
||
|
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
|
||
|
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
|
||
|
self.updateHandlesPos()
|
||
|
|
||
|
def handleAt(self, point):
|
||
|
"""
|
||
|
Returns the resize handle below the given point.
|
||
|
"""
|
||
|
for k, v, in self.handles.items():
|
||
|
if v.contains(point):
|
||
|
return k
|
||
|
return None
|
||
|
|
||
|
def hoverMoveEvent(self, moveEvent):
|
||
|
"""
|
||
|
Executed when the mouse moves over the shape (NOT PRESSED).
|
||
|
"""
|
||
|
if self.isSelected():
|
||
|
handle = self.handleAt(moveEvent.pos())
|
||
|
cursor = Qt.ArrowCursor if handle is None else self.handleCursors[handle]
|
||
|
self.setCursor(cursor)
|
||
|
super().hoverMoveEvent(moveEvent)
|
||
|
|
||
|
def hoverLeaveEvent(self, moveEvent):
|
||
|
"""
|
||
|
Executed when the mouse leaves the shape (NOT PRESSED).
|
||
|
"""
|
||
|
self.setCursor(Qt.ArrowCursor)
|
||
|
super().hoverLeaveEvent(moveEvent)
|
||
|
|
||
|
def mousePressEvent(self, mouseEvent):
|
||
|
"""
|
||
|
Executed when the mouse is pressed on the item.
|
||
|
"""
|
||
|
self.handleSelected = self.handleAt(mouseEvent.pos())
|
||
|
if self.handleSelected:
|
||
|
self.mousePressPos = mouseEvent.pos()
|
||
|
self.mousePressRect = self.boundingRect()
|
||
|
super().mousePressEvent(mouseEvent)
|
||
|
|
||
|
def mouseMoveEvent(self, mouseEvent):
|
||
|
"""
|
||
|
Executed when the mouse is being moved over the item while being pressed.
|
||
|
"""
|
||
|
if self.handleSelected is not None:
|
||
|
self.interactiveResize(mouseEvent.pos())
|
||
|
else:
|
||
|
super().mouseMoveEvent(mouseEvent)
|
||
|
|
||
|
def mouseReleaseEvent(self, mouseEvent):
|
||
|
"""
|
||
|
Executed when the mouse is released from the item.
|
||
|
"""
|
||
|
super().mouseReleaseEvent(mouseEvent)
|
||
|
self.handleSelected = None
|
||
|
self.mousePressPos = None
|
||
|
self.mousePressRect = None
|
||
|
self.update()
|
||
|
|
||
|
def boundingRect(self):
|
||
|
"""
|
||
|
Returns the bounding rect of the shape (including the resize handles).
|
||
|
"""
|
||
|
o = self.handleSize + self.handleSpace
|
||
|
return self.rect().adjusted(-o, -o, o, o)
|
||
|
|
||
|
def updateHandlesPos(self):
|
||
|
"""
|
||
|
Update current resize handles according to the shape size and position.
|
||
|
"""
|
||
|
s = self.handleSize
|
||
|
b = self.boundingRect()
|
||
|
self.handles[self.handleTopLeft] = QRectF(b.left(), b.top(), s, s)
|
||
|
self.handles[self.handleTopMiddle] = QRectF(b.center().x() - s / 2, b.top(), s, s)
|
||
|
self.handles[self.handleTopRight] = QRectF(b.right() - s, b.top(), s, s)
|
||
|
self.handles[self.handleMiddleLeft] = QRectF(b.left(), b.center().y() - s / 2, s, s)
|
||
|
self.handles[self.handleMiddleRight] = QRectF(b.right() - s, b.center().y() - s / 2, s, s)
|
||
|
self.handles[self.handleBottomLeft] = QRectF(b.left(), b.bottom() - s, s, s)
|
||
|
self.handles[self.handleBottomMiddle] = QRectF(b.center().x() - s / 2, b.bottom() - s, s, s)
|
||
|
self.handles[self.handleBottomRight] = QRectF(b.right() - s, b.bottom() - s, s, s)
|
||
|
|
||
|
def interactiveResize(self, mousePos):
|
||
|
"""
|
||
|
Perform shape interactive resize.
|
||
|
"""
|
||
|
offset = self.handleSize + self.handleSpace
|
||
|
boundingRect = self.boundingRect()
|
||
|
rect = self.rect()
|
||
|
diff = QPointF(0, 0)
|
||
|
|
||
|
self.prepareGeometryChange()
|
||
|
|
||
|
if self.handleSelected == self.handleTopLeft:
|
||
|
|
||
|
fromX = self.mousePressRect.left()
|
||
|
fromY = self.mousePressRect.top()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setX(toX - fromX)
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setLeft(toX)
|
||
|
boundingRect.setTop(toY)
|
||
|
rect.setLeft(boundingRect.left() + offset)
|
||
|
rect.setTop(boundingRect.top() + offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleTopMiddle:
|
||
|
|
||
|
fromY = self.mousePressRect.top()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setTop(toY)
|
||
|
rect.setTop(boundingRect.top() + offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleTopRight:
|
||
|
|
||
|
fromX = self.mousePressRect.right()
|
||
|
fromY = self.mousePressRect.top()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setX(toX - fromX)
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setRight(toX)
|
||
|
boundingRect.setTop(toY)
|
||
|
rect.setRight(boundingRect.right() - offset)
|
||
|
rect.setTop(boundingRect.top() + offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleMiddleLeft:
|
||
|
|
||
|
fromX = self.mousePressRect.left()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
diff.setX(toX - fromX)
|
||
|
boundingRect.setLeft(toX)
|
||
|
rect.setLeft(boundingRect.left() + offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleMiddleRight:
|
||
|
print("MR")
|
||
|
fromX = self.mousePressRect.right()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
diff.setX(toX - fromX)
|
||
|
boundingRect.setRight(toX)
|
||
|
rect.setRight(boundingRect.right() - offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleBottomLeft:
|
||
|
|
||
|
fromX = self.mousePressRect.left()
|
||
|
fromY = self.mousePressRect.bottom()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setX(toX - fromX)
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setLeft(toX)
|
||
|
boundingRect.setBottom(toY)
|
||
|
rect.setLeft(boundingRect.left() + offset)
|
||
|
rect.setBottom(boundingRect.bottom() - offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleBottomMiddle:
|
||
|
|
||
|
fromY = self.mousePressRect.bottom()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setBottom(toY)
|
||
|
rect.setBottom(boundingRect.bottom() - offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
elif self.handleSelected == self.handleBottomRight:
|
||
|
|
||
|
fromX = self.mousePressRect.right()
|
||
|
fromY = self.mousePressRect.bottom()
|
||
|
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
||
|
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
||
|
diff.setX(toX - fromX)
|
||
|
diff.setY(toY - fromY)
|
||
|
boundingRect.setRight(toX)
|
||
|
boundingRect.setBottom(toY)
|
||
|
rect.setRight(boundingRect.right() - offset)
|
||
|
rect.setBottom(boundingRect.bottom() - offset)
|
||
|
self.setRect(rect)
|
||
|
|
||
|
self.updateHandlesPos()
|
||
|
|
||
|
def shape(self):
|
||
|
"""
|
||
|
Returns the shape of this item as a QPainterPath in local coordinates.
|
||
|
"""
|
||
|
path = QPainterPath()
|
||
|
path.addRect(self.rect())
|
||
|
if self.isSelected():
|
||
|
for shape in self.handles.values():
|
||
|
path.addEllipse(shape)
|
||
|
return path
|
||
|
|
||
|
def paint(self, painter, option, widget=None):
|
||
|
"""
|
||
|
Paint the node in the graphic view.
|
||
|
"""
|
||
|
painter.setBrush(QBrush(QColor(255, 0, 0, 100)))
|
||
|
painter.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
|
||
|
painter.drawRect(self.rect())
|
||
|
|
||
|
painter.setRenderHint(QPainter.Antialiasing)
|
||
|
painter.setBrush(QBrush(QColor(255, 0, 0, 255)))
|
||
|
painter.setPen(QPen(QColor(0, 0, 0, 255), 1.0, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
|
||
|
for handle, rect in self.handles.items():
|
||
|
if self.handleSelected is None or handle == self.handleSelected:
|
||
|
painter.drawEllipse(rect)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
|
||
|
app = QApplication(sys.argv)
|
||
|
|
||
|
grview = QGraphicsView()
|
||
|
scene = QGraphicsScene()
|
||
|
scene.setSceneRect(0, 0, 680, 459)
|
||
|
|
||
|
scene.addPixmap(QPixmap('01.png'))
|
||
|
grview.setScene(scene)
|
||
|
|
||
|
item = GraphicsRectItem(0, 0, 300, 150)
|
||
|
scene.addItem(item)
|
||
|
|
||
|
grview.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)
|
||
|
grview.show()
|
||
|
sys.exit(app.exec_())
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|