python - QtWidgets.QStackedWidget() 的意外行为
问题描述
我想创建一个使用 pyqt5 在两个窗口之间来回切换的 GUI,即 WindowA 和 WindowB。为了实现这一点,我有
- 为 WindowA 创建了一个类,为 WindowB 创建了另一个类,每个类中都有一个按钮
- 创建了一个 mainWindow 类,该类实例化一个 WindowA 类型的对象和另一个 WindowB 类型的对象,并将这两个对象都添加到堆栈中。根据pyqt 文档,
“QStackedWidget 类提供了一堆小部件,一次只能看到一个小部件。”
- 在 mainWindow 类中定义了两个方法 LaunchA 和 LaunchB,分别使用 setCurrentWidget() 方法将当前小部件设置为 A 或 B,并在单击按钮时调用另一个。
前几次它工作得很好。我单击按钮 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_())
解决方案
你在错误的地方链接对象信号槽。试试看:
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_())
推荐阅读
- android - 即使 LiveData 只会更新一次,也从 Coroutine 发布到 LiveData 以更新 UI
- python - 从 Python 转换为 F# 递归函数?
- php - 在 Slim 框架中获取组名
- python - python装饰器计数器原语失败
- javascript - 如何解析基于 JavaScript 的页面
- unit-testing - 单元测试 - 我应该对实体/值对象级别进行单元测试还是仅在聚合根级别进行单元测试?
- python - 如何让 docker 容器永远运行
- react-native - 无效的 Podfile - React Native
- nginx - 在路径级别应用 nginx-ingress 注释
- python - Python:按用户定义对象的属性排序,使用 lambda 函数按自定义顺序