微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 PyQt5 中,为什么 Signal 无法连接外部类中的 Slot?

如何解决在 PyQt5 中,为什么 Signal 无法连接外部类中的 Slot?

背景

我正在使用信号在 PyQt5 中实现 MVC。一个程序中有多个接口。每个页面都有一个对应的控制器,最后所有的控制器组合在一起。

问题

我的问题是:我在四个不同的地方实现了相同的slot函数,但是为什么Signal不能连接外部类中的slot?

这是目录树:

error
├─ UI
│    └─ main_window.py
├─ control
│    ├─ controller.py
│    └─ login_control.py
├─ main.py
└─ model
       └─ model.py

最小的可运行示例

model.py:

class Student(object):

    def __init__(self):
        self.name = "aaa"
        self.password = "aaa"

login_control.py:

class Controller(object):
    def __init__(self,view,stu_id,stu_psd):
        self._view = view
        self._stu_id = stu_id
        self._stu_psd = stu_psd
        self.init()

    def init(self):
        # connect successfully
        self._view.login_signal.connect(self._view.login)
        # Connection Failed  why ???
        self._view.login_signal.connect(self.login)

        # connect successfully
        self._view.login_signal.connect(login)

    # why this Failed ???
    def login(self):
        print('222')

def login():
    print('333')

controller.py:

import sys
from PyQt5.QtWidgets import QApplication
from model.model import Student
from UI.main_window import MainWindow
from control import login_control


class Controll(object):

    def __init__(self):

        self._app = QApplication([])

        self._stu = Student()

        self._view = MainWindow()
        self.init()

    def init(self):
        login_controller = login_control.Controller(self._view,self._stu.name,self._stu.password)
        # connect successfully
        self._view.login_signal.connect(self.login)

    def login(self):
        print('444')

    def run(self):
        self._view.show()
        return self._app.exec()

main_window.py

from PyQt5.QtWidgets import QWidget,QHBoxLayout,QPushButton,QMessageBox,QLineEdit
from PyQt5 import QtCore


class MainWindow(QWidget):
    login_signal = QtCore.pyqtSignal()

    def __init__(self,*args,**kwargs):
        super(MainWindow,self).__init__(*args,**kwargs)
        self.id_line = QLineEdit()
        self.id_line.setPlaceholderText("Please Input ID")
        self.psd_line = QLineEdit()
        self.psd_line.setPlaceholderText("Please Input Password")

        self.init()

    def init(self):

        layout = QHBoxLayout()
        self.setLayout(layout)

        self.button = QPushButton("Login")
        layout.addWidget(self.button)

        layout.addWidget(self.id_line)
        layout.addWidget(self.psd_line)
    
        self.button.clicked.connect(self.login_signal)

    def login(self):
        print('111')

    def verify_ok(self):
        QMessageBox.about(self,"Correct","Login successfully")

    def verify_no(self):
        QMessageBox.about(self,"Mistake","Input again")

main.py

import sys
from control.controller import Controll


if __name__ == "__main__":
    controller = Controll()
    sys.exit(controller.run())

python main.py输出为:

111
333
444

我想要的输出是:

111
222
333
444

我想验证 login 函数中的信息。但是为什么 222 没有输出,我该怎么做才能解决它?这个问题困扰了我半个月,谢谢。

解决方法

没有对 login_controller 的持久引用:你将它创建为一个 local 变量,然后 init 函数返回,python 的垃圾收集器无法找到任何对它,所以它删除它。

解决方案很简单:

    def init(self):
        self.login_controller = login_control.Controller(
            self._view,self._stu.name,self._stu.password)
        self._view.login_signal.connect(self.login)

请注意,虽然使用 MVC 模式通常是一个好主意,但应该通过提供更好的抽象和更容易的调试来提高项目结构的质量。
例如,您的 Controller 类(它的名称也与另一个类 非常相似)几乎是多余的,因为您的主要 Controll 应该就足够了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。