正确设置 QStackedWidget,信号看不到功能/插槽

Posted

技术标签:

【中文标题】正确设置 QStackedWidget,信号看不到功能/插槽【英文标题】:Setting up QStackedWidget properly, signal cannot see function/slot 【发布时间】:2018-02-13 03:58:54 【问题描述】:

我正在使用 PyQt5 开发 GUI。这是我进入 OOP 的第一步,我正在努力自学。我正在努力理解类何时继承方法/属性等以及它们有哪些可用方法——我想这是一个与范围相关的问题?我在下面的 GUI 上制作了一个 MWE。总的来说,将会有更多的页面和信号/插槽。

我想要什么:

堆栈应该初始化为“MainMenu”小部件/对象显示(左下图)。单击“下一页”按钮应切换堆栈顺序以将“OtherPage”小部件/对象放在顶部(右下图)。我将每个页面创建为一个类,认为这将是组织我的项目的好方法。这是好的还是坏的做法?

现在发生了什么:

如果nextPg.clicked.connect(self.drawOtherPage()) 行被注释掉,GUI 就可以工作(初始化),但是当然点击按钮什么也不会。我可以切换初始堆栈顺序,以便“其他”小部件位于堆栈顶部并且它显示得很好,所以我认为该类也在工作。当上述行包含在代码中时,会抛出以下错误:

in __init__
     nextPg.clicked.connect(self.drawOtherPage())
AttributeError: 'MainMenu' object has no attribute 'drawOtherPage'

我尝试过的

我认为对super() 的调用应该允许子类(在本例中为MainMenu)从父类(RootInit)继承方法。因此,我认为这应该使 drawOtherPage 方法可用于按钮连接信号。显然,错误是该方法不可用的结果。

我做错了什么?我应该在方法中创建这些“页面”小部件吗?它们是否需要在 RootInit 类下,或者它们可以位于 .py 文件的顶层?我正在尝试遵循最佳实践,因为该项目最终会变得非常大。幸运的是,其中大部分应该是基于单击哪些按钮到达那里而具有变化的页面——因此我认为类会很有帮助。请严格对待代码和我的 python/PyQt 语言,努力学习——谢谢!

import sys, os
from PyQt5.QtWidgets import *
from PyQt5 import QtGui, QtCore

class RootInit(QMainWindow):
    # root window
    def __init__(self, parent=None):
        QMainWindow.__init__(self)
        self.root = QWidget()
        self.stack = QStackedWidget()
        rootLayout = QVBoxLayout()
        rootLayout.addWidget(self.stack)
        self.root.setLayout(rootLayout)
        self.setCentralWidget(self.root)

        self.initializeGUI()

    def initializeGUI(self):
        self.main = MainMenu(self) # build MainMenu (class)
        self.other = OtherPage(self) # build OtherPage (class)
        self.stack.addWidget(self.main)
        self.stack.addWidget(self.other)

    def drawMain(self):
        self.stack.setCurrentIndex(0)

    def drawOtherPage(self):
        self.stack.setCurrentIndex(1)


class MainMenu(QWidget):
    # class for main menu
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        super().__init__()

        mainLayout = QGridLayout() # layout for entire main menu
        quitBtn = QPushButton("Quit")
        quitBtn.clicked.connect(QtCore.QCoreApplication.instance().quit)
        nextPg = QPushButton("Next page")
        nextPg.clicked.connect(self.drawOtherPage())

        mainLayout.addWidget(quitBtn, 0, 0)
        mainLayout.addWidget(nextPg, 0, 1)
        self.setLayout(mainLayout)


class OtherPage(QWidget):
    # class for another menu
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        label = QLabel("test label")
        layout = QGridLayout() #
        layout.addWidget(label, 0, 0)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    root = RootInit()
    root.setWindowTitle("Title")
    root.show()
    sys.exit(app.exec_())

【问题讨论】:

【参考方案1】:

您的代码有以下错误:

1234563方法。

您的另一个错误是两次调用父级的构造函数:


class MainMenu(QWidget):
    # class for main menu
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        super().__init__()

在第一个构造函数中,您分配了一个父级,而在第二个构造函数中,您没有。为了在python中澄清,有几种方法可以调用父级的构造函数:

    QWidget.__init__(self, parent)
    super(MainMenu, self).__init__(parent)
    super().__init__(parent)

所以你应该只使用其中一个。

另一个错误是信号是通过函数名连接的,函数不能用括号计算

最后一次使用涉及多个对象的函数或方法应该在两个对象都可以访问的地方完成,在您的情况下,您可以利用您将要使用的 RootInit 作为父级MainMenuself.main = MainMenu(self),并通过parent()方法访问该元素的连接。

以上所有内容都需要将MainMenu 类修改为以下内容:

class MainMenu(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        mainLayout = QGridLayout() # layout for entire main menu
        quitBtn = QPushButton("Quit")
        quitBtn.clicked.connect(QtCore.QCoreApplication.instance().quit)
        nextPg = QPushButton("Next page")
        nextPg.clicked.connect(self.parent().drawOtherPage)

        mainLayout.addWidget(quitBtn, 0, 0)
        mainLayout.addWidget(nextPg, 0, 1)
        self.setLayout(mainLayout)

【讨论】:

感谢您的有用评论。这解决了我的问题。我开始更好地掌握类继承。我根本不知道parent() 方法。

以上是关于正确设置 QStackedWidget,信号看不到功能/插槽的主要内容,如果未能解决你的问题,请参考以下文章

来自其类外的QStackedWidget的setCurrentIndex

滑动 QStackedWidget 页面

如何将 QStackedWidget 大小设置为子小部件的最小尺寸?

从另一个文件中的按钮切换 QStackedWidget 中的小部件

将自定义小部件添加到 QStackedWidget

明确设置值时抑制Qt信号的正确方法是啥