2

I have a GraphicScene inside a QGraphicView populated with many rectangles (items). I would like each rectangle to respond to the mouse click but I'm not able to find the hook to attach the event handler to the correct object and to get the event propagated to it.

I attached an event handler to the scene:

scene.event = myfunction

and it worked (it was firing every event) but I was unable to attach the same function to one of its children. Can you give me an insight on where to search for such an entry point?

Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
MassimoV
  • 21
  • 2

2 Answers2

3

So - I'm not really sure what you're doing there, but I can't think of anything in PyQt where you should be mapping a custom function directly to a scene's event method.

Do you have an actual example?

If you're doing:

scene.mousePressEvent = my_mouse_function

Then that is not how you want to do that.

You can look into using an event filters (http://doc.qt.nokia.com/4.7-snapshot/eventsandfilters.html#event-filters).

Best way to get what you want is to subclass the QGraphicsItem (whichever one you are using - QGraphicsRectItem, QGraphicsPathItem, etc.) and overload the mousePressEvent method on it.

http://doc.qt.nokia.com/4.7-snapshot/qgraphicsitem.html#mousePressEvent

For instance:

from PyQt4.QtGui import QGraphicsRectItem

class MyItem(QGraphicsRectItem):
    def mousePressEvent(self, event):
        super(MyItem, self).mousePressEvent(event)
        print 'overloaded'

scene.addItem(MyItem())
Eric Hulser
  • 3,912
  • 21
  • 20
  • Thank you, I followed your suggestion and I found a way for a rectangle to generate a mousePressEvent. – MassimoV Aug 31 '12 at 07:34
2

Either subclass the view, scene, item etc and reimplement mousePressEvent and/or mouseReleaseEvent; or install an event filter on those items.

For an example that uses an event filter on a scene, see this answer.

Here's a demo which reimplements mouseReleaseEvent on the view:

from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.view = View(self)
        self.label = QtGui.QLabel(self)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.view)
        layout.addWidget(self.label)

class View(QtGui.QGraphicsView):
    def __init__(self, parent):
        QtGui.QGraphicsView.__init__(self, parent)
        self.setScene(QtGui.QGraphicsScene(self))
        for index, name in enumerate('One Two Three Four Five'.split()):
            item = QtGui.QGraphicsRectItem(
                index * 60, index * 60, 50, 50)
            item.setData(0, name)
            self.scene().addItem(item)

    def mouseReleaseEvent(self, event):
        pos = event.pos()
        item = self.itemAt(pos)
        if item is not None:
            text = 'Rectangle <b>%s</b>' % item.data(0).toString()
        else:
            text = 'No Rectangle (%d, %d)' % (pos.x(), pos.y())
        self.parent().label.setText(text)
        QtGui.QGraphicsView.mouseReleaseEvent(self, event)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.resize(400, 400)
    window.show()
    sys.exit(app.exec_())
Community
  • 1
  • 1
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Thank you, but I wanted to let every rectangle generate the event, not induce the scene to filter it. But your post was helpful. – MassimoV Aug 31 '12 at 07:36