pretzlstyle
pretzlstyle

Reputation: 2962

How to make QtGui window process events whenever it is brought forward on the screen?

I'm using PyQt for Python, and am building a gui. I had a problem a few weeks ago where I had a function outside of the gui module modifying widgets within the gui (advanced progress bar, updating strings, etc.), and those modifications were not reflected in the gui until the function that had made the changes finished running.

The solution to this was to simply call app.processEvents() after doing whatever modifications I wanted, which would immediately update the graphics of the window.

But now I am wondering, is there a way to do this everytime the window is brought forward?

Let's say I have called a function that will be modifying the progress bar, but this function takes quite a while to run. Inbetween calling the function, and the progress bar modification, the app processes no events. So, it during this time, I pull up a Chrome window (or anything else), and then close it, my gui window is blank, just gray, until app.processEvents() is called again.

Is ther functionality in PyQt that allows me to detect whenever the window is brought to the front of all current windows?

Upvotes: 6

Views: 14395

Answers (1)

Alex Huszagh
Alex Huszagh

Reputation: 14614

You should look into QThread.

Threads allow you to run long, complicated tasks in a worker thread while a background thread keeps the GUI responsive, such as updating a QProgressBar, ensuring it responds to motion events.

The basic idea is this:

# load modules
import time

from PySide import QtCore, QtGui


# APPLICATION STUFF
# -----------------

APP = QtGui.QApplication([])


# THREADS
# -------


class WorkerThread(QtCore.QThread):
    '''Does the work'''

    def __init__(self):
        super(WorkerThread, self).__init__()

        self.running = True

    def run(self):
        '''This starts the thread on the start() call'''

        # this goes over 1000 numbers, at 10 a second, will take
        # 100 seconds to complete, over a minute
        for i in range(1000):
            print(i)
            time.sleep(0.1)

        self.running = False


class BackgroundThread(QtCore.QThread):
    '''Keeps the main loop responsive'''

    def __init__(self, worker):
        super(BackgroundThread, self).__init__()

        self.worker = worker

    def run(self):
        '''This starts the thread on the start() call'''

        while self.worker.running:
            APP.processEvents()
            print("Updating the main loop")
            time.sleep(0.1)


# MAIN
# ----


def main():
    # make threads
    worker = WorkerThread()
    background = BackgroundThread(worker)

    # start the threads
    worker.start()
    background.start()
    # wait until done
    worker.wait()

if __name__ == '__main__':
    main()

The output you get is something like this, showing how it takes turns at doing the long calculation and updating the main loop:

0
 Updating the main loop
1
Updating the main loop
2
Updating the main loop
3
Updating the main loop
4
Updating the main loop
5
Updating the main loop
6
Updating the main loop
Updating the main loop7

8
Updating the main loop
9

This along with a QFocusEvent override should allow you to do whatever you wish. But it's better to separate updating the GUI and running your desired long thread.

As for overriding the QFocusEvent you can do something as follows:

def focusInEvent(self, event):
    event.accept()

    # insert your code here

And if you choose to implement threads to avoid GUI blocking, you should read about the basics of threading (as threads have a lot of nuances unless you know about their potential pitfalls).

Upvotes: 8

Related Questions