V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
ALLROBOT
V2EX  ›  问与答

菜鸟求指教, pyqt5 的 QThread 发送信号后弹出对话框未响应,怎么解决?

  •  
  •   ALLROBOT · 2023-04-14 19:43:30 +08:00 · 840 次点击
    这是一个创建于 591 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设了一个场景,在处理文件的时候遇到错误,弹出警告窗口,三个按钮分别为重试、忽略或取消,可是警告窗口未响应,没有显示内容

    进度条窗口,附代码链接: https://gist.github.com/allrobot/3a6449b4389a1e28a907702d38d7422b

    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import Script
    from Vam_Dialogs import InterruptDialog
    from Vam_Modules import ScanPackages
    
    class ShowProgressBar(QWidget):
        def __init__(self, MaxNumber: int,worker):
            super().__init__()
            self.worker=worker
            # 忽略代码...
            
        @pyqtSlot(str)
        def show_dialog(self,text: str):
            self.dialog = InterruptDialog.InterruptProcessing(text)
            self.dialog.retry.connect(self.worker.resume)
            self.dialog.ignored.connect(self.worker.ignore)
            self.dialog.cancel.connect(progress_bar.progress_close)
            self.dialog.cancel.connect(self.worker.quit)
    
    '''输出依赖'''
    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
    app = QApplication(sys.argv)
    worker = ScanPackages.Worker(r'I:\VAM\Vam Pure\AddonPackages')
    progress_bar = ShowProgressBar(worker.exist_vars_path.__len__(),worker)
    worker.intReady.connect(progress_bar.update_progress_bar)
    worker.started.connect(worker.scan_meta_json)
    worker.showdialog.connect(worker.pause)
    worker.showdialog.connect(progress_bar.show_dialog)
    worker.finished.connect(progress_bar.progress_close)
    worker.start()
    app.exec_()
    

    QThread 代码,附代码链接: https://gist.github.com/allrobot/14be27794f8a9cd7dd08de40a3e443e9

        def scan_meta_json(self) -> None:
            num=0
            for file in self.exist_vars_path:
                self.intReady.emit(self.CurrentFiles)
                num+=1
                # 上锁
                self.mutex.lock()
                if num==500:
                    self.error = True
                    self.error_text = f'AddonPackages{file[1:]}\n\n 文件执行权限获取失败。\n\n 请确认文件是否被系统占用。\n\n 如果已关闭文件,点击返回继续处理操作任务。'
                    self.showdialog.emit(self.error_text)
                if self.isPause:
                    self.condition.wait(self.mutex)
                self.CurrentFiles += 1
                print(file)
                timer = QTimer()
                timer.setSingleShot(True)
                timer.start(1)
                loop = QEventLoop()
                timer.timeout.connect(loop.quit)
                loop.exec()
                self.mutex.unlock()
            os.chdir(self.current_path)
            self.finished.emit()
    

    请问为啥未响应?对话框自测了,能正常打开,但进度条没法调用对话框显示内容。。。

    对话框代码: https://gist.github.com/allrobot/aad2aa88f8ccdd8043a857478eebfab7

    NoOneNoBody
        1
    NoOneNoBody  
       2023-04-14 20:54:56 +08:00
    太长,暂时没看完,先说三点
    1.
    def close(self) :
    self.worker.quit()
    self.progress_close()

    def progress_close(self):
    self.close()
    这两个互相调用?死循环?

    2.
    worker.showdialog.connect(worker.pause)
    worker.showdialog.connect(progress_bar.show_dialog)
    connect 两个槽?把两个写到一块,connect 一个就好了
    如果分属两个对象,用参数传递对象再调用就好了

    3. 不要直接就 start 一个 Qthread
    应该在窗口类里面写一个函数 A ,在 A 里面实例化一个 QThread ,及其相关的 connect ,start
    实例化窗口的控件后,调用 A
    或者在窗口 init 里面创建 QThread 对象
    简单说应该在控件 show 后再调用 Qthread.start()
    这样理,顺一些

    感觉有点乱,例如等待用户响应的没必要用 timer ,timer 一般用在自动响应,如后台检查消息队列
    这个批量处理的任务,不要中途弹出对话框比较好,有问题记入一个 log 或者变量,结束时一起作为消息汇总弹出
    中途弹出要引入新的逻辑,如果弹出次数多每次还要点击操作,体验很差
    NoOneNoBody
        2
    NoOneNoBody  
       2023-04-14 21:11:58 +08:00
    还有个大问题,你的 QThread 里面为何没有 run()? start 是自动执行这个的啊

    把 scan_meta_json()改成 run()吧
    worker.started.connect(worker.scan_meta_json) 这句就没必要了

    另外 start 前最好加个判断
    if not someThread.isRunning(): someThread.start()
    ALLROBOT
        3
    ALLROBOT  
    OP
       2023-04-15 01:00:30 +08:00
    @NoOneNoBody 感谢建议,我用口语化描述 qt 逻辑说给 GPT ,然后按 chatgpt 给的代码写出来的,但跑不出来,改一改就写成这样了。。。再问 GPT ,GPT 说的不知所云😂

    对话框已解决,用 QMessageBox 即可,自己创建的对话框没法用

    果然我还是应该看官网文档或书籍比较好一点,自己边看文档边写太费劲。。。

    1. 代码写的欠缺逻辑
    2. 真不知道有这用法,网上搜了下,可以写成:worker.showdialog[str].connect(lambda x:(worker.pause(),progress_bar.show_message_box(x)))
    3. 受教了
    kanchi240
        4
    kanchi240  
       2023-04-17 09:10:15 +08:00
    不建议继承 QThread
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1314 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:53 · PVG 01:53 · LAX 09:53 · JFK 12:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.