简体   繁体   中英

In PyQt5, Why Signal can't connect a Slot in a external class?

Background

I'm using signals to implement MVC in PyQt5. There are many interfaces in one program. Each page has a corresponding controller, and all the controllers are finally put together.

Question

My question is: I implemented the same slot function in four different places, but Why Signal can't connect a Slot in a external class?

Here is dir tree:

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

minimal runnable example

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 , the output is:

111
333
444

The output which I want is:

111
222
333
444

I want to verify the info in login function. But why 222 is not output, and what should I do to fix it? This problem has bothered me for half a month, thank you.

There is no persistent reference to login_controller : you create it as a local variable, then the init function returns, python's garbage collector is unable to find any reference to it, so it deletes it.

The solution is simple:

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

Please consider that, while using an MVC pattern is generally a good idea, it should be done to improve the quality of your project structure by providing better abstraction and offering easier debugging without overcomplicating things.
For instance, your Controller class (which also has a name that is really too similar to the other one), is almost superfluous, as your main Controll should be enough.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM