它不工作的原因是因爲控制器類正在垃圾收集之前,你可以點擊任何東西。
當你設置view.clicked = self.clicked時,你實際上正在做的是讓控制器中的一個對象保持在視圖對象上,這樣它永遠不會被清理 - 這不是真正的解決方案。
如果您將控制器存儲到一個變量,它將保護它免受收集。
所以,如果你改變你的代碼,上面寫着:
ctrl = TestViewController(view)
您將所有設置。
這就是說 - 你究竟在做什麼,我不確定......看起來你試圖爲Qt設置一個MVC系統 - 但Qt已經有一個相當不錯的系統, Qt Designer將界面組件從控制器邏輯(QWidget子類)分離爲UI(視圖/模板)文件。同樣,我不知道你正在嘗試做的,這可能是它的一個愚蠢的縮小版本,但是我建議你做這一切一類,像這樣:
from PyQt4 import QtGui
import sys
class TestView(QtGui.QWidget):
def __init__(self):
super(TestView, self).__init__()
self.initUI()
def initUI(self):
self.btn = QtGui.QPushButton('Button', self)
self.btn.resize(self.btn.sizeHint())
self.btn.move(50, 50)
self.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestView()
view.show()
app.exec_()
if __name__ == '__main__':
main()
編輯:澄清的MVC的Qt
因此,上面這個例子實際上並沒有實際加載ui並創建控制器/視圖分離。這裏有點難以展示。最好通過一些基於Qt/Designer的示例/教程來工作 - 我在這裏有一個http://bitesofcode.blogspot.com/2011/10/introduction-to-designer.html,但很多可以在網上找到。
簡短的回答是,你的loadUi方法可以用PyQt4代替。UIC動態負載(也有許多不同的方式來設置了),使得您的代碼最終讀取這樣的事情:
from PyQt4 import QtGui
import PyQt4.uic
import sys
class TestController(QtGui.QWidget):
def __init__(self):
super(TestController, self).__init__()
# load view
uifile = '/path/to/some/widget.ui'
PyQt4.uic.loadUi(uifile, self)
# create connections (assuming there is a widget called 'btn' that is loaded)
self.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestController()
view.show()
app.exec_()
if __name__ == '__main__':
main()
編輯2:存儲UI引用
如果它更容易爲了可視化這個概念,你還可以存儲對生成的UI對象的引用:
from PyQt4 import QtGui
import PyQt4.uic
import sys
class TestController(QtGui.QWidget):
def __init__(self):
super(TestController, self).__init__()
# load a view from an external template
uifile = '/path/to/some/widget.ui'
self.ui = PyQt4.uic.loadUi(uifile, self)
# create connections (assuming there is a widget called 'btn' that is loaded)
self.ui.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestController()
view.show()
app.exec_()
if __name__ == '__main__':
main()
「將控制器分配給變量」部分很好!雖然,我想指出,你的答案的第二部分似乎有點矛盾。首先,這只是我試圖實現的一個工作示例。其次,你推薦使用QtDesigner將View與邏輯分開,但是你會展示一個例子,其中程序的所有元素都在一個類中。請注意,在我的示例中,TestView類只包含UI元素,而不包含一行「邏輯」。下一步是通過控制器將「clicked」調用轉發給Model的API。 – freitass
是的,你是對的 - 我根本沒有改變你的代碼,在這裏展示如何使用設計器並不那麼容易。這裏有一個教程:http://bitesofcode.blogspot.com/2011/10/introduction-to-designer.html –
對,我明白你的觀點。但是因爲你的連接是在視圖內進行的,所以它必須有一個對其控制器對象的引用,對嗎?這可以通過在控制器內建立連接來解決,這將是視圖和模型之間的粘合劑。 – freitass