它不工作的原因是因为控制器类在你点击任何东西之前就被垃圾收集了。
当您设置 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()
编辑:澄清 Qt 的 MVC
所以上面的这个例子实际上并没有动态加载用户界面并创建一个控制器/视图分离。在这里展示有点困难。最好通过一些基于 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()