Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何连接PyQt4中控制器的信号?(PyQt4中类似iOS的MVC结构)_Python_Model View Controller_Pyqt4 - Fatal编程技术网

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()