Python 如何连接PyQt4中控制器的信号?(PyQt4中类似iOS的MVC结构)
为什么下面的示例不起作用Python 如何连接PyQt4中控制器的信号?(PyQt4中类似iOS的MVC结构),python,model-view-controller,pyqt4,Python,Model View Controller,Pyqt4,为什么下面的示例不起作用 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)
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)
class TestViewController():
def __init__(self, view):
view.btn.clicked.connect(self.buttonClicked)
view.show()
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestView()
TestViewController(view)
app.exec_()
if __name__ == '__main__':
main()
该示例应该表示一个MVC结构(如中的一个,不带模型),其中控制器(TestViewController
)接收对视图的引用(TestView
),并将来自视图按钮view.btn
的单击信号连接到其函数self.buttonicked
)
我确信行view.btn.clicked.connect(self.buttonClicked)
已执行,但显然没有效果。有人知道如何解决这个问题吗
更新(糟糕的解决方案): 在本例中,如果替换该行
view.btn.clicked.connect(self.buttonClicked)
与
它起作用了。我仍然对此不满意。它不起作用的原因是,在您单击任何对象之前,控制器类正在被垃圾收集 当您设置view.clicked=self.clicked时,您实际要做的是将控制器中的一个对象持久化到视图对象上,这样它就永远不会被清理—这并不是真正的解决方案 如果将控制器存储到变量,它将保护它不被收集 因此,如果您将上述代码更改为:
ctrl = TestViewController(view)
你会准备好的
也就是说,我不确定您在这里到底想做什么…似乎您正在尝试为Qt设置一个MVC系统-但是Qt已经有了一个非常好的系统,使用Qt设计器将界面组件从控制器逻辑(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
因此,上面的示例实际上并没有动态加载ui并创建控制器/视图分离。在这里表演有点难。最好阅读一些基于Qt/Designer的示例/教程-我这里有一个,但很多可以在网上找到
简单的回答是,您的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将视图与逻辑分开,然后展示一个示例,其中程序的所有元素都在一个类中。注意,在我的示例中,
TestView
类只包含UI元素,没有一行“逻辑”。下一步是通过控制器将“单击”调用转发到模型的API。是的,你是对的-我实际上根本没有更改你的代码,在这里显示如何使用designer并不是那么容易。这里有一个教程:对,我明白你的意思。但是,由于您的连接是在视图中进行的,因此它必须具有对其控制器对象的引用,对吗?这可以通过在控制器内部建立连接来解决,这将是视图和模型之间的粘合剂。我想,更好的例子是将其称为TestController(QtGui.QWidget)与TestView。类是控制器,视图将完全由UI文件定义。另一种设置方法是存储指向已解析类实例的指针(如果更容易可视化)。我并不是说你不能按照你的建议去做,我只是从来没有见过Qt用那种方式,我只是觉得把网站结构/逻辑应用到桌面系统上太过复杂了。这种结构实际上是受移动系统启发的。对于某些应用程序(主要是较简单的应用程序),可能会过度设计,但如果在同一窗口中有来自多个域的复杂命令,则可能还需要分配多个控制器来管理该窗口的部分。我并不是说你错了,因为在软件工程中没有绝对的真理。只是在大多数情况下,拥有一个分区良好、灵活的结构是很有用的。顺便说一句,您的第二次编辑增强了视图控制器分区。非常好=D
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()