线程处理时出现 msgbox 错误,GUI 块 [关闭]

2024-04-21

我在执行以下 gui 时遇到问题。如果没有消息框,它可以正常工作,但是当有消息框时,它会阻塞。知道为什么 gui 在有消息时会阻塞吗?谢谢

from PyQt5 import QtCore, QtGui, QtWidgets
import threading
import time
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setObjectName("pushButton")
        self.verticalLayout.addWidget(self.pushButton)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.pushButton.pressed.connect(self.threadingc)      
    def calculation(self):
        for i in range(10):
            time.sleep(1)
            print(i)
        msg = QtWidgets.QMessageBox()
        msg.setInformativeText('Finish')
        msg.exec_()   
    def threadingc(self):
        x=threading.Thread(target=self.calculation)
        x.start()
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
import sys
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Any仅允许从 Qt 主线程内访问 UI 元素。注意access不仅意味着读/写小部件属性,还意味着创建;从其他线程执行此操作的任何尝试都会在最好的情况下导致图形问题或不一致的行为,并在最坏(也是更常见)的情况下导致崩溃。

唯一正确的方法是使用带有(可能)自定义信号的 QThread:这允许 Qt 正确地对信号进行排队,并在实际可以处理它们时对它们做出反应。

下面是一个very简单的情况,不需要创建 QThread 子类,但请考虑这只是为了教育性的目的。

class Ui_MainWindow(object):
    # ...

    def calculation(self):
        for i in range(10):
            time.sleep(1)
            print(i)

    def showMessage(self):
        msg = QtWidgets.QMessageBox()
        msg.setInformativeText('Finish')
        msg.exec_()   
        self.pushButton.setEnabled(True)

    def threadingc(self):
        self.pushButton.setEnabled(False)
        self.thread = QtCore.QThread()
        # override the `run` function with ours; this ensures that the function
        # will be executed in the new thread
        self.thread.run = self.calculation
        self.thread.finished.connect(self.showMessage)
        self.thread.start()

请考虑以下重要方面:

  • 我必须禁用该按钮,否则可能会在前一个线程仍在执行的同时创建一个新线程;这会产生一个问题,因为覆盖self.thread将导致 python 尝试垃圾收集(delete) 运行时的前一个线程,这是一个very bad thing;
  • 一个可能的解决方案是创建具有父线程的线程,这通常通过简单的方法完成QThread(self),但这在您的情况下是不可能的,因为 Qt 对象只能接受其他 Qt 对象作为其父对象,而在您的情况下self将是一个Ui_MainWindow实例(这是一个基本的Python对象);
  • 上述一点是一个重要的问题,因为您试图从pyuic生成的文件,应该never完成:这些文件应该保持原样any手动修改,仅作为导入模块使用;在官方指南中阅读有关此主题的更多信息使用设计器 https://www.riverbankcomputing.com/static/Docs/PyQt5/designer.html;还要注意,尝试模仿这些文件的行为是没有用的,因为通常会导致对对象结构的极大混乱;
  • 理论上你可以添加对 qt 对象的引用(例如,通过添加self.mainWindow = MainWindow in the setupUi()函数)并使用该引用创建线程(thread = QThread(self.mainWindow)),或者将线程添加到持久列表(self.threads = [],再次在setupUi()),但由于上述几点,我强烈建议您不要这样做;

最后,还有一个correct代码的实现需要您再次生成 ui 文件,保持原状并执行类似以下示例的操作;请注意,我添加了一个非常基本异常实现还展示了如何正确与自定义信号交互。

from PyQt5 import QtCore, QtGui, QtWidgets
from mainwindow import Ui_MainWindow
import time

class Calculation(QtCore.QThread):
    error = QtCore.pyqtSignal(object)
    def run(self):
        for i in range(10):
            time.sleep(1)
            print(i)
            try:
                10 / 0
            except Exception as e:
                self.error.emit(e)
                break


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.pushButton.pressed.connect(self.threadingc)

    def showMessage(self):
        msg = QtWidgets.QMessageBox()
        msg.setInformativeText('Finish')
        msg.exec_()   

    def threadingc(self):
        # create the thread with the main window as a parent, this is possible 
        # since QMainWindow also inherits from QObject, and this also ensures
        # that python will not delete it if you want to start another thread
        thread = Calculation(self)
        thread.finished.connect(self.showMessage)
        thread.error.connect(self.showError)
        thread.start()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

在上述情况下,使用以下命令处理 ui 文件(显然,假设 ui 名为“mainwindow.ui”):

