MainWindow 不会同时处理事件和用户操作

MainWindow do not process events and user actions concurrently

我有一个使用 Qt Designer 制作的 PyQt5 MainWindow。

此 window 应该抓取网站并在找到后在 TreeView 中列出已抓取的 link。

我可以通过创建模型来做到这一点,QStandardItemModel 每次抓取新的 link 时,将所有 link 添加到模型中,然后将模型设置为TreeView.setModel(model) 的树,然后我调用 QtWidgets.qApp.processEvents() 所以 window 被更新。当软件抓取站点时,window 不会响应用户交互,直到执行 QtWidgets.qApp.processEvents()

如何使用最新抓取的 link 更新我的 TreeView 并且在抓取过程中仍然让我的 window 难以处理?

这是我的代码

def start(self):
    ## start crawling
    self.populate_tree(crawled_links)

def populate_tree(self, links):
    data = []
    for index in links:
        item = (links[index]['from'], [])
        for link in links[index]['url']:
            item[1].append((link, []))
        data.append(item)
    model = QtGui.QStandardItemModel()
    self.__add_items(model, data)
    self.treeView.setModel(model)
    self.treeView.expandAll()
    self.treeView.scrollToBottom()
    self.treeView.setHeaderHidden(True)
    QtWidgets.qApp.processEvents()

def __add_items(self, model, data):
    for text, children in data:
        item = QtGui.QStandardItem(text)
        model.appendRow(item)
        if children:
            self.__add_items(item, children)

如果有任何帮助,crawled_links 列表如下所示:

crawled_links = {
0:{
    'url': {
        'one.html',
        'three.html'
        },
    'from':
        'site1.com'
    },
1:{
    'url': {
        'two.html'
        },
    'from':
        'site1.com'
    }
}

使用 processEvents() 是一种不好的做法,它们应该只用于某些特殊任务,如您所见并不能解决问题。

解决方案是在线程上执行任务,通过信号发送给GUI的线程。


import threading

from PyQt5 import QtCore, QtWidgets

class Helper(QtCore.QObject):
     resultChanged = QtCore.pyqtSignal(dict)

     def start_crawling(self):
         crawled_links = {}
         # processing
         self.resultChanged.emit(crawled_links)


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
     def __init__(self, parent=None)
         QtWidgets.QMainWindow.__init__(self, parent)
         self.setupUi(self)
         self.helper = Helper()
         self.helper.resultChanged.connect(self.populate_tree)

     def start(self):
         # start crawling
         threading.Thread(target=self.helper.start_crawling, daemon=True).start()


     def populate_tree(self, crawled_links)
         ...