I am using pyqt and Python 3. I want to prevent a QGraphicsRectItem to cross the horizontal axis (y=0) in a QGraphicsScene when dragged with the mouse. I am using the following code (employing height() because the rectangle is in the upper half of the screen). See below a full example of the code.
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()
In principle this is working, but when I keep dragging the mouse below the horizontal axis (y=0), the rectangle flickers and jumps back and forth between the mouse position and its restrained position in the upper hemiplane while dragging. So it looks like the drag first moves it to the mouse cursor, and only then the position is adjusted retroactively. I would like the adjustment to happen before the item is moved (visibly) at all.