2010-07-22 131 views
10

我想在我的樹視圖中啓用刪除鍵。這是我到目前爲止有:創建一個事件過濾器

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 

我連接eventfilter這樣的:

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

爲什麼我需要傳遞self.dataTreeview當我創建過濾器?沒有它,它就無法工作。

+3

I * *認爲(但不因此,如果沒有父節點,Python的垃圾收集器將會吃掉你的過濾器,因爲安裝事件過濾器不會創建一個引用(在python方面)。爲了驗證這一點,請儘量保留對「過濾器」的引用(例如,說'self.filter = ...')但不傳遞父代。 – balpha 2010-07-22 11:29:16

回答

10

@balpha是正確的。簡單的答案是,如果您未通過父項或確保filter實例具有實時參考,則它將被垃圾收集。

PyQt使用SIP綁定到Qt的C++實現。從SIP documentation

當包裝C++實例時,會創建相應的Python對象。 Python對象的行爲與您在垃圾回收方面的預期相同 - 當引用計數達到零時垃圾回收。相應的C++實例會發生什麼?顯而易見的答案可能是實例的析構函數被調用。但是,庫API可能會說,當實例傳遞給特定函數時,庫將獲取實例的所有權,即調用實例的析構函數的責任從SIP生成的模塊傳遞給庫。

實例的所有權也可能與另一個實例相關聯。這意味着如果擁有的實例被銷燬,擁有的實例將自動銷燬。 SIP會跟蹤這些關係,以確保Python的循環垃圾收集器可以檢測並中斷擁有和擁有的實例之間的任何引用循環。該關聯是作爲所擁有的實例參考所擁有的實例來實現的。

以上意味着如果您將Python對象傳遞給擁有所有權的Qt對象,即使您不能保證對特定對象的引用得到保持,所有內容也都能正常工作。

因此,要重申什麼@balpha在他的評論中說,這裏有一個解決方法的情況下,當你不希望在一個對象傳遞給構造函數:

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

密鑰處理已在QAbstractItemView中實現。你所要做的只是樹視圖的子類,然後執行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) 

`