PyQt/QGraphicsView练习/QGraphicsItem/Item拖拽改变大小.py

171 lines
6.2 KiB
Python
Raw Normal View History

2018-07-26 14:28:16 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年7月26日
@author: Irony
2018-09-25 23:20:03 +08:00
@site: https://pyqt5.com, https://github.com/892768447
2018-07-26 14:28:16 +08:00
@email: 892768447@qq.com
@file: QGraphicsView练习.QGraphicsItem.Item移动
@description:
"""
2018-07-26 22:26:37 +08:00
from PyQt5.QtCore import Qt, QLineF, QRectF
2018-07-26 14:28:16 +08:00
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtWidgets import QGraphicsRectItem, QGraphicsView, QGraphicsScene,\
QStyle
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"
class MoveableItem(QGraphicsRectItem):
def __init__(self, *args, **kwargs):
super(MoveableItem, self).__init__(*args, **kwargs)
2018-07-26 22:26:37 +08:00
self.setPos(0, 0)
2018-07-28 23:15:00 +08:00
# 可移动,可选择,有焦点,发送大小位置改变事件
self.setFlags(self.ItemIsMovable | self.ItemIsSelectable |
self.ItemIsFocusable | self.ItemSendsGeometryChanges)
2018-07-26 14:28:16 +08:00
# 设置接收悬停事件
self.setAcceptHoverEvents(True)
self.setBrush(QColor(247, 160, 57)) # 设置背景颜色
# 是否在调整大小的状态
self.isResizing = False
2018-07-31 11:36:46 +08:00
self.mousePressPos = None
self.mousePressRect = None
2018-07-26 14:28:16 +08:00
def paint(self, painter, option, widget):
super(MoveableItem, self).paint(painter, option, widget)
# 当鼠标选中后在边缘绘制边框
if option.state & QStyle.State_Selected:
rect = self.boundingRect()
painter.setRenderHint(QPainter.Antialiasing, True) # 抗锯齿
2018-07-26 22:26:37 +08:00
x, y, w, h = rect.x(), rect.y(), rect.width(), rect.height()
2018-07-26 14:28:16 +08:00
if option.state & QStyle.State_HasFocus: # 有焦点
2018-07-26 22:26:37 +08:00
painter.setPen(QPen(Qt.red, 3)) # 设置红色画笔
2018-07-31 11:36:46 +08:00
# 在左上、左下、右上、右下、以及四条边上画小线段
painter.drawLines(
2018-07-26 22:26:37 +08:00
QLineF(x, y, x + 10, y), # 左上顶点向右
QLineF(x, y, x, y + 10), # 左上顶点向下
QLineF(x, y + h, x + 10, y + h), # 左下顶点向右
QLineF(x, y + h, x, y + h - 10), # 左下顶点向上
QLineF(x + w, y, x + w - 10, y), # 右上顶点向左
QLineF(x + w, y, x + w, y + 10), # 右上顶点向下
QLineF(x + w, y + h, x + w - 10, y + h), # 右下顶点向左
QLineF(x + w, y + h, x + w, y + h - 10) # 右下顶点向上
2018-07-26 14:28:16 +08:00
)
def hoverMoveEvent(self, event):
super(MoveableItem, self).hoverMoveEvent(event)
2018-07-31 11:36:46 +08:00
# 鼠标悬停事件,用于检测鼠标位置并改变鼠标形态
2018-07-26 22:26:37 +08:00
cursor = self.isInResizeArea(event.pos())
if self.isResizing or (cursor and self.isSelected()):
# 正在调整中或者鼠标在可调整区域范围内并且是选中
self.setCursor(cursor)
else:
self.setCursor(Qt.ArrowCursor)
2018-07-31 11:36:46 +08:00
def hoverLeaveEvent(self, event):
"""鼠标悬停离开事件恢复鼠标样式"""
super(MoveableItem, self).hoverLeaveEvent(event)
self.setCursor(Qt.ArrowCursor)
2018-07-26 22:26:37 +08:00
def mousePressEvent(self, event):
# 鼠标按下
super(MoveableItem, self).mousePressEvent(event)
if event.button() == Qt.LeftButton and self.isInResizeArea(event.pos()):
self.isResizing = True
2018-07-31 11:36:46 +08:00
self.mousePressPos = event.pos()
self.mousePressRect = self.boundingRect()
2018-07-26 22:26:37 +08:00
def mouseReleaseEvent(self, event):
# 鼠标释放开
super(MoveableItem, self).mouseReleaseEvent(event)
if event.button() == Qt.LeftButton and self.isResizing:
self.isResizing = False
2018-07-31 11:36:46 +08:00
self.mousePressPos = None
self.mousePressRect = None
self.update()
2018-07-26 22:26:37 +08:00
def mouseMoveEvent(self, event):
# 鼠标移动
2018-07-31 11:36:46 +08:00
if self.isResizing and self.mousePressPos:
2018-07-26 22:26:37 +08:00
rect = self.boundingRect()
2018-07-31 11:36:46 +08:00
pos = event.pos() - self.mousePressPos
2018-07-26 22:26:37 +08:00
w = pos.x()
h = pos.y()
2018-07-28 23:15:00 +08:00
x = -4 if w > 0 else 4
y = -4 if h > 0 else 4
print(x, y, -x, -y, pos)
2018-07-26 22:26:37 +08:00
self.setRect(rect.adjusted(x, y, -x, -y))
self.prepareGeometryChange()
else:
super(MoveableItem, self).mouseMoveEvent(event)
def isInResizeArea(self, pos):
# 检测判断鼠标所在位置是否为四个顶点的范围内
rect = self.boundingRect()
x, y, w, h = rect.x(), rect.y(), rect.width(), rect.height()
lx = pos.x() < x + 10
rx = pos.x() > x + w - 10
ty = pos.y() < y + 10
by = pos.y() > y + h - 10
# 左上角和右下角
if (lx and ty) or (rx and by):
return Qt.SizeFDiagCursor
# 右上角和左下角
if (rx and ty) or (lx and by):
return Qt.SizeBDiagCursor
2018-07-31 11:36:46 +08:00
# 上、下
if ty or by:
return Qt.SizeVerCursor
if lx or rx:
return Qt.SizeHorCursor
# 左、右
2018-07-26 22:26:37 +08:00
return 0
2018-07-26 14:28:16 +08:00
class ImageWidget(QGraphicsView):
def __init__(self, *args, **kwargs):
super(ImageWidget, self).__init__(*args, **kwargs)
self.resize(800, 600)
# 设置背景颜色
self.setBackgroundBrush(QColor(31, 31, 47))
# 去掉滚动条
# self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# 设置变换中心为鼠标所在位置
self.setTransformationAnchor(self.AnchorUnderMouse)
# 不保证painter的状态
self.setOptimizationFlags(self.DontSavePainterState)
self.setViewportUpdateMode(self.SmartViewportUpdate)
self.setRenderHints(QPainter.Antialiasing |
QPainter.SmoothPixmapTransform)
# 场景
self._scene = QGraphicsScene(0, 0, self.width(), self.height())
self.setScene(self._scene)
self._scene.addItem(MoveableItem(100, 100, 200, 200))
if __name__ == '__main__':
import sys
import cgitb
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = ImageWidget()
w.show()
sys.exit(app.exec_())