I’ve just started to get into Qt for Maya, using PySide. I’m developing a node interface and have a small problem which I haven’t been able to solve yet. If you think you know of a solution but doesn’t speak Python, just write it in c++ and I’ll try to convert it
I have a QGraphicsView which manages a QGraphicsScene. The QGraphicsScene have all the nodes (QGraphicsItem) in it. The QGraphicsItem have a built in function, or flag if you like, called “ItemIsMovable” that I use to be able to move the nodes around by left clicking on a node and moving the mouse. This works well until I try to implement a way of navigating the node interface. When I implement overrides for mouseMoveEvent, mousePressEvent and mouseReleaseEvent in the QGraphicsView class, to be able to pan and zoom, the functionality for moving the nodes them self stops working. It is as if my overrides to the QGraphicsView class prevents any similar events from triggering on the QGraphicsItem.
As an example, this is what my mousePressEvent function in my QGraphicsView class looks like:
def mousePressEvent(self, event):
# Panning
if (event.button() == QtC.Qt.MidButton) and (self.alt == 1) and (self.panning == 0): # self.alt triggers when the "Alt" button is pressed
self.mousePressPos = QtC.QPointF(event.pos())
self.scrollBarValuesOnMousePress.setX(self.horizontalScrollBar().value())
self.scrollBarValuesOnMousePress.setY(self.verticalScrollBar().value())
self.panning = 1
event.accept()
else:
event.ignore()
return
As an aside, please use 1) don’t use ints instead of bools, and 2) don’t even bother comparing to bools. Your line can be written as: if event.button() == QtC.Qt.MidButton and self.alt and not self.panning
As for your question, it is the ‘event.ignore’ that I think is the issue- you’re basically telling Qt to not continue propagating the event down to other widgets. I haven’t dealt with exactly this problem/widget, but you’ll need to allow the events to propagate. I’m pretty sure the docs have a lot to say about this matter (with examples), and since it’s tricky I’m sure there are some answers on Stack Overflow as well. Please tell us what you find! Or maybe post a full example and we can try to fix it.
Thanks for the reminders
Removing the event.ignore()'s didn’t solve it, I have written a simplified script that reproduces my problem. It doesn’t have it’s own QApplication so copy and paste it in to Maya to try it out.
Alt + middleMouseClick is the combination used for panning.
import PySide.QtGui as QtG
import PySide.QtCore as QtC
import PySide.QtSvg as QtS
class MainWindow(QtG.QMainWindow):
def __init__(self, parent = None):
QtG.QMainWindow.__init__(self, parent)
self.initUI()
def initUI(self):
graphicsView = GraphicsView(self)
self.setCentralWidget(graphicsView)
self.setGeometry(100, 100, 800, 800)
self.show()
class GraphicsView(QtG.QGraphicsView):
def __init__(self, parent):
QtG.QGraphicsView.__init__(self, parent)
self.nodeEditorScene = GraphicsScene(self)
self.setScene(self.nodeEditorScene)
node01 = DrawNode(True)
self.nodeEditorScene.addItem(node01)
# This makes the node movable
node01.setFlag(QtG.QGraphicsItem.ItemIsMovable)
# Used for panning
self.mousePressPos = QtC.QPointF()
self.scrollBarValuesOnMousePress = QtC.QPointF()
self.alt = False
self.panning = False
# Commenting out the following mouse events will make the node movable and obviously disable panning
def mouseMoveEvent(self, event):
if self.panning and not self.mousePressPos.isNull():
self.horizontalScrollBar().setValue(self.scrollBarValuesOnMousePress.x() - event.pos().x() + self.mousePressPos.x())
self.verticalScrollBar().setValue(self.scrollBarValuesOnMousePress.y() - event.pos().y() + self.mousePressPos.y())
self.horizontalScrollBar().update()
self.verticalScrollBar().update()
event.accept()
def mousePressEvent(self, event):
# Panning
if event.button() == QtC.Qt.MidButton and self.alt and not self.panning:
print "mousePress ok!"
self.mousePressPos = QtC.QPointF(event.pos())
self.scrollBarValuesOnMousePress.setX(self.horizontalScrollBar().value())
self.scrollBarValuesOnMousePress.setY(self.verticalScrollBar().value())
self.panning = True
event.accept()
def mouseReleaseEvent(self, event):
if self.panning:
print "mouseRelease ok!"
self.mousePressPos = QtC.QPointF()
self.panning = False
event.accept()
def keyPressEvent(self, event):
if event.key() == QtC.Qt.Key_Alt:
print "keyPress ok!"
self.alt = True
event.accept()
def keyReleaseEvent(self, event):
if event.key() == QtC.Qt.Key_Alt:
print "keyRelease ok!"
self.alt = False
event.accept()
class GraphicsScene(QtG.QGraphicsScene):
def __init__(self, parent):
QtG.QGraphicsScene.__init__(self, parent)
# Make the scene big to get some room for panning
self.setSceneRect(-10000, -10000, 20000, 20000)
class DrawNode(QtG.QGraphicsItem):
def __init__(self, AA = False, parent = None):
QtG.QGraphicsItem.__init__(self, parent)
self.newPos = QtC.QPointF()
self.setZValue(1)
self.penWidth = 1
self.hSize = 360
self.vSize = 400
# Specify the bounding box rectangle
self.qrectf = QtC.QRectF((-1 * (self.hSize / 2)) - self.penWidth / 2, (-1 * (self.vSize / 2)) - self.penWidth / 2, self.hSize + self.penWidth / 2, self.vSize + self.penWidth / 2)
# Just for debugging
def mousePressEvent(self, event):
print "mousePress event registered on the node itself!"
event.accept()
# Implements its pure virtual function boundingRect, to define the bounding box
def boundingRect(self):
return self.qrectf
# Implements its pure virtual function paint, to draw the item
def paint(self, painter, option, widget):
self.draw_nodeBackground(painter)
def draw_nodeBackground(self, painter):
QRectF_nodeBackground = self.qrectf
bgBrushColor = QtG.QColor(117, 117, 117, 255)
bgBrush = QtG.QBrush(bgBrushColor)
painter.setBrush(bgBrush)
painter.setPen(QtC.Qt.NoPen) #Don't draw the outline
painter.drawRoundedRect(QRectF_nodeBackground, 15, 15)
ex = MainWindow()
ex.show()