How to keep the GUI from freezing when calling a function? (PyQT4, Python3)

Question:

I am new to PyQT4. I develop a program with it, and I use web search to get data in my program. While the information loads my graphical interface. I would like to call this function in a separate background thread, possibly using QThread, but it's hard for me to wrap my head around QThread, Qt as a whole and the way the slots / signals are transmitted.

I read about creating a generic workflow that will call any function passed to it. I do not know how to implement it in my main file so that I can perform my functions as a background process. If any sample code can be shown, please explain each line in detail, as I do not understand this process.

Questions:

  • How can I prevent my GUI from freezing while the function is running?
  • How to use background thread to run functions from my class?

code:

My ui is loaded from an external file created by Qt 4 Designer.

Complete Files on Github

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

main.py (main file)

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_())
+4
source share
2 answers

It is not clear from the code example why it connections()blocks (given the code that it contains), or why login()it should not be blocked (given that this is what they usually do in login dialogs). But in any case, the working class in your example can be converted to QThreadas follows:

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

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

and then it can be used as follows:

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

, , , , .

+5

. , . @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()
+2

Source: https://habr.com/ru/post/1614042/


All Articles