Search code examples
pythonpyqtpyqt5qthreadqtablewidget

PyQt5 - update Qtablewidget with QThread


Can somebody help me out, app just crashes.

I've done the research and found this and below is my code:

from PyQt5.QtCore import QThread, pyqtSignal
import threading
import time

class Job(QThread):
    data_downloaded = pyqtSignal(str)

    def __init__(self, url):
        QThread.__init__(self)
        # self.__flag = threading.Event()
        # self.__flag.set()
        # self.__running = threading.Event()
        # self.__running.set()


    def run(self):
        for i in range(100):
            self.data_downloaded.emit("B")  # 朝connect的函数发射一个进度信号
            time.sleep(1)

    # def pause(self):
    #     self.__flag.clear()     # 设置为False, 让线程阻塞
    #
    # def resume(self):
    #     self.__flag.set()    # 设置为True, 让线程停止阻塞
    #
    # def stop(self):
    #     self.__flag.set()       # 将线程从暂停状态恢复, 如何已经暂停的话
    #     self.__running.clear()        # 设置为False

Main window:

from xxx import Job 
class SearchWindow(QWidget):
    ......
    ...... # There's a QTableWidget on main window, after right clicked "Start Download", Job will be created 
    ......

    def right_click_from_download_list_context(self):
        row_num = []
        for i in self.download_list.selectionModel().selection().indexes():
            row_num.append(i.row())
        popMenu = QMenu(self)
        self.start_download_action = QAction('Start Download', self)
        self.remove_task_action = QAction('删除此任务', self)
        self.start_download_action.triggered.connect(self.start_download)
        self.remove_task_action.triggered.connect(partial(self.remove_task, row_num))
        popMenu.addAction(self.start_download_action)
        popMenu.addAction(self.remove_task_action)
        popMenu.exec_(QCursor.pos())

    def start_download(self):
        print("AAAA")
        downloader = Job("http://www.baidu.com")
        print("BBB")
        downloader.data_downloaded.connect(self.update_download_process)
        print("ccc")
        downloader.start()
        print("ddd")

    @pyqtSlot(str)
    def update_download_process(self, data_process):
        print(data_process)

I've done some debugging, "AAAA","BBB","ccc","ddd" can be successfully print out, so I guess the error is in my Job QThread.

Can someone do me a favor, I just can NOT find where can be the error. Thanks in advance :)


Solution

  • The problem is because a variable that is created within a function only exists as long as the function is executed and the elimination of downloader will also eliminate the thread. For this there are 2 solutions:

    • Make a downloader member of the class:

    def start_download(self):
        print("AAAA")
        self.downloader = Job("http://www.baidu.com")
        print("BBB")
        self.downloader.data_downloaded.connect(self.update_download_process)
        print("ccc")
        self.downloader.start()
        print("ddd")
    
    • Pass a parent to Job:

    class Job(QThread):
        data_downloaded = pyqtSignal(str)
    
        def __init__(self, url, parent=None):
            QThread.__init__(self, parent)
    
        [...]
    
    
    class SearchWindow(QWidget):
        [...]
        def start_download(self):
            print("AAAA")
            downloader = Job("http://www.baidu.com", self)
            print("BBB")
            downloader.data_downloaded.connect(self.update_download_process)
            print("ccc")
            downloader.start()
            print("ddd")