Creating an event filter

11,854

Solution 1

@balpha is correct. The simple answer is that if you don't pass in a parent or otherwise ensure that the filter instance has a live reference, it will be garbage collected.

PyQt uses SIP to bind to Qt's C++ implementation. From the SIP documentation:

When a C++ instance is wrapped a corresponding Python object is created. The Python object behaves as you would expect in regard to garbage collection - it is garbage collected when its reference count reaches zero. What then happens to the corresponding C++ instance? The obvious answer might be that the instance’s destructor is called. However the library API may say that when the instance is passed to a particular function, the library takes ownership of the instance, i.e. responsibility for calling the instance’s destructor is transferred from the SIP generated module to the library.

Ownership of an instance may also be associated with another instance. The implication being that the owned instance will automatically be destroyed if the owning instance is destroyed. SIP keeps track of these relationships to ensure that Python’s cyclic garbage collector can detect and break any reference cycles between the owning and owned instances. The association is implemented as the owning instance taking a reference to the owned instance.

The above implies that if you pass a Python object to a Qt object that takes ownership, everything will also work, even though you haven't guaranteed that a reference to the specific object was maintained.

So, to restate what @balpha said in his comment, here's one workaround for the case when you don't want to pass in an object to the constructor:

self.filter = delkeyFilter()
self.dataTreeView.installEventFilter(self.filter)

Solution 2

Key handling is already implimented in QAbstractItemView. All you have to do is subclass the treeview, then implement keyPressEvent.

class MyTreeView(QTreeView):

    delkeyPressed = pyqtSignal()

    def __init__(self):
        QTreeView.__init__(self)

    def keyPressEvent(self, event): #QKeyEvent
        if event.key() == Qt.Key_Delete:
            self.delkeyPressed.emit()
            print 'del key pressed'

        # pass the event up the chain or we will eat the event
        QTreeView.keyPressEvent(self, event)

`

Share:
11,854

Related videos on Youtube

crabman
Author by

crabman

Updated on April 28, 2022

Comments

  • crabman
    crabman about 2 years

    I am trying to enable the delete key in my treeview. This is what I have so far:

    class delkeyFilter(QObject):
        delkeyPressed = pyqtSignal()
    
        def eventFilter(self,  obj,  event):
            if event.type() == QEvent.KeyPress:
                if event.key() == Qt.Key_Delete:
                    self.delkeyPressed.emit()
                    print 'delkey pressed'
                    return True
            return False
    

    I connect the eventfilter like this:

        filter = delkeyFilter(self.dataTreeView)
        self.dataTreeView.installEventFilter(filter)
    

    Why do I need to pass self.dataTreeview when I create the filter? It doesn't work without it.

    • balpha
      balpha almost 14 years
      I think (but not sure, hence not posting as an answer) that Python's garbage collector will eat your filter if it doesn't have a parent, because installing the event filter doesn't create a reference (on the python side of things). To verify this, try to keep a reference to filter around (e.g. be saying self.filter = ...) but not passing a parent.