You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5子线程中如何获取MessageBox的用户点击按钮结果?

解决PyQt5子线程触发弹窗后获取用户点击值的问题

问题根源

  1. 子线程function_one发射弹窗信号后立刻读取btn_pressed,但弹窗在主线程显示,用户操作需要时间,此时btn_pressed还未被赋值
  2. show_message方法错误调用了主窗口实例的exec_(),应该调用弹窗自身的exec_()
  3. 自定义MainMessage类未调用add_btn()方法,导致传入的按钮没有被添加到弹窗中

修改方案

通过新增信号传递弹窗结果,结合QEventLoop让子线程等待用户操作完成,具体步骤:

  • 新增resultSignal信号,用于主线程将弹窗点击结果传回子线程
  • 在function_one中创建事件循环,等待结果信号触发后再执行后续逻辑
  • 修正弹窗的按钮添加和执行逻辑

修改后的完整代码

模块代码(main_message.py)

from PyQt5.QtWidgets import QMessageBox

class MainMessage(QMessageBox):
    def __init__(self, title, text, buttons):
        super(MainMessage, self).__init__()
        self.setWindowTitle(title)
        self.setText(text)
        self.button_list = buttons
        self.add_btn()  # 初始化时直接添加按钮

    def add_btn(self):
        for button_add in self.button_list:
            self.addButton(button_add)

    def info(self):
        self.setIcon(QMessageBox.Information)

主模块代码

from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from PyQt5 import QtCore
from main_message import MainMessage
import time

class MyThread(QtCore.QThread):
    def __init__(self, func):
        super(MyThread, self).__init__()
        self.function_list = func

    def run(self):
        for function_to_exec in self.function_list:
            function_to_exec()

class Main(QMainWindow):
    messageSignal = QtCore.pyqtSignal(str, str, list)
    resultSignal = QtCore.pyqtSignal(int)  # 新增传递结果的信号

    def __init__(self):
        super(Main, self).__init__()
        self.resize(800, 600)
        self.function_list = [self.function_one, self.function_two]
        self.message = MainMessage
        self.messageSignal.connect(self.show_message)
        self.btn_pressed = None
        self.start()

    def start(self):
        self.main_thread = MyThread(self.function_list)
        self.main_thread.start()

    def function_one(self):
        time.sleep(3)
        # 创建事件循环,等待弹窗结果
        loop = QtCore.QEventLoop()
        self.resultSignal.connect(loop.quit)
        
        self.messageSignal.emit("提示", "确认操作吗?", [QMessageBox.Ok, QMessageBox.Cancel])
        loop.exec_()  # 暂停子线程,直到结果信号触发

        # 现在可以获取到用户点击结果
        print(f"用户点击按钮值:{self.btn_pressed}")
        if self.btn_pressed == QMessageBox.Ok:
            print("用户选择了确认")
        elif self.btn_pressed == QMessageBox.Cancel:
            print("用户选择了取消")
        print("fun_one finish")

    def function_two(self):
        time.sleep(3)
        print("fun_two finish")

    @QtCore.pyqtSlot(str, str, list)
    def show_message(self, title, text, buttons):
        new_message = self.message(title, text, buttons)
        new_message.info()
        self.btn_pressed = new_message.exec_()  # 调用弹窗自身的exec_()
        self.resultSignal.emit(self.btn_pressed)  # 将结果发回子线程

app = QApplication([])
m = Main()
m.show()
app.exec_()

内容的提问来源于stack exchange,提问作者Revsky01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:42:34