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

2023-04-14 19:43:30 +08:00
 ALLROBOT

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

进度条窗口,附代码链接: 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

835 次点击
所在节点    问与答
4 条回复
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
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
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
2023-04-17 09:10:15 +08:00
不建议继承 QThread

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/932615

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX