正确设置QStackedWidget,信号无法看到函数/插槽

时间:2018-02-13 03:58:54

标签: python pyqt pyqt5 qstackedwidget

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

我想要的是什么:

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

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 个答案:

答案 0 :(得分:2)

您的代码有以下错误:

  • 变量self指的是同一个类的实例,在您的情况下self指的是MainMenu的实例,如果我们观察MainMenu它没有任何drawOtherPage()方法。

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

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的内容MainMenu的父级self.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)