簡體   English   中英

在調用函數時如何防止GUI凍結? (PyQT4,Python3)

[英]How do I keep GUI from freezing, while calling a function? (PyQT4, Python3)

問題背景:

我是PyQT4的新手。 我正在開發一個程序,我正在網上抓取數據到我的程序。 在信息下載時,我的GUI鎖定。 我想在一個單獨的后台線程中調用這個函數,也許使用QThread,但是我很難繞過QThread,Qt,以及插槽/信號通信方式。

我已經讀過關於創建一個泛型工作線程,它將調用傳遞給它的任何函數。 我不知道如何在我的主文件中實現它,以便我可以將我的函數作為后台進程運行。 如果可以顯示任何示例代碼,請詳細解釋每一行,因為我不了解該過程。

問題:

  1. 如何在函數運行時阻止GUI凍結?
  2. 我如何使用后台線程來運行我的類中的函數?

碼:

我的ui是從Qt 4 Designer創建的外部文件中加載的。

Github上的完整文件

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))

main.py(主文件)

def connections():
    # If button is clicked, call summary(), which web scrapes 
    # for data. This could take 5-30 seconds, this freezes UI.
    ui.btnRefreshSummary.clicked.connect(lambda: summary())

# Refresh items in gui
def refresh_ui():
    if summary_data != []:
        ui.valWatching.setText(summary_data[0])
        ui.valBidding.setText(summary_data[1])
        ui.valWon.setText(summary_data[2])
        ui.valNotWon.setText(summary_data[3])
        ui.valPurchases.setText(summary_data[4])
        ui.valInvoices.setText(summary_data[5])

def login():
    # Scrape website and login while in background; 
    # This locks up GUI until it completes.
    # Pretend this sleep command is the time it takes to login
    time.sleep(5)  # <-This would lock it up for 5 seconds

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    connections()
    # Load credentials from file.
    with open('login.txt') as f:
        credentials = f.readline().strip().split(':')
    f.closed

    # Login, download summary, then refresh the UI.
    b = Biddergy()
    b.login(credentials[0],credentials[1])
    summary_data = b.summary()
    b.logout()

    refresh_ui()
    sys.exit(app.exec_())

從示例代碼中不清楚為什么connections() 阻塞(給定它包含的代碼),或者為什么login() 不應該阻塞(假設登錄對話框通常這樣做)。 但無論如何,你的例子中的worker類可以像這樣轉換為QThread

class Worker(QThread):
    intReady = pyqtSignal(int)

    def run(self):
        for i in range(1, 10):
            time.sleep(1)
            self.intReady.emit(i)

然后它可以像這樣使用:

    # connections()
    # login()
    def slot(arg='finished'): print(arg)
    thread = Worker()
    thread.intReady.connect(slot)
    thread.finished.connect(slot)
    thread.start()

還有許多其他方法可以實現相同的功能 - 但哪一種最合適,以及實際如何實現,取決於應用程序的工作方式的詳細信息。

有了這個更新的代碼,我終於可以在后台啟動我的功能。 現在開始學習如何使我的后台線程與主UI線程進行通信。 非常感謝@ekhumoro對我非常耐心。

#!/usr/bin/env python3
from PySide import QtGui, QtCore
from PySide.QtCore import QThread, QObject, Signal, Slot
from main_gui import Ui_MainWindow  # my UI from Qt4 Designer(pyside-uic)
from Scrapers import Biddergy       # My own class
import sys
import queue

class BiddergyWrapper(QThread):
    def __init__(self, q, loop_time=1.0/60):
        self.q = q
        self.timeout = loop_time
        super(BiddergyWrapper, self).__init__()

    def onThread(self, function, *args, **kwargs):
        self.q.put((function, args, kwargs))

    def run(self):
        while True:
            try:
                function, args, kwargs = self.q.get(timeout=self.timeout)
                function(*args, **kwargs)
            except queue.Empty:
                self.idle()

    def idle(self):
        pass

    def _summary(self):
        b.summary()

    def summary(self):
        self.onThread(self._summary)

    def _login(self):
        b.login()

    def login(self):
        self.onThread(self._login())

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    ui.btnRefreshSummary.clicked.connect(lambda: bw.summary())

    # Load credentials from file.
    with open('login.txt') as f:
        credentials = f.readline().strip().split(':')

    # Login, download summary, then refresh the UI.
    b = Biddergy(credentials[0], credentials[1])
    request_queue = queue.Queue()
    bw = BiddergyWrapper(request_queue)
    bw.start()

    # Run QApplication
    app.exec_()
    # Begin "Graceful stop?"
    bw.quit()
    b.logout()
    sys.exit()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM