Python PyQt5:连接到单击信号的插槽不工作

Python PyQt5:连接到单击信号的插槽不工作,python,pyqt5,Python,Pyqt5,首先,对不起我的英语。我的母语是西班牙语。 所以,我正在做这个学习python的小项目。我正在学习如何使用PyQt5实现UI。这个应用程序很简单,它有三个输入、一个按钮和一个输出。 我在这个应用程序中使用MVC软件模式,我的视图、模型和控制器都在不同的文件中 问题是: 在控制器类中,我将唯一的按钮连接到一个名为(_calculate)的插槽。当我运行应用程序并按下该按钮时,终端应该打印一个文本,这样我就可以看到它是否工作了。终点站什么也看不见。 通过不同种类的研究,我发现如果我在视图类中执行相同

首先,对不起我的英语。我的母语是西班牙语。 所以,我正在做这个学习python的小项目。我正在学习如何使用PyQt5实现UI。这个应用程序很简单,它有三个输入、一个按钮和一个输出。 我在这个应用程序中使用MVC软件模式,我的视图、模型和控制器都在不同的文件中

问题是: 在控制器类中,我将唯一的按钮连接到一个名为(_calculate)的插槽。当我运行应用程序并按下该按钮时,终端应该打印一个文本,这样我就可以看到它是否工作了。终点站什么也看不见。 通过不同种类的研究,我发现如果我在视图类中执行相同的绑定,_calculate将被执行。我做了一个关于使用PyQt5的计算器的教程。教程中的计算器可以很好地使用MVC,所以我用它来判断我是否忘记或错过了什么,但没有明显的结果

我的控制器类

class Controller:
def __init__(self, view):
    self._view = view
    self._connectSignals()


def _connectSignals(self):
    self._view.button.clicked.connect(self._calculate)


def _calculate(self):
    print('trying to calculate')
我的观点课

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QSpacerItem
from PyQt5.QtWidgets import QSizePolicy
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import TextEdit

from PyQt5.QtGui import QPixmap

from PyQt5.QtCore import Qt
from ToolController import Controller

class UserInterface(QMainWindow):
  def __init__(self):
    super().__init__()

    self.setWindowTitle('BDO Tool')
    self.setFixedSize(450, 300)
    self._centralWidget = QWidget(self)
    self.setCentralWidget(self._centralWidget)
    self._createWindowSkeleton()


  def _createWindowSkeleton(self):
    # Vertical container who contains all the program widget
    self._generalLayout = QVBoxLayout()
    self._centralWidget.setLayout(self._generalLayout)
    self._generalLayout.setAlignment(Qt.AlignCenter)

    self._generalLayout.addLayout(self._createFirstRow())
    self._generalLayout.addLayout(self._createButton())
    self._generalLayout.addWidget(self._createAreaText())


  def _createFirstRow(self):
    hLayout = QHBoxLayout()
    spacer = QSpacerItem(20, 20, hPolicy=QSizePolicy.Expanding)
    self._inputBoxes = {
            self.INPUT_BASE_FAIL: (QPixmap(self.IMG_BASE_FAILS), QLineEdit()),
            self.INPUT_TARGET_FAIL: (QPixmap(self.IMG_TARGET_FAIL), QLineEdit()),
            self.INPUT_STACK_AMOUNT: (QPixmap(self.IMG_STACK_AMOUNT), QLineEdit()),
        }
    keys = list(self._inputBoxes.keys())

    for key, value in self._inputBoxes.items():
        pixmap, editLine = value
        label = QLabel()

        label.setPixmap(pixmap)
        editLine.setFixedWidth(40)
        editLine.setAlignment(Qt.AlignRight)

        hLayout.addWidget(label)
        hLayout.addWidget(editLine)

        if key != keys[-1]:
            hLayout.addSpacerItem(spacer)

    return hLayout


  def _createButton(self):
    self.button = QPushButton('Calculate')
    spacer = QSpacerItem(20, 20, hPolicy=QSizePolicy.Expanding)
    hLayout = QHBoxLayout()

    hLayout.addSpacerItem(spacer)
    hLayout.addWidget(self.button)
    hLayout.addSpacerItem(spacer)

    return hLayout


  def _createAreaText(self):
    self._infoDisplay = QTextEdit()
    self._infoDisplay.setEnabled(False)

    return self._infoDisplay

  INPUT_BASE_FAIL = 1
  INPUT_TARGET_FAIL = 2
  INPUT_STACK_AMOUNT = 3
  IMG_BASE_FAILS = 'img\\user25x25.png'
  IMG_TARGET_FAIL = 'img\\target25x25.png'
  IMG_STACK_AMOUNT = 'img\\stack25x25.png'
我的主要

import sys

from PyQt5.QtWidgets import QApplication

from ToolView import UserInterface
from ToolController import Controller


def main():
    app = QApplication(sys.argv)
    view = UserInterface()
    view.show()

    Controller(view=view)

    sys.exit(app.exec())


if __name__ == '__main__':
    main()

问题是,您没有为控制器实例创建持久对象,因此该实例随后会立即被垃圾收集,因为它没有在其他任何地方被引用

只要实例引用存在,它就会按预期工作。
在这种情况下,局部变量就足够了,因为
app.exec()
将阻止
main
中的进一步处理,从而确保实例将一直存在,直到它存在为止

def main():
    app = QApplication(sys.argv)
    view = UserInterface()
    view.show()

    controller = Controller(view=view)

    sys.exit(app.exec())
尽管如此,我还是要告诉您,虽然从概念上讲使用MVC通常是一个好主意,但您应该谨慎地使用它,不要“夸大”模式,并且只有在它确实有助于开发的情况下

我想指出其中一个:

缺乏增量优势——UI应用程序已经被分解成组件,并通过组件体系结构实现代码重用和独立性,MVC没有任何增量优势

我知道你的例子是一个简单的概念性例子,但就它的作用而言,它肯定是一个过于复杂的例子。例如:

  • 您似乎没有使用模型,或者至少您似乎不需要一个完整的MVC模式来实现这一点(只要这样做有实际优势,就应该选择MVC,而不是“因为您应该使用它”)
  • 使用MVC模式并不一定意味着必须使用3个类(和3个单独的文件),这也可能会降低代码的可导航性;MVC主要是关于三个元素在程序逻辑中的划分方式:Qt(大多数提供UI元素的框架)已经在这方面有所帮助,因为它提供的UI元素除了显示自己几乎什么都不做,以及其他允许与它们交互的元素(文件访问、网络接口和实际模型)
  • 过度使用函数来创建UI通常是一个坏主意,因为这会使事情变得比实际情况复杂得多,从可读性的角度来看,这一点最为重要:虽然使用单独的函数可能有助于保持代码“整洁”,但创建函数也是为了实现其可重用性,在您的
    UserInterface
    类中,有4个函数肯定只会使用一次

你说的“我正在使用MVC构建应用程序”是什么意思?尝试移动self.\u视图。单击。连接(self.\u计算)到构造函数(def.\u初始化(self,视图):)directly@musicamante我只是想说我在项目中使用了模型-视图-控制器(MVC)软件模式。动词使用不当,sorry@RustyBucketBay这对我来说不起作用。我说的是编辑你的代码并给我们一个答案,而不是“你的源代码在哪里”。如果人们将来面临类似的问题,他们可能需要理解你的问题,而那时你的回购协议可能已经不存在了。同样,请编辑您的帖子,并提供链接中解释的MRE,并确保它能够准确地再现您的问题,因为它是书面的,我们将阅读它。非常感谢,这就解决了问题。我在下面的教程中没有声明变量就声明了控制器,它可以工作,这有点让人困惑。我使用MVC只是为了适应这种模式,因为这些应用程序很简单,所以我决定用它来练习。模型丢失了,因为我将创建为最后一段代码。当我使用MVC时,我会密切注意,谢谢你提供的信息。如果它有效,那可能是因为它在其他地方设置了对控制器的间接引用;可能在控制器的
\uuuu init\uuuu
中,它将自己设置为视图的成员,例如:
self.\u view.Controller=self