在使用 PyQt 的 QMessageBox
时,如果你遇到 消息框重复显示 或 QMessageBox 重复实例化 的问题,通常是因为消息框没有正确管理或关闭,或者消息框的创建和显示逻辑中存在重复调用。以下是一些常见原因和解决方案。
1、问题背景
在 PyQt 中使用 QMessageBox 时,发现了一个重复的问题。当用户在回答问题时,会弹出一个确认消息框。然而,当用户确认并继续下一个问题时,会有 2 个消息框弹出,然后是 3 个,以此类推。
以下代码描述了该问题:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class IntegrationQuestions(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Integration')
self.setMinimumSize(265,400)
self.setMaximumSize(266,401)
self.Question1()
def Question1(self):
# 从另一个文件中获取问题
from FQuestions import FIntQuestion, FIntAnswer
self.lbl1 = QtGui.QLabel("Integrate the equation below",self)
self.lbl1.move(0,0)
self.lbl1.resize(200,20)
self.lbl2 = QtGui.QLabel(pretty(FIntQuestion[0], use_unicode = False), self)
self.lbl2.resize(200, 80)
self.lbl2.move(30,30)
self.lbl3 = QtGui.QLabel("Sketch pad",self)
self.lbl3.move(0,120)
# 用户可以用来演算的自由区域
self.SketchPad = QtGui.QTextEdit(self)
self.SketchPad.resize(250,150)
self.SketchPad.move(0,150)
self.lbl4 = QtGui.QLabel("Answer",self)
self.lbl4.move(0,300)
# 用户输入的答案
self.Answer = QtGui.QLineEdit(self)
self.Answer.move(0,330)
self.Answer.resize(250,20)
self.next_question = QtGui.QPushButton('Next', self)
self.next_question.move(160,360)
# 连接按钮的单击事件和处理问题1的方法
self.next_question.clicked.connect(self.HandleQuestion1)
# 用于存储用户回答所有问题后的分数
self.score = 0
# 用于测试
print(FIntAnswer[0])
def HandleQuestion1(self):
from FQuestions import FIntAnswer
# 弹出确认消息框,询问用户是否确认答案
reply = QtGui.QMessageBox.question(self, 'Message',
"Are you sure this is your final answer?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
# 如果用户确认答案,则检查答案是否正确
if reply == QtGui.QMessageBox.Yes:
if self.Answer.text() == FIntAnswer[0]:
self.score += 1
else:
self.score += 0
# 如果用户确认,则继续下一个问题
self.Question2()
def Question2(self):
from FQuestions import FIntQuestion, FIntAnswer
# 更新问题文本
self.lbl2.setText(pretty(FIntQuestion[1], use_unicode = False))
# 连接按钮的单击事件和处理问题2的方法
self.next_question.clicked.connect(self.HandleQuestion2)
# 用于测试
print(FIntAnswer[1])
def HandleQuestion2(self):
from FQuestions import FIntAnswer
# 弹出确认消息框,询问用户是否确认答案
reply = QtGui.QMessageBox.question(self, 'Message',
"Are you sure this is your final answer?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
# 如果用户确认答案,则检查答案是否正确
if reply == QtGui.QMessageBox.Yes:
if self.Answer.text() == FIntAnswer[1]:
self.score += 1
else:
self.score += 0
# 如果用户确认,则继续下一个问题
self.Question3()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = IntegrationQuestions()
window.show()
sys.exit(app.exec_())
当用户回答第一个问题并单击“Next”按钮时,会弹出一个消息框询问是否确认答案。如果用户确认,则会继续下一个问题。然而,当用户回答第二个问题并单击“Next”按钮时,会出现两个消息框,其中一个是第一个问题的确认消息框,另一个是第二个问题的确认消息框。以此类推,每回答一个问题,就会出现一个新的消息框。
2、解决方案
要解决这个问题,需要在连接新方法之前断开以前连接的信号。例如,在 HandleQuestion2
方法中,可以先断开 next_question
按钮与 HandleQuestion1
方法的连接,然后再将其与 HandleQuestion2
方法连接。
# 断开按钮与处理问题1方法的连接
self.next_question.clicked.disconnect(self.HandleQuestion1)
# 连接按钮与处理问题2方法
self.next_question.clicked.connect(self.HandleQuestion2)
这样,当用户回答第二个问题并单击“Next”按钮时,只会弹出一个消息框询问是否确认答案,而不会出现两个消息框。
以下代码展示了修正后的代码:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class IntegrationQuestions(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Integration')
self.setMinimumSize(265,400)
self.setMaximumSize(266,401)
self.Question1()
def Question1(self):
# 从另一个文件中获取问题
from FQuestions import FIntQuestion, FIntAnswer
self.lbl1 = QtGui.QLabel("Integrate the equation below",self)
self.lbl1.move(0,0)
self.lbl1.resize(200,20)
self.lbl2 = QtGui.QLabel(pretty(FIntQuestion[0], use_unicode = False), self)
self.lbl2.resize(200, 80)
self.lbl2.move(30,30)
self.lbl3 = QtGui.QLabel("Sketch pad",self)
self.lbl3.move(0,120)
# 用户可以用来演算的自由区域
self.SketchPad = QtGui.QTextEdit(self)
self.SketchPad.resize(250,150)
self.SketchPad.move(0,150)
self.lbl4 = QtGui.QLabel("Answer",self)
self.lbl4.move(0,300)
# 用户输入的答案
self.Answer = QtGui.QLineEdit(self)
self.Answer.move(0,330)
self.Answer.resize(250,20)
self.next_question = QtGui.QPushButton('Next', self)
self.next_question.move(160,360)
# 连接按钮的单击事件和处理问题1的方法
self.next_question.clicked.connect(self.HandleQuestion1)
# 用于存储用户回答所有问题后的分数
self.score = 0
# 用于测试
print(FIntAnswer[0])
def HandleQuestion1(self):
from FQuestions import FIntAnswer
# 弹出确认消息框,询问用户是否确认答案
reply = QtGui.QMessageBox.question(self, 'Message',
"Are you sure this is your final answer?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
# 如果用户确认答案,则检查答案是否正确
if reply == QtGui.QMessageBox.Yes:
if self.Answer.text() == FIntAnswer[0]:
self.score += 1
else:
self.score += 0
# 断开按钮与处理问题1方法的连接
self.next_question.clicked.disconnect(self.HandleQuestion1)
# 如果用户确认,则继续下一个问题
self.Question2()
def Question2(self):
from FQuestions import FIntQuestion, FIntAnswer
# 更新问题文本
self.lbl2.setText(pretty(FIntQuestion[1], use_unicode = False))
# 连接按钮的单击事件和处理问题2的方法
self.next_question.
通过上面这些方法,我们就可以避免 QMessageBox
的重复显示问题,并确保应用的对话框逻辑运行顺畅。