pyuic mainwindow.ui -o mainwindow.py
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程处理时出现 msgbox 错误,GUI 块 [关闭] 的相关文章

  • Tkinter 菜单删除项

    如何删除任何菜单项 例如我想删除 播放 self menubar Menu self root self root config menu self menubar self filemenu2 Menu self menubar self
  • 将 yerr/xerr 绘制为阴影区域而不是误差线

    在 matplotlib 中 如何将误差绘制为阴影区域而不是误差条 例如 而不是 忽略示例图中各点之间的平滑插值 这需要进行一些手动插值 或者只是获得更高分辨率的数据 您可以使用pyplot fill between https matpl
  • 如何删除 PyCharm 中的项目?

    如果我关闭一个项目 然后删除该项目文件夹 则在 PyCharm 重新启动后 会再次创建一个空的项目文件夹 只需按顺序执行以下步骤即可 他们假设您当前在 PyCharm 窗口中打开了该项目 单击 文件 gt 关闭项目 关闭项目 在 PyCha
  • 从字典的元素创建 Pandas 数据框

    我正在尝试从字典创建一个 pandas 数据框 字典设置为 nvalues y1 1 2 3 4 y2 5 6 7 8 y3 a b c d 我希望数据框仅包含 y1 and y2 到目前为止我可以使用 df pd DataFrame fr
  • 数据框 - 平均列

    我在 pandas 中有以下数据框 Column 1 Column 2 Column3 Column 4 2 2 2 4 1 2 2 3 我正在创建一个数据框 其中包含第 1 列和第 2 列 第 3 列和第 4 列等的平均值 ColumnA
  • 如何使用 Python boto3 获取 redshift 中的列名称

    我想使用 python boto3 获取 redshift 中的列名称 创建Redshift集群 将数据插入其中 配置的机密管理器 配置 SageMaker 笔记本 打开Jupyter Notebook写入以下代码 import boto3
  • 如何获取numpy.random.choice的索引? - Python

    是否可以修改 numpy random choice 函数以使其返回所选元素的索引 基本上 我想创建一个列表并随机选择元素而不进行替换 import numpy as np gt gt gt a 1 4 1 3 3 2 1 4 gt gt
  • 在Python中读取tiff标签

    我正在尝试用 Python 读取 tiff 文件的标签 该文件是 RGB 的uint16每个通道的值 我目前正在使用tifffile import tifffile img tifffile imread file tif 然而 img是一
  • 更改QLineEdit的ClearButton图标

    我想在Windows 10 1909 64位 上的Python 3 8和PyQt5 5 15 0 上更改我的QLineEdit的ClearButton图标 稍后我想在Linux上运行代码 我尝试应用此处找到的代码 如何在 QLineEdit
  • Flask 应用程序路由中的多个参数

    烧瓶怎么写app route如果我在 URL 调用中有多个参数 这是我从 AJax 调用的 URL http 0 0 0 0 8888 createcm summary VVV change Feauure 我试图写我的烧瓶app rout
  • 为正则表达式编写解析器

    即使经过多年的编程 我很羞愧地说我从未真正完全掌握正则表达式 一般来说 当问题需要正则表达式时 我通常可以 在一堆引用语法之后 想出一个合适的正则表达式 但我发现自己越来越频繁地使用这种技术 所以 自学并理解正则表达式properly 我决
  • Python守护进程:保持日志记录

    我有一个将一些数据记录到磁盘的脚本 logging basicConfig filename davis debug log level logging DEBUG logging basicConfig filename davis er
  • 确定分割形状几何体的“左”侧和“右”侧

    我的问题是 我怎样才能确定哪一个Aside and Bside的侧面已经分割的旋转矩形几何体 http nbviewer jupyter org urls dl dropbox com s ll3mchnx0jwzjnf determine
  • PyInstaller“ValueError:源代码字符串不能包含空字节”

    我得到了一个ValueError source code string cannot contain null bytes执行命令时pyinstaller main py在具有和不具有管理员权限的cmd中 Traceback most re
  • 仅允许正小数

    在我的 Django 模型中 我创建了一个如下所示的小数字段 price models DecimalField u Price decimal places 2 max digits 12 显然 价格为负或零是没有意义的 有没有办法将小数
  • 在 numpy 中连接维度

    我有x 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 2 3 I want 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 6 也就是说 我想连接中间维度的所有项目 在这种特殊情况下我可以得到这
  • java中使用多线程调用同一类的不同方法

    我有一个类 如下所示 具有三种方法 public class MyRunnable implements Runnable Override public void run what code need to write here to c
  • 非法指令:MacOS High Sierra 上有 4 条指令

    我正在尝试在 pygame 3 6 中制作一个看起来像聊天的窗口 我刚刚将我的 MacBook 更新到版本 10 13 6 在我这样做之前它工作得很好 但在我收到消息之后 非法指令 4 Code import pygame from pyg
  • Python 中的 Unix cat 函数 (cat * > merged.txt)? [复制]

    这个问题在这里已经有答案了 一旦建立了目录 有没有办法在Python中使用Unix中的cat函数或类似的函数 我想将 files 1 3 合并到 merged txt 我通常会在 Unix 中找到该目录 然后运行 cat gt merged
  • 使用 paramiko 运行 Sudo 命令

    我正在尝试执行sudo使用 python paramiko 在远程计算机上运行命令 我尝试了这段代码 import paramiko ssh paramiko SSHClient ssh set missing host key polic

随机推荐