PyQt5按钮未连接

时间:2020-09-30 17:45:01

标签: python pyqt5

我正在尝试使用PyQT5构建一个简单的GUI,使用3个按钮打开文件浏览器,再用3个按钮运行处理所选文件的操作,但是我无法让我的按钮连接到执行此操作所需的功能

Ctrl类中,_connect_signals函数似乎没有在调用_input_select。谁能帮我找出原因?

import sys

# Import QApplication and the required widgets from PyQt5.QtWidgets
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QFileDialog


# Create a subclass of QMainWindow to setup the calculator's GUI
class UI(QMainWindow):
    """App's View (GUI)."""

    def __init__(self):
        """View initializer."""
        super().__init__()
        # Set some main window's properties
        self.setFixedSize(300, 150)
        # Set the central widget and the general layout
        self.generalLayout = QVBoxLayout()
        self._centralWidget = QWidget(self)
        self.setCentralWidget(self._centralWidget)
        self._centralWidget.setLayout(self.generalLayout)
        # Create the buttons
        self._create_buttons()

    def _create_buttons(self):
        """Create the buttons."""
        self.buttons = {}
        buttons_layout = QVBoxLayout()
        # Button text | position on the QVBoxLayout
        buttons = {
            "Select input file...": 0,
            "Select config file...": 1,
            "Select output file...": 2,
            "Run": 3,
        }
        # Create the buttons and add them to the grid layout
        for btnText, pos in buttons.items():
            self.buttons[btnText] = QPushButton(btnText)
            buttons_layout.addWidget(self.buttons[btnText], pos)
        # Add buttons_layout to the general layout
        self.generalLayout.addLayout(buttons_layout)


# Create a Controller class to connect the GUI and the model
class Ctrl:
    """App's Controller."""

    def __init__(self, setup, view):
        """Controller initializer."""
        self._view = view
        self._setup = setup
        # Connect signals and slots
        self._connect_signals()

    def _input_select(self):    # Not being called
        print("input selection")

        options = QFileDialog.Options()
        file_select, _ = QFileDialog.getOpenFileNames(
            self,
            'Select Input File...',
            '',
            'CSV Files (*.csv);;All Files (*)',
            options=options
        )
        if file_select:
            self._setup["input"] = file_select

    def _connect_signals(self):
        """Connect signals and slots."""
        self._view.buttons["Select input file..."].clicked.connect(self._input_select)  # Not working!


# Client code
def main():
    """Main function."""
    # Create an instance of `QApplication`
    app = QApplication(sys.argv)
    # Show the app's GUI
    view = UI()
    view.show()
    setup = {}
    # Create instance of the controller
    Ctrl(setup=setup, view=view)
    # Execute app's main loop
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

如果有帮助,我首先从Real Python教程中屠宰this example code,但一定会破坏它。

1 个答案:

答案 0 :(得分:0)

问题是您没有保留对所创建的Ctrl()实例的任何持久引用。创建实例后,这会导致python垃圾回收。

要解决此问题,只需将其分配给变量:

def main():
    """Main function."""
    # Create an instance of `QApplication`
    app = QApplication(sys.argv)
    # Show the app's GUI
    view = UI()
    view.show()
    setup = {}
    # Create instance of the controller
    ctrl = Ctrl(setup=setup, view=view)
    # Execute app's main loop
    sys.exit(app.exec_())

一些注意事项:

  • 尽管将逻辑与接口分离通常是一种好习惯,但是这个概念需要谨慎使用,因为有时它只会使事情变得比原本应该的复杂。在大多数情况下(尤其是使用简单的程序),它只会产生更大的代码库而没有任何实际的好处:读取和调试起来更加困难,并且您最终可能会不断地从逻辑部分和ui部分进行切换代码;
  • 您的代码显示了该概念的缺点之一:创建文件对话框时,您使用的是self,但在这种情况下,它引用的是Ctrl实例,而参数应改为UI实例(这将导致崩溃,因为Qt将获得意外的参数类型);您可以改用self._view,但是,如上所述,整个分隔只会使事情变得不必要地复杂;
  • 使用字符串作为引用内部对象的字典键很少是一个好主意(特别是在像您一样使用长描述性字符串时);
  • 从模块中导入多个元素时,通常最好将它们分组而不是使用单行导入:它使代码更整齐,更易于阅读和检查:from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog)