首页  >  文章  >  后端开发  >  如何从多线程高效更新 PyQt GUI?

如何从多线程高效更新 PyQt GUI?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-11-19 19:33:02327浏览

How Can I Efficiently Update a PyQt GUI from Multiple Threads?

多线程 PyQT 应用程序中的实时 GUI 更新

在使用 PyQt 进行多线程编程的世界中,出现了一个常见的挑战:如何有效地更新 GUI 以响应在单独的线程中执行的操作。本文旨在提供在此类应用程序中实现响应式和同步 GUI 更新的实际示例和见解。

引用传递方法

一种方法是将 GUI 元素的引用传递给线程。在线程内,您可以直接更新 UI 组件。然而,值得注意的是,Qt 小部件不是线程安全的,只能从主线程访问。 PyQt 文档强烈建议不要从主线程以外的线程访问 GUI 元素。

代码示例:

import sys
import urllib2

from PyQt4 import QtCore, QtGui


class DownloadThread(QtCore.QThread):
    def __init__(self, url, list_widget):
        QtCore.QThread.__init__(self)
        self.url = url
        self.list_widget = list_widget

    def run(self):
        info = urllib2.urlopen(self.url).info()
        self.list_widget.addItem('%s\n%s' % (self.url, info))


class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.list_widget = QtGui.QListWidget()
        self.button = QtGui.QPushButton("Start")
        self.button.clicked.connect(self.start_download)
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.list_widget)
        self.setLayout(layout)

    def start_download(self):
        urls = ['http://google.com', 'http://twitter.com', 'http://yandex.ru',
                'http://stackoverflow.com/', 'http://www.youtube.com/']
        self.threads = []
        for url in urls:
            downloader = DownloadThread(url, self.list_widget)
            self.threads.append(downloader)
            downloader.start()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())

信号和槽方法

更安全、更可靠从线程更新 GUI 的方法是通过信号和槽。信号允许您从线程发出自定义事件,GUI 可以监听并适当处理这些事件。

代码示例:

import sys
import urllib2

from PyQt4 import QtCore, QtGui


class DownloadThread(QtCore.QThread):

    data_downloaded = QtCore.pyqtSignal(object)

    def __init__(self, url):
        QtCore.QThread.__init__(self)
        self.url = url

    def run(self):
        info = urllib2.urlopen(self.url).info()
        self.data_downloaded.emit('%s\n%s' % (self.url, info))


class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.list_widget = QtGui.QListWidget()
        self.button = QtGui.QPushButton("Start")
        self.button.clicked.connect(self.start_download)
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.list_widget)
        self.setLayout(layout)

        # Connect our signal to our slot
        self.thread = DownloadThread()
        self.thread.data_downloaded.connect(self.on_data_ready)

    def start_download(self):
        urls = ['http://google.com', 'http://twitter.com', 'http://yandex.ru',
                'http://stackoverflow.com/', 'http://www.youtube.com/']
        self.threads = []
        for url in urls:
            downloader = DownloadThread(url)
            downloader.data_downloaded.connect(self.on_data_ready)
            self.threads.append(downloader)
            downloader.start()

    def on_data_ready(self, data):
        print data
        self.list_widget.addItem(unicode(data))


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())

通过利用信号和槽,我们确保所有 GUI 更新发生在主线程内,维护线程安全并防止潜在错误。

以上是如何从多线程高效更新 PyQt GUI?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn