Обновление элементов графического интерфейса в MultiThreaded PyQT

Я искал какое-то время, чтобы найти информациюкак сделать многопоточную программу используя PyQT, обновив графический интерфейс, чтобы показать результаты.

Я привык учиться на собственном примере, и я не могу найти (да, я искал несколько недель) простой пример программы, использующей многопоточность, выполняющей такую простую задачу, как, например, подключение к списку сайтов www (5 потоков) и просто обработка печати URL с кодом ответа.

Может кто-нибудь поделиться кодом или отправить мне хороший учебник, где объясняется такая программа?

 Froyo31 мар. 2012 г., 18:36
эй, я не пробовал pyQt, но я использовал многопоточность в pygtk. В pygtk для этого обычно используется gobject. Вы должны искать что-то подобное для pyQt.

Ответы на вопрос(1)

Решение Вопроса

Вы можете передавать ссылки на элементы 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_())

Примечание редактора: Виджеты Qt не являются поточно-ориентированными, и к ним нельзя обращаться из какого-либо потока, кроме основногоДокументация Qt Больше подробностей). Правильный способ использования потоков - через сигналы / слоты, как показано во второй части этого ответа.

Кроме того, вы можете использовать сигналы и слоты, чтобы отделить графический интерфейс и сетевую логику.

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)

    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_())
 Winand08 апр. 2015 г., 16:28
Но запрещено взаимодействовать с графическим интерфейсом напрямую из не-основного (основного) потока, не так ли?
 reclosedev27 июл. 2015 г., 21:16
@three_pineapples, спасибо за редактирование! Я согласен с виджетами и безопасностью потоков. Этот код работал из-за удачи на конкретной версии, я думаю.
 Josh Usre23 мар. 2016 г., 19:36
Как бы я адаптировал это для нескольких рабочих с несколькими перечисляемыми элементами GUI /
 Whatang02 апр. 2012 г., 02:23
+1 за предложение использовать сигналы для отделения потоков от логики дисплея.
 Aaron Digulla15 апр. 2015 г., 17:17
Примечание: первый пример неверен. Вам не разрешено звонитьQListWidget.addItem() из нити. Вы должны использовать сигналы.

Ваш ответ на вопрос