首页 > 解决方案 > QtWidgets.QStackedWidget() 的意外行为

问题描述

我想创建一个使用 pyqt5 在两个窗口之间来回切换的 GUI,即 WindowA 和 WindowB。为了实现这一点,我有

“QStackedWidget 类提供了一堆小部件,一次只能看到一个小部件。”

前几次它工作得很好。我单击按钮 A,它把它带到窗口 B。我单击按钮 B,它把我带回到窗口 A。但是,之后它开始注册多次点击,就好像我同时点击了当前按钮和之前显示的所有按钮一样。我不知道如何解决这个问题。这是一个展示问题的(最小的?)可重现的示例。我还实现了一个计算按钮被按下的次数的函数,这样你就可以看到预期结果和实际结果之间的差异。

import sys 
from PyQt5 import QtWidgets, QtCore
from PyQt5.Qt import QAction, QMenu


class WindowA(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(WindowA, self).__init__(parent)
        self.buttonA = QtWidgets.QPushButton("Button A - Press me!")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.buttonA)
        self.buttonA.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(1)
        self.setLayout(layout)
    def whenButtonPressed(self, count):
        print("Button A pressed. Total buttons pressed: " + str(count))

class WindowB(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(WindowB, self).__init__(parent)
        self.buttonB = QtWidgets.QPushButton("Button B - Press me!")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.buttonB)
        self.buttonB.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(1)
        self.setLayout(layout)
    def whenButtonPressed(self, count):
        print("Button B pressed. Total buttons pressed: " + str(count))

class mainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        self.setGeometry(850, 250, 300, 150)
        self.count = 0
        # Instantiating the classes of each window and adding them to the stack
        self.__A = WindowA()
        self.__B = WindowB()
        self.__stack = QtWidgets.QStackedWidget(self)
        self.__stack.addWidget(self.__A)
        self.__stack.addWidget(self.__B)
        self.__stack.setContentsMargins(1,1,1,1)
        self.setCentralWidget(self.__stack)
        self.launchA()
    def launchA(self):
        self.__stack.setCurrentWidget(self.__A)
        self.__stack.currentWidget().buttonA.clicked.connect(lambda: self.printAndChange())
        self.show()
    def launchB(self):
        self.__stack.setCurrentWidget(self.__B)
        self.__stack.currentWidget().buttonB.clicked.connect(lambda: self.printAndChange())
        self.show()
    def printAndChange(self):
        self.count += 1
        self.__stack.currentWidget().whenButtonPressed(self.count)
        if isinstance(self.__stack.currentWidget(), WindowA) == True : 
            self.launchB()
        elif isinstance(self.__stack.currentWidget(), WindowA) == False:
            self.launchA()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('Fusion')
    w = mainWindow()
    sys.exit(app.exec_())

标签: pythonpyqt5

解决方案


你在错误的地方链接对象信号槽。试试看:

import sys 
from PyQt5 import QtWidgets, QtCore
from PyQt5.Qt import QAction, QMenu


class WindowA(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(WindowA, self).__init__(parent)
        self.buttonA = QtWidgets.QPushButton("Button A - Press me!")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.buttonA)
        self.buttonA.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(1)
        self.setLayout(layout)
        
    def whenButtonPressed(self, count):
        print("Button A pressed. Total buttons pressed: " + str(count))


class WindowB(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(WindowB, self).__init__(parent)
        self.buttonB = QtWidgets.QPushButton("Button B - Press me!")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.buttonB)
        self.buttonB.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(1)
        self.setLayout(layout)
        
    def whenButtonPressed(self, count):
        print("Button B pressed. Total buttons pressed: " + str(count))


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        
        self.setGeometry(850, 250, 300, 150)
        self.count = 0
        # Instantiating the classes of each window and adding them to the stack
        self.__A = WindowA()
        self.__A.buttonA.clicked.connect(lambda: self.printAndChange())       # +++
                
        self.__B = WindowB()
        self.__B.buttonB.clicked.connect(lambda: self.printAndChange())       # +++
        
        self.__stack = QtWidgets.QStackedWidget(self)
        self.__stack.addWidget(self.__A)
        self.__stack.addWidget(self.__B)
        self.__stack.setContentsMargins(1, 1, 1, 1)
        self.setCentralWidget(self.__stack)
        self.launchA()
        
    def launchA(self):
        self.__stack.setCurrentWidget(self.__A)
#        self.__stack.currentWidget().buttonA.clicked.connect(lambda: self.printAndChange())
        self.show()
        
    def launchB(self):
        self.__stack.setCurrentWidget(self.__B)
#        self.__stack.currentWidget().buttonB.clicked.connect(lambda: self.printAndChange())
        self.show()
        
    def printAndChange(self):
        self.count += 1
        self.__stack.currentWidget().whenButtonPressed(self.count)
        if isinstance(self.__stack.currentWidget(), WindowA) == True : 
            self.launchB()
        elif isinstance(self.__stack.currentWidget(), WindowA) == False:
            self.launchA()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('Fusion')
    w = MainWindow()
    sys.exit(app.exec_())

推荐阅读