1. 程式人生 > >PyQt中處理訊號和槽時遇到的問題和解決方法

PyQt中處理訊號和槽時遇到的問題和解決方法

    做老師佈置的大作業用了PyQt,然後訊號與槽的部分要傳入引數,研究了半天,最後找到一篇不錯的教程(源地址:http://frymgump.iteye.com/blog/846557):

   昨天在群裡一個朋友提出了一個問題,要求在PyQt中click一個pushButton時給它的響應槽傳入一個和發射訊號的物件屬性相關的引數,比如按順序建立了N個pushButton,把這個次序數i告訴槽函式。

   這本來看上去是一個很簡單的問題,可問題就在於QPushButton只有click()等沒有任何引數的訊號,而自己在寫相應的槽的時候無法讓其再傳入一個自定義的引數。而訊號發射時如果不帶引數的話槽函式根本無法獲知是哪個widget向它發射了訊號,自然也無法處理和發射物件相關的屬性。

   當然這個問題還得從qt的訊號和槽機制說起,槽函式必須和訊號的引數是保持一致的,定義訊號發射時帶了幾個引數,槽函式被呼叫時就會以這幾個引數為入參,這是關鍵的一步。我一直覺得qt自稱最大特色的訊號和槽機制是個不好的發明,也許它真的很強大,但它的機制很彆扭,不容易理解,這會給開發者帶來困惑,就像我一樣。

   於是就出了這樣的問題,折騰了半天終於發現其實可以用事件響應來解決這個問題。Qt中的事件響應函式是widget物件的一個方法,也就是說任何從QWidget繼承的類的物件都可以偵聽到諸如mousePressEvent()之類的事件。這樣一來,自定義一個從QPushButton繼承的類,然後在其中重寫mousePressEvent()方法,在該方法中emit()一個自定義的訊號或者直接執行本來要由槽函式完成的動作即可。完整程式碼如下:

Python程式碼  收藏程式碼
  1. import sys  
  2. from PyQt4 import QtCore, QtGui  
  3. class ManyButton(QtGui.QDialog):  
  4.     t = ['button1''button2''button3''button4''button5']  
  5.     def __init__(self, parent=None):  
  6.         QtGui.QDialog.__init__(self, parent)  
  7.         self.pb = []  
  8.         vbox = QtGui.QVBoxLayout()  
  9.         for i in range(len(self.t)):  
  10.             self.pb.append(MyButton(self.t[i], self))  
  11.             QtCore.QObject.connect(self.pb[i],  QtCore.SIGNAL("myslot(str)"), self.myslot)  
  12.             vbox.addWidget(self.pb[i])  
  13.             self.setLayout(vbox)  
  14.         self.resize(250150)  
  15.     def myslot(self, text):  
  16.         QtGui.QMessageBox.critical(self"MessageShow", text, QtGui.QMessageBox.Ok)  
  17. class MyButton(QtGui.QPushButton):  
  18.     def __init__(self, text, parent):  
  19.         QtGui.QPushButton.__init__(self, text, parent)  
  20.     def mouseReleaseEvent(self, event):  
  21.         self.emit(QtCore.SIGNAL("myslot(str)"), self.text())  
  22. if __name__ == '__main__':  
  23.     app = QtGui.QApplication(sys.argv)  
  24.     mb = ManyButton()  
  25.     mb.show()  
  26.     sys.exit(app.exec_())  

 從中可以看出,其實我們通常關注並以為好像是一個函式的訊號本身只是一個字串,比如上面的myslot(str),你必須將這個字串傳入QtCore.SIGNAL()來生成訊號。而訊號定義的格式必須和emit時所帶的引數個數一致,比如

   self.emit(QtCore.SIGNAL("myslot(str, str)"), self.text1(), self.text2())
訊號後面就必須跟上兩個引數型別str,或者不寫也行,但不能寫成

   self.emit(QtCore.SIGNAL("myslot(str)"), self.text1(), self.text2()), 這時會報錯。
直接寫成這樣也是能正常執行的  

   self.emit(QtCore.SIGNAL("myslot"), self.text1(), self.text2())

也許訊號和槽的機制在由多個發射源向多個槽發射訊號時會起到很大作用,不過一般來講,感覺這種機制還是太麻煩了一點。