Pyqt:自定义框架在 mouseMoveEvent 下不检测鼠标点击
Pyqt: custom frame doesn't detect mouse click under mouseMoveEvent
我已经为 Qgraphics 小部件创建了自定义框架。我遇到了两个问题,首先,一个是在 MouseMoveEvent 下没有检测到点击,即 event.button()
总是 returns 0 即使有鼠标点击。其次,我的 setCursor()
没有改变光标。这是我在自定义框架 class.
下的代码
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt, QRectF, QEvent, QPoint
from PyQt5.QtGui import QPen, QColor, QPainter, QBrush, qRgb, QPolygon
from PyQt5.QtWidgets import *
import sys
class Frame(QFrame):
def __init__(self, parent=None, option=[], margin=0):
super(Frame, self).__init__()
self.parent = parent
self._triangle = QPolygon()
self.options = option
self._margin = margin
self.start_pos = None
# self.parent.setViewport(parent)
self.setStyleSheet('background-color: lightblue')
self.setMouseTracking(True)
self.installEventFilter(self)
self.show()
def update_option(self, option):
self.options = option
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.white)
qp.setBrush(Qt.gray)
qp.drawPolygon(self._triangle)
def _recalculate_triangle(self):
p = QPoint(self.width() - 20, self.height() - 10)
q = QPoint(self.width() - 10, self.height() - 20)
r = QPoint(self.width() - 10, self.height() - 10)
self._triangle = QPolygon([p, q, r])
self.update()
def resizeEvent(self, event):
self._recalculate_triangle()
super().resizeEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if event.button() == Qt.LeftButton and self._triangle.containsPoint(
event.pos(), Qt.OddEvenFill
):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
self.start_pos = event.pos()
# print(self.start_pos)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
if event.button() == Qt.LeftButton:
if event.button() == QtCore.Qt.LeftButton and self.start_pos is not None:
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
delta = event.pos() - self.start_pos
self.n_resize(self.width()+delta.x(), self.height()+delta.y())
self.start_pos = event.pos()
elif not self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseReleaseEvent(event)
def n_resize(self, width, height):
self.resize(width, height)
if __name__ == '__main__':
q = QApplication(sys.argv)
a = Frame()
sys.exit(q.exec())
我也试过使用eventfilter
但是没有用。
编辑:
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPen, QColor, QPainter, QBrush, QPolygon
from PyQt5.QtWidgets import *
import sys
class graphLayout(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.scene = QGraphicsScene()
self.lines = []
self.draw_grid()
self.set_opacity(0.3)
widget = QGraphicsProxyWidget()
t = stack(self)
t.setFlag(QGraphicsItem.ItemIsMovable)
t.resize(340, 330)
self.scene.addItem(t)
self.setScene(self.scene)
self.show()
def create_texture(self):
image = QtGui.QImage(QtCore.QSize(30, 30), QtGui.QImage.Format_RGBA64)
pen = QPen()
pen.setColor(QColor(189, 190, 191))
pen.setWidth(2)
painter = QtGui.QPainter(image)
painter.setPen(pen)
painter.drawRect(image.rect())
painter.end()
return image
def draw_grid(self):
texture = self.create_texture()
brush = QBrush()
# brush.setColor(QColor('#999'))
brush.setTextureImage(texture) # Grid pattern.
self.scene.setBackgroundBrush(brush)
borderColor = Qt.black
fillColor = QColor('#DDD')
def set_visible(self, visible=True):
for line in self.lines:
line.setVisible(visible)
def delete_grid(self):
for line in self.lines:
self.scene.removeItem(line)
del self.lines[:]
def set_opacity(self, opacity):
for line in self.lines:
line.setOpacity(opacity)
def wheelEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
delta = event.angleDelta().y()
if delta > 0:
self.on_zoom_in()
elif delta < 0:
self.on_zoom_out()
super(graphLayout, self).wheelEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.MidButton:
self.setCursor(Qt.OpenHandCursor)
self.mousepos = event.localPos()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
# This helps to pan the area
if event.buttons() == Qt.MidButton:
delta = event.localPos() - self.mousepos
h = self.horizontalScrollBar().value()
v = self.verticalScrollBar().value()
self.horizontalScrollBar().setValue(int(h - delta.x()))
self.verticalScrollBar().setValue(int(v - delta.y()))
self.mousepos = event.localPos()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.unsetCursor()
self.mousepos = event.localPos()
super().mouseReleaseEvent(event)
def on_zoom_in(self):
if self.transform().m11() < 3.375:
self.setTransformationAnchor(self.AnchorUnderMouse)
self.scale(1.5, 1.5)
def on_zoom_out(self):
if self.transform().m11() > 0.7:
self.setTransformationAnchor(self.AnchorUnderMouse)
self.scale(1.0 / 1.5, 1.0 / 1.5)
class stack(QGraphicsWidget):
_margin = 0
def __init__(self, parent=None):
super().__init__()
self.options = []
self.gridlayout = parent
graphic_layout = QGraphicsLinearLayout(Qt.Vertical, self)
self.width, self.height = 10, 10
self.outer_container = Frame(parent, self.options, self._margin)
self.outer_container.setContentsMargins(0, 0, 0, 0)
self.setParent(self.outer_container)
layout = QVBoxLayout()
self.headerLayout = QGridLayout()
self.headerLayout.setContentsMargins(2, 0, 0, 0)
self.top_bar = QFrame()
self.top_bar.setFrameShape(QFrame.StyledPanel)
self.top_bar.setLayout(self.headerLayout)
self.top_bar.setContentsMargins(0, 0, 0, 0)
self.top_bar.setMaximumHeight(30)
# self.contentLayout = QVBoxLayout()
self.contentLayout = QFormLayout()
self.contentLayout.setContentsMargins(10, 10, 10, 10)
self.contentLayout.setSpacing(5)
layout.addWidget(self.top_bar)
layout.addLayout(self.contentLayout)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self.outer_container.setContentsMargins(0, 0, 0, 0)
self.setContentsMargins(0, 0, 0, 0)
self.setMaximumSize(400, 800)
self.outer_container.setLayout(layout)
widget = QGraphicsProxyWidget()
widget.setWidget(self.outer_container)
# todo: figure out a way to add top_bar widget
graphic_layout.addItem(widget)
graphic_layout.setSpacing(0)
graphic_layout.setContentsMargins(0, 0, 0, 0)
# widget move and resize note: don't touch any of these
self.__mouseMovePos = None
self._triangle = QPolygon()
self.start_pos = None
def addHeaderWidget(self, widget=None, column=0, bg_color='green'):
self.top_bar.setStyleSheet(f'background-color:{bg_color};')
self.headerLayout.addWidget(widget, 0, column)
class Frame(QFrame):
def __init__(self, parent=None, option=[], margin=0):
super(Frame, self).__init__()
self.parent = parent
self._triangle = QPolygon()
self.options = option
self._margin = margin
self.start_pos = None
# self.parent.setViewport(parent)
self.setStyleSheet('background-color: lightblue')
self.setMouseTracking(True)
self.installEventFilter(self)
self.show()
def update_option(self, option):
self.options = option
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.white)
qp.setBrush(Qt.gray)
qp.drawPolygon(self._triangle)
def _recalculate_triangle(self):
p = QPoint(self.width() - 20, self.height() - 10)
q = QPoint(self.width() - 10, self.height() - 20)
r = QPoint(self.width() - 10, self.height() - 10)
self._triangle = QPolygon([p, q, r])
self.update()
def resizeEvent(self, event):
self._recalculate_triangle()
super().resizeEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if event.button() == Qt.LeftButton and self._triangle.containsPoint(
event.pos(), Qt.OddEvenFill
):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
self.start_pos = event.pos()
# print(self.start_pos)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
if event.button() == Qt.LeftButton:
if event.button() == QtCore.Qt.LeftButton and self.start_pos is not None:
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
delta = event.pos() - self.start_pos
self.n_resize(self.width()+delta.x(), self.height()+delta.y())
self.start_pos = event.pos()
elif not self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseReleaseEvent(event)
def n_resize(self, width, height):
self.resize(width, height)
if __name__ == '__main__':
q = QApplication(sys.argv)
a = graphLayout()
sys.exit(q.exec())
您的代码存在各种问题,但基本问题是:
- 在 MouseMove 事件中
event.button()
无法检索鼠标按钮状态,event.button<b>s</b>()
应该改用:区别很明显:button()
显示 生成 事件的按钮(鼠标移动事件显然 不是 任意按钮产生),buttons()
显示按钮状态产生事件时;
- 未由对象显式管理的事件总是传播到其父控件,这意味着您的鼠标移动也可能由父控件处理,然后图形代理、场景、视口、视图等,直到顶层 window,直到前面的对象之一实际上 returns
True
来自 event()
或事件过滤器;在您的情况下,它会导致移动图形项目,因为您启用了 ItemIsMovable
标志。
我不知道为什么没有真正设置光标,但坦白说你的代码很复杂,我真的找不到原因。
由于您真正要找的是一种调整小部件大小的方法,我建议您使用另一种解决方案。
虽然使用自定义绘画实现调整大小当然是可行的,但在大多数情况下,使用 QSizeGrip 就足够了(正如另一个 post 中已经向您建议的那样),这是一个允许调整顶层大小的小部件windows 并且能够自动理解哪个“角”用于根据其位置调整大小。请记住 QSizeGrip 的 parent 非常重要,因为它使用它来了解哪个是它的顶层 window,并且在这种情况下,“容器框架”,即使它在 QGraphicsScene 中。
请注意,QSizeGrip 不应不 添加到布局中,并且应始终根据其角 位置和其父级的大小(除非它被放置在左上角),并且由于您已经需要自定义绘画,所以最好将其子类化。
from PyQt5 import QtCore, QtGui, QtWidgets
class SizeGrip(QtWidgets.QSizeGrip):
def __init__(self, parent):
super().__init__(parent)
parent.installEventFilter(self)
self.setFixedSize(30, 30)
self.polygon = QtGui.QPolygon([
QtCore.QPoint(10, 20),
QtCore.QPoint(20, 10),
QtCore.QPoint(20, 20),
])
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.Resize:
geo = self.rect()
geo.moveBottomRight(source.rect().bottomRight())
self.setGeometry(geo)
return super().eventFilter(source, event)
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(QtCore.Qt.white)
qp.setBrush(QtCore.Qt.gray)
qp.drawPolygon(self.polygon)
class Container(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sizeGrip = SizeGrip(self)
self.startPos = None
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(6, 6, 6, 30)
self.setStyleSheet('''
Container {
background: lightblue;
border: 0px;
border-radius: 4px;
}
''')
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.startPos = event.pos()
def mouseMoveEvent(self, event):
if self.startPos:
self.move(self.pos() + (event.pos() - self.startPos))
def mouseReleaseEvent(self, event):
self.startPos = None
class GraphicsRoundedFrame(QtWidgets.QGraphicsProxyWidget):
def __init__(self):
super().__init__()
self.container = Container()
self.setWidget(self.container)
def addWidget(self, widget):
self.container.layout().addWidget(widget)
def paint(self, qp, opt, widget):
qp.save()
p = QtGui.QPainterPath()
p.addRoundedRect(self.boundingRect().adjusted(0, 0, -.5, -.5), 4, 4)
qp.setClipPath(p)
super().paint(qp, opt, widget)
qp.restore()
class View(QtWidgets.QGraphicsView):
def __init__(self):
super().__init__()
scene = QtWidgets.QGraphicsScene()
self.setScene(scene)
self.setRenderHints(QtGui.QPainter.Antialiasing)
scene.setSceneRect(0, 0, 1024, 768)
texture = QtGui.QImage(30, 30, QtGui.QImage.Format_ARGB32)
qp = QtGui.QPainter(texture)
qp.setBrush(QtCore.Qt.white)
qp.setPen(QtGui.QPen(QtGui.QColor(189, 190, 191), 2))
qp.drawRect(texture.rect())
qp.end()
scene.setBackgroundBrush(QtGui.QBrush(texture))
testFrame = GraphicsRoundedFrame()
scene.addItem(testFrame)
testFrame.addWidget(QtWidgets.QLabel('I am a label'))
testFrame.addWidget(QtWidgets.QPushButton('I am a button'))
import sys
app = QtWidgets.QApplication(sys.argv)
w = View()
w.show()
sys.exit(app.exec_())
我已经为 Qgraphics 小部件创建了自定义框架。我遇到了两个问题,首先,一个是在 MouseMoveEvent 下没有检测到点击,即 event.button()
总是 returns 0 即使有鼠标点击。其次,我的 setCursor()
没有改变光标。这是我在自定义框架 class.
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt, QRectF, QEvent, QPoint
from PyQt5.QtGui import QPen, QColor, QPainter, QBrush, qRgb, QPolygon
from PyQt5.QtWidgets import *
import sys
class Frame(QFrame):
def __init__(self, parent=None, option=[], margin=0):
super(Frame, self).__init__()
self.parent = parent
self._triangle = QPolygon()
self.options = option
self._margin = margin
self.start_pos = None
# self.parent.setViewport(parent)
self.setStyleSheet('background-color: lightblue')
self.setMouseTracking(True)
self.installEventFilter(self)
self.show()
def update_option(self, option):
self.options = option
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.white)
qp.setBrush(Qt.gray)
qp.drawPolygon(self._triangle)
def _recalculate_triangle(self):
p = QPoint(self.width() - 20, self.height() - 10)
q = QPoint(self.width() - 10, self.height() - 20)
r = QPoint(self.width() - 10, self.height() - 10)
self._triangle = QPolygon([p, q, r])
self.update()
def resizeEvent(self, event):
self._recalculate_triangle()
super().resizeEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if event.button() == Qt.LeftButton and self._triangle.containsPoint(
event.pos(), Qt.OddEvenFill
):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
self.start_pos = event.pos()
# print(self.start_pos)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
if event.button() == Qt.LeftButton:
if event.button() == QtCore.Qt.LeftButton and self.start_pos is not None:
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
delta = event.pos() - self.start_pos
self.n_resize(self.width()+delta.x(), self.height()+delta.y())
self.start_pos = event.pos()
elif not self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseReleaseEvent(event)
def n_resize(self, width, height):
self.resize(width, height)
if __name__ == '__main__':
q = QApplication(sys.argv)
a = Frame()
sys.exit(q.exec())
我也试过使用eventfilter
但是没有用。
编辑:
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPen, QColor, QPainter, QBrush, QPolygon
from PyQt5.QtWidgets import *
import sys
class graphLayout(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.scene = QGraphicsScene()
self.lines = []
self.draw_grid()
self.set_opacity(0.3)
widget = QGraphicsProxyWidget()
t = stack(self)
t.setFlag(QGraphicsItem.ItemIsMovable)
t.resize(340, 330)
self.scene.addItem(t)
self.setScene(self.scene)
self.show()
def create_texture(self):
image = QtGui.QImage(QtCore.QSize(30, 30), QtGui.QImage.Format_RGBA64)
pen = QPen()
pen.setColor(QColor(189, 190, 191))
pen.setWidth(2)
painter = QtGui.QPainter(image)
painter.setPen(pen)
painter.drawRect(image.rect())
painter.end()
return image
def draw_grid(self):
texture = self.create_texture()
brush = QBrush()
# brush.setColor(QColor('#999'))
brush.setTextureImage(texture) # Grid pattern.
self.scene.setBackgroundBrush(brush)
borderColor = Qt.black
fillColor = QColor('#DDD')
def set_visible(self, visible=True):
for line in self.lines:
line.setVisible(visible)
def delete_grid(self):
for line in self.lines:
self.scene.removeItem(line)
del self.lines[:]
def set_opacity(self, opacity):
for line in self.lines:
line.setOpacity(opacity)
def wheelEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
delta = event.angleDelta().y()
if delta > 0:
self.on_zoom_in()
elif delta < 0:
self.on_zoom_out()
super(graphLayout, self).wheelEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.MidButton:
self.setCursor(Qt.OpenHandCursor)
self.mousepos = event.localPos()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
# This helps to pan the area
if event.buttons() == Qt.MidButton:
delta = event.localPos() - self.mousepos
h = self.horizontalScrollBar().value()
v = self.verticalScrollBar().value()
self.horizontalScrollBar().setValue(int(h - delta.x()))
self.verticalScrollBar().setValue(int(v - delta.y()))
self.mousepos = event.localPos()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.unsetCursor()
self.mousepos = event.localPos()
super().mouseReleaseEvent(event)
def on_zoom_in(self):
if self.transform().m11() < 3.375:
self.setTransformationAnchor(self.AnchorUnderMouse)
self.scale(1.5, 1.5)
def on_zoom_out(self):
if self.transform().m11() > 0.7:
self.setTransformationAnchor(self.AnchorUnderMouse)
self.scale(1.0 / 1.5, 1.0 / 1.5)
class stack(QGraphicsWidget):
_margin = 0
def __init__(self, parent=None):
super().__init__()
self.options = []
self.gridlayout = parent
graphic_layout = QGraphicsLinearLayout(Qt.Vertical, self)
self.width, self.height = 10, 10
self.outer_container = Frame(parent, self.options, self._margin)
self.outer_container.setContentsMargins(0, 0, 0, 0)
self.setParent(self.outer_container)
layout = QVBoxLayout()
self.headerLayout = QGridLayout()
self.headerLayout.setContentsMargins(2, 0, 0, 0)
self.top_bar = QFrame()
self.top_bar.setFrameShape(QFrame.StyledPanel)
self.top_bar.setLayout(self.headerLayout)
self.top_bar.setContentsMargins(0, 0, 0, 0)
self.top_bar.setMaximumHeight(30)
# self.contentLayout = QVBoxLayout()
self.contentLayout = QFormLayout()
self.contentLayout.setContentsMargins(10, 10, 10, 10)
self.contentLayout.setSpacing(5)
layout.addWidget(self.top_bar)
layout.addLayout(self.contentLayout)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self.outer_container.setContentsMargins(0, 0, 0, 0)
self.setContentsMargins(0, 0, 0, 0)
self.setMaximumSize(400, 800)
self.outer_container.setLayout(layout)
widget = QGraphicsProxyWidget()
widget.setWidget(self.outer_container)
# todo: figure out a way to add top_bar widget
graphic_layout.addItem(widget)
graphic_layout.setSpacing(0)
graphic_layout.setContentsMargins(0, 0, 0, 0)
# widget move and resize note: don't touch any of these
self.__mouseMovePos = None
self._triangle = QPolygon()
self.start_pos = None
def addHeaderWidget(self, widget=None, column=0, bg_color='green'):
self.top_bar.setStyleSheet(f'background-color:{bg_color};')
self.headerLayout.addWidget(widget, 0, column)
class Frame(QFrame):
def __init__(self, parent=None, option=[], margin=0):
super(Frame, self).__init__()
self.parent = parent
self._triangle = QPolygon()
self.options = option
self._margin = margin
self.start_pos = None
# self.parent.setViewport(parent)
self.setStyleSheet('background-color: lightblue')
self.setMouseTracking(True)
self.installEventFilter(self)
self.show()
def update_option(self, option):
self.options = option
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setPen(Qt.white)
qp.setBrush(Qt.gray)
qp.drawPolygon(self._triangle)
def _recalculate_triangle(self):
p = QPoint(self.width() - 20, self.height() - 10)
q = QPoint(self.width() - 10, self.height() - 20)
r = QPoint(self.width() - 10, self.height() - 10)
self._triangle = QPolygon([p, q, r])
self.update()
def resizeEvent(self, event):
self._recalculate_triangle()
super().resizeEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if event.button() == Qt.LeftButton and self._triangle.containsPoint(
event.pos(), Qt.OddEvenFill
):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
self.start_pos = event.pos()
# print(self.start_pos)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
else:
self.parent.viewport().unsetCursor()
self.start_pos = None
if event.button() == Qt.LeftButton:
if event.button() == QtCore.Qt.LeftButton and self.start_pos is not None:
self.parent.viewport().setCursor(Qt.SizeFDiagCursor)
delta = event.pos() - self.start_pos
self.n_resize(self.width()+delta.x(), self.height()+delta.y())
self.start_pos = event.pos()
elif not self._triangle.containsPoint(event.pos(), Qt.OddEvenFill):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.parent.viewport().unsetCursor()
self.start_pos = None
super().mouseReleaseEvent(event)
def n_resize(self, width, height):
self.resize(width, height)
if __name__ == '__main__':
q = QApplication(sys.argv)
a = graphLayout()
sys.exit(q.exec())
您的代码存在各种问题,但基本问题是:
- 在 MouseMove 事件中
event.button()
无法检索鼠标按钮状态,event.button<b>s</b>()
应该改用:区别很明显:button()
显示 生成 事件的按钮(鼠标移动事件显然 不是 任意按钮产生),buttons()
显示按钮状态产生事件时; - 未由对象显式管理的事件总是传播到其父控件,这意味着您的鼠标移动也可能由父控件处理,然后图形代理、场景、视口、视图等,直到顶层 window,直到前面的对象之一实际上 returns
True
来自event()
或事件过滤器;在您的情况下,它会导致移动图形项目,因为您启用了ItemIsMovable
标志。
我不知道为什么没有真正设置光标,但坦白说你的代码很复杂,我真的找不到原因。
由于您真正要找的是一种调整小部件大小的方法,我建议您使用另一种解决方案。
虽然使用自定义绘画实现调整大小当然是可行的,但在大多数情况下,使用 QSizeGrip 就足够了(正如另一个 post 中已经向您建议的那样),这是一个允许调整顶层大小的小部件windows 并且能够自动理解哪个“角”用于根据其位置调整大小。请记住 QSizeGrip 的 parent 非常重要,因为它使用它来了解哪个是它的顶层 window,并且在这种情况下,“容器框架”,即使它在 QGraphicsScene 中。
请注意,QSizeGrip 不应不 添加到布局中,并且应始终根据其角 位置和其父级的大小(除非它被放置在左上角),并且由于您已经需要自定义绘画,所以最好将其子类化。
from PyQt5 import QtCore, QtGui, QtWidgets
class SizeGrip(QtWidgets.QSizeGrip):
def __init__(self, parent):
super().__init__(parent)
parent.installEventFilter(self)
self.setFixedSize(30, 30)
self.polygon = QtGui.QPolygon([
QtCore.QPoint(10, 20),
QtCore.QPoint(20, 10),
QtCore.QPoint(20, 20),
])
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.Resize:
geo = self.rect()
geo.moveBottomRight(source.rect().bottomRight())
self.setGeometry(geo)
return super().eventFilter(source, event)
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(QtCore.Qt.white)
qp.setBrush(QtCore.Qt.gray)
qp.drawPolygon(self.polygon)
class Container(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sizeGrip = SizeGrip(self)
self.startPos = None
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(6, 6, 6, 30)
self.setStyleSheet('''
Container {
background: lightblue;
border: 0px;
border-radius: 4px;
}
''')
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.startPos = event.pos()
def mouseMoveEvent(self, event):
if self.startPos:
self.move(self.pos() + (event.pos() - self.startPos))
def mouseReleaseEvent(self, event):
self.startPos = None
class GraphicsRoundedFrame(QtWidgets.QGraphicsProxyWidget):
def __init__(self):
super().__init__()
self.container = Container()
self.setWidget(self.container)
def addWidget(self, widget):
self.container.layout().addWidget(widget)
def paint(self, qp, opt, widget):
qp.save()
p = QtGui.QPainterPath()
p.addRoundedRect(self.boundingRect().adjusted(0, 0, -.5, -.5), 4, 4)
qp.setClipPath(p)
super().paint(qp, opt, widget)
qp.restore()
class View(QtWidgets.QGraphicsView):
def __init__(self):
super().__init__()
scene = QtWidgets.QGraphicsScene()
self.setScene(scene)
self.setRenderHints(QtGui.QPainter.Antialiasing)
scene.setSceneRect(0, 0, 1024, 768)
texture = QtGui.QImage(30, 30, QtGui.QImage.Format_ARGB32)
qp = QtGui.QPainter(texture)
qp.setBrush(QtCore.Qt.white)
qp.setPen(QtGui.QPen(QtGui.QColor(189, 190, 191), 2))
qp.drawRect(texture.rect())
qp.end()
scene.setBackgroundBrush(QtGui.QBrush(texture))
testFrame = GraphicsRoundedFrame()
scene.addItem(testFrame)
testFrame.addWidget(QtWidgets.QLabel('I am a label'))
testFrame.addWidget(QtWidgets.QPushButton('I am a button'))
import sys
app = QtWidgets.QApplication(sys.argv)
w = View()
w.show()
sys.exit(app.exec_())