Skip to main content
 首页 » 编程设计

python之PyQt5 线程 GUI 不工作

2025年05月04日38mfryf

我正在尝试加载一些需要 30 多秒的数据。在此期间,我希望用户看到一个小的 GUI,上面写着“正在加载。”,然后是“正在加载..”,然后是“正在加载...”,然后是“正在加载”。等。我读了一些书,我想我必须把它放在一个单独的线程中。我发现有人遇到了类似的问题,建议解决方案是在正确的位置:

t = threading.Thread(target=self.test) 
t.daemon = True 
t.start() 

在文件的下半部分我有测试函数

def test(self): 
    tmp = InfoMessage() 
 
    while True: 
        print(1) 

和 InfoMessage 函数

from PyQt5 import uic, QtCore, QtGui, QtWidgets 
import sys 
 
class InfoMessage(QtWidgets.QDialog): 
    def __init__(self, msg='Loading ', parent=None): 
        try: 
            super(InfoMessage, self).__init__(parent) 
            uic.loadUi('ui files/InfoMessage.ui',self) 
 
            self.setWindowTitle(' ') 
 
            self.o_msg = msg 
            self.msg = msg 
            self.info_label.setText(msg) 
            self.val = 0 
 
            self.timer = QtCore.QTimer() 
            self.timer.setInterval(500) 
            self.timer.timeout.connect(self.update_message) 
            self.timer.start() 
 
            self.show() 
        except BaseException as e: 
            print(str(e)) 
 
    def update_message(self): 
        self.val += 1 
        self.msg += '.' 
 
        if self.val < 20: 
            self.info_label.setText(self.msg) 
        else: 
            self.val = 0 
            self.msg = self.o_msg 
 
        QtWidgets.QApplication.processEvents() 
 
def main(): 
    app = QtWidgets.QApplication(sys.argv)      # A new instance of QApplication 
    form = InfoMessage('Loading ')                  # We set the form to be our MainWindow (design) 
    app.exec_()                                 # and execute the app 
 
if __name__ == '__main__':                      # if we're running file directly and not importing it 
    main()                                      # run the main function 

当我单独运行 InfoMessage 函数时,它工作正常,并且每 0.5 秒更新一次等等。但是,当我将其作为加载文件的一部分使用时,GUI 是空白的并且显示不正确。我知道它保留在测试函数中,因为那里有 print 语句。

有人能指出我正确的方向吗?我想我错过了几个步骤。

请您参考如下方法:

首先,有两种方法可以做到这一点。一种方法是使用 Python 内置线程模块。另一种方法是使用与 PyQT 更加集成的 QThread 库。通常,我建议使用 QThread 在 PyQt 中进行线程处理。但只有在与 PyQt 进行交互时才需要 QThread。

其次,我从 InfoMessage 中删除了 processEvents(),因为它在您的特定情况下没有任何用处。

最后,将您的线程设置为守护进程意味着您的线程将永远不会停止。大多数功能并非如此。

import sys 
import threading 
import time 
 
from PyQt5 import uic, QtCore, QtWidgets 
from PyQt5.QtCore import QThread 
 
 
def long_task(limit=None, callback=None): 
    """ 
    Any long running task that does not interact with the GUI. 
    For instance, external libraries, opening files etc.. 
    """ 
    for i in range(limit): 
        time.sleep(1) 
        print(i) 
    if callback is not None: 
        callback.loading_stop() 
 
 
class LongRunning(QThread): 
    """ 
    This class is not required if you're using the builtin 
    version of threading. 
    """ 
    def __init__(self, limit): 
        super().__init__() 
        self.limit = limit 
 
    def run(self): 
        """This overrides a default run function.""" 
        long_task(self.limit) 
 
 
class InfoMessage(QtWidgets.QDialog): 
    def __init__(self, msg='Loading ', parent=None): 
        super(InfoMessage, self).__init__(parent) 
        uic.loadUi('loading.ui', self) 
 
        # Initialize Values 
        self.o_msg = msg 
        self.msg = msg 
        self.val = 0 
 
        self.info_label.setText(msg) 
        self.show() 
 
        self.timer = QtCore.QTimer() 
        self.timer.setInterval(500) 
        self.timer.timeout.connect(self.update_message) 
        self.timer.start() 
 
    def update_message(self): 
        self.val += 1 
        self.msg += '.' 
 
        if self.val < 20: 
            self.info_label.setText(self.msg) 
        else: 
            self.val = 0 
            self.msg = self.o_msg 
 
    def loading_stop(self): 
        self.timer.stop() 
        self.info_label.setText("Done") 
 
 
class MainDialog(QtWidgets.QDialog): 
    def __init__(self, parent=None): 
        super(MainDialog, self).__init__(parent) 
 
        # QThread Version - Safe to use 
        self.my_thread = LongRunning(limit=10) 
        self.my_thread.start() 
        self.my_loader = InfoMessage('Loading ') 
        self.my_thread.finished.connect(self.my_loader.loading_stop) 
 
        # Builtin Threading - Blocking - Do not use 
        # self.my_thread = threading.Thread( 
        #     target=long_task, 
        #     kwargs={'limit': 10} 
        # ) 
        # self.my_thread.start() 
        # self.my_loader = InfoMessage('Loading ') 
        # self.my_thread.join()  # Code blocks here 
        # self.my_loader.loading_stop() 
 
        # Builtin Threading - Callback - Use with caution 
        # self.my_loader = InfoMessage('Loading ') 
        # self.my_thread = threading.Thread( 
        #     target=long_task, 
        #     kwargs={'limit': 10, 
        #             'callback': self.my_loader} 
        # ) 
        # self.my_thread.start() 
 
 
def main(): 
    app = QtWidgets.QApplication(sys.argv) 
    dialog = MainDialog() 
    app.exec_() 
 
if __name__ == '__main__': 
    main() 

如有任何关于此代码的后续问题,请随时提出。

祝你好运。

编辑: 更新以显示如何在线程完成时运行代码。请注意添加到 long_task 函数的新参数。