【问题标题】:Restraining a QGraphicsItem using itemChange()使用 itemChange() 限制 QGraphicsItem
【发布时间】:2018-01-04 01:17:20
【问题描述】:

我正在使用 pyqt 和 Python 3。我想防止 QGraphicsRectItem 在用鼠标拖动时穿过 QGraphicsScene 中的水平轴 (y=0)。我正在使用以下代码(使用 height() 因为矩形位于屏幕的上半部分)。请参阅下面的完整代码示例。

import sys
from PyQt4.QtCore import Qt, QPointF
from PyQt4.QtGui import QGraphicsRectItem, QGraphicsLineItem, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem

class MyRect(QGraphicsRectItem):
    def __init__(self, w, h):
        super().__init__(0, 0, w, h)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            if self.y() + self.rect().height() > 0:
                return QPointF(self.x(), -self.rect().height())
        return value

def main():
    # Set up the framework.
    app = QApplication(sys.argv)
    gr_view = QGraphicsView()
    scene = QGraphicsScene()
    scene.setSceneRect(-100, -100, 200, 200)
    gr_view.setScene(scene)

    # Add an x-axis
    x_axis = QGraphicsLineItem(-100, 0, 100, 0)
    scene.addItem(x_axis)

    # Add the restrained rect.
    rect = MyRect(50, 50)
    rect.setPos(-25, -100) # <--- not clear to me why I have to do this twice to get the 
    rect.setPos(-25, -100) # item positioned. I know it has to do with my itemChanged above...
    scene.addItem(rect)

    gr_view.fitInView(0, 0, 200, 200, Qt.KeepAspectRatio)    
    gr_view.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

原则上这是可行的,但是当我继续将鼠标拖动到水平轴下方(y = 0)时,矩形会在拖动时在鼠标位置与其在上半平面中的约束位置之间来回跳跃。所以看起来拖动首先将其移动到鼠标光标,然后才追溯调整位置。我希望在项目完全移动(可见)之前进行调整。

【问题讨论】:

  • 顺便说一句,在同一端使用 mouseMoveEvent 效果很好。只是当我选择一组项目时这会失败,因为该操作仅适用于鼠标光标下的项目。
  • 请提供minimal reproducible example,说明您是如何限制项目的移动的。
  • @MarekR。我看不出这个答案有什么帮助,因为 OP 已经声明 itemChange 正在工作。问题是移动项目时有闪烁。

标签: python qt pyqt qgraphicsitem


【解决方案1】:

您使用self.y() + self.rect().height() &gt; 0 来测试项目是否仍在 y 轴上方。但是,self.y() 指的是旧/当前位置。您应该使用 value.y() 来测试新位置。

所以方法应该是:

def itemChange(self, change, value):
    if change == QGraphicsItem.ItemPositionChange:
        if value.y() + self.rect().height() > 0:
            return QPointF(value.x(), -self.rect().height())
    return super().itemChange(change, value) # Call super

请注意,如果测试通过,我返回value.x(),如果测试失败,则调用超类的itemChange(就像itemChange Qt documentation 中的C++ 示例)

【讨论】:

  • 完美。这也解决了我必须做两次定位的另一个问题。
猜你喜欢
  • 2015-11-18
  • 1970-01-01
  • 2016-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 2014-04-26
  • 1970-01-01
相关资源
最近更新 更多