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

PyQt5中QDialog实时更新QListWidget并自动关闭问题

解决PyQt5备份对话框实时更新与自动关闭问题

你的问题核心是耗时的备份操作阻塞了主线程,导致UI无法实时刷新,对话框也无法响应关闭信号。Qt要求所有UI操作必须在主线程执行,耗时任务需要放到子线程中处理,通过信号与槽机制实现线程间通信。

以下是修改后的完整代码,解决了实时更新和自动关闭的问题:

import random
import sys
import time

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QListWidget, QListWidgetItem, QMessageBox


class BackupWorker(QtCore.QThread):
    # 定义信号:向主线程发送UI更新消息和备份完成状态
    update_log = QtCore.pyqtSignal(str)
    backup_finished = QtCore.pyqtSignal(int)

    def run(self):
        # 执行所有耗时备份逻辑
        self.update_log.emit("getting_started() called")
        self.check_usb_drive()
        self.backup_routine()

    def check_usb_drive(self):
        self.update_log.emit("check_usb_drive() called")
        self.update_log.emit(f"randomly time.sleep(random.randint(1,5))")
        time.sleep(random.randint(1, 5))

    def backup_routine(self):
        self.update_log.emit("backup_routine() called")
        self.update_log.emit(f"randomly time.sleep(random.randint(1,5))")
        time.sleep(random.randint(1, 5))
        backup_ok = random.choice([True, False])
        if backup_ok:
            self.update_log.emit("Signal 1 emitted, backup ok")
            self.backup_finished.emit(1)
        else:
            self.update_log.emit("Signal 0 emitted, backup not ok")
            self.backup_finished.emit(0)


class Backup_GUI(QDialog):
    def __init__(self):
        super().__init__(parent=None)

        self.setWindowTitle("Daily Backup ... ")
        self.layout = QVBoxLayout()
        self.info = QListWidget()
        self.info.addItem(QListWidgetItem("Please insert USB drive ... "))
        self.info.addItem(QListWidgetItem("Looking for new USB drive ... "))
        self.info.setAutoScroll(True)
        self.layout.addWidget(self.info)
        self.setLayout(self.layout)

        # 创建并配置备份工作线程
        self.backup_worker = BackupWorker()
        # 连接子线程信号到主线程槽函数
        self.backup_worker.update_log.connect(self.add_log_item)
        self.backup_worker.backup_finished.connect(self.handle_backup_result)
        # 线程结束后自动清理资源
        self.backup_worker.finished.connect(self.backup_worker.deleteLater)

    def add_log_item(self, text):
        # 主线程中更新UI,添加日志项
        self.info.addItem(QListWidgetItem(text))
        # 自动滚动到最新日志
        self.info.scrollToBottom()

    def handle_backup_result(self, backupcode):
        self.add_log_item(f"own_func() called; BackupCode {backupcode} ==> {'self.accept()' if backupcode ==1 else 'self.reject()'}")
        if backupcode == 1:
            self.accept()
        else:
            self.reject()

    def start_backup(self):
        # 启动备份线程
        self.backup_worker.start()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    backup_window = Backup_GUI()
    # 先启动备份线程,再显示对话框
    backup_window.start_backup()
    answ = backup_window.exec()
    if answ == QMessageBox.Accepted:
        print("all good")
    else:
        print("not so good")

    print("finished and closed ... or not")

关键修改点说明:

  • 分离耗时操作到子线程:创建BackupWorker继承自QThread,把check_usb_drive、backup_routine等耗时方法放到run()中执行,避免阻塞主线程。
  • 信号与槽通信:子线程通过update_log信号向主线程发送日志文本,主线程的add_log_item槽函数负责更新QListWidget;备份完成后通过backup_finished信号通知主线程处理关闭逻辑。
  • 线程生命周期管理:连接finished信号到deleteLater,确保线程结束后自动释放资源,避免内存泄漏。
  • 调整启动顺序:先启动备份线程,再调用exec()显示对话框,确保UI事件循环正常运行。

这样修改后,QListWidget会实时显示备份状态,备份完成后对话框会自动关闭,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 05:40:07