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

10,514

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).

Share:
10,514

Related videos on Youtube

pretzlstyle
Author by

pretzlstyle

Updated on June 04, 2022

Comments

  • pretzlstyle
    pretzlstyle almost 2 years

    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?

    • Mel
      Mel over 8 years
      Possible duplicate of An event for focus changed?
    • Alex Huszagh
      Alex Huszagh over 8 years
      Not really @tmoreau, it's an issue of GUI-blocking. focusChanged is indeed a good signal when needed, or focusInEvent for their applications, but if the main thread is blocked, they will not be called until well after the long task finishes.
    • Oliver
      Oliver over 8 years
      Although qthread is typically a better approach to long running functions, calling app.processEvents() might be sufficient if called from the right place and could lead to a much simpler fix to your issue. If you post the code in the vicinity of where you call app.processEvents() you might get an alternative approach.
  • pretzlstyle
    pretzlstyle over 8 years
    Thank you, this is certainly the best way to go. My program is fairly complex, and long, so making these changed would be a pretty massive overhaul. But it is necessary, the program feels shaky as it is and I always felt that it needed something like this. Thanks for the links and info.
  • Alex Huszagh
    Alex Huszagh over 8 years
    Of course, one thing I will mention is that make sure you know how resources are accessed if it could potentially be shared between two threads. Not all operations are atomic, which means if a resource is potentially shared between two threads, you could have unexpected results. (Most Python objects, however, are safe). If you need access to a resource between two threads, look into a QMutex: doc.qt.io/qt-4.8/qmutex.html