2012-03-31 61 views
9

我正在研究一段時間來查找信息如何使用PyQT執行多線程程序,更新GUI以顯示結果更新MultiThreaded PyQT中的GUI元素

我習慣於通過示例進行學習,但找不到(是的,我正在尋找幾周)任何使用多線程程序的簡單示例,可以執行諸如連接到www站點列表(5個線程)等簡單任務,只需打印帶響應代碼的處理過的網址即可。

任何人都可以共享代碼或發送給我很好的教程,這樣的程序解釋?

+0

哎,我沒試過PyQt的,但我在pygtk的使用多線程。在pygtk中,gobject通常用於這樣做。你應該搜索pyQt類似的東西。 – Froyo 2012-03-31 16:36:28

+0

另請參閱http://stackoverflow.com/questions/11265812/pyside-pyqt-starting-a-cpu-intensive-thread-hangs-the-whole-application,http://stackoverflow.com/questions/16879971/example -of-the-right-way-to-use-qthread-in-pyqt,http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt或http://stackoverflow.com/questions/20752154/pyqt-connecting-a-signal-to-a-slot-to-start-a-background-operation – Trilarion 2015-01-07 09:44:15

回答

22

這裏有一些非常基本的例子。

您可以將對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 documentation瞭解詳細信息)進行訪問。正如本答案的第二部分所示,使用線程的正確方法是通過信號/插槽。


另外,您可以使用信號和插槽來分離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) 

    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_()) 
+0

我將分析這個例子。謝謝。 – Nuncjo 2012-04-01 13:28:38

+1

+1用於建議使用信號將線程從顯示邏輯中分離出來。 – Whatang 2012-04-02 00:23:07

+0

示例非常棒,這正是我所尋找的,但是如何將線程數限制爲5個同時工作? – Nuncjo 2012-04-07 13:55:12