PyQt: app.exec_() stops all following code from running

That is intended. What you have to do is use signals/slots, code inside your Qt classes, or spawn off threads before you call app.exec().

Signals and slots are your defacto way of interacting with Qt. Basically a signal is any "event" or custom "event" and slots can be thought of as "event handlers". For instance when someone hits a button on a GUI it creates a signal that seeks out any handler that is connected to it. You can connect none, one, or many slots to each signal (you can even connect the same one multiple times)! Here is a good reference for this in python.

Coding inside your Qt classes usually means creating slots that do useful work for you. Remember you don't want to hold up the event loop too long so spawn a new thread if you do this.

The third option available to you is to spin off other threads. Be careful interacting with Qt from threads, if you do you MUST us signals and slots. Implement threading as suggested in this SO.


app.exec_() does not lock anything, it runs a GUI event loop that waits for user actions (events) and dispatches them to the right widget for handling. It does this until there are no top level windows left open; if you leave at least one top level window of your app open, then exec() never returns, it can't (your app will be terminated during system shutdown). When no more top level windows the app cleans up and returns from exec(). At that point the GUI is no longer in the event loop.

Whatever it is you want to do after exec() it is likely you would either put it in a QThread or in a signal handler (which you would connect, for example, to a "Go!" button; you would connect a "Cancel" button to a handler that closes the app window).

You can put code after exec() but it would be rather unconventional: if anything goes wrong it is unlikely that user can see the problem since the GUI is no longer visible, a GUI app doesn't usually have a console terminal open where the error might be seen, there will not typically be a console for a GUI app (ie you will run the app via pythonw.exe instead of python.exe), or you have to open a new window and exec() again in order to show an error message and wait till user clicks ok, destroy message window in ok handler so app.exec() once again returns.


In addition to the previous answer, not every time when all windows are closed does the GUI event loop, run by app.exec_(), stop. If you want to terminate it manually you can use app.quit() inside any of the event handlers. It stops GUI event loop and launches your code after app.exec_().

First answer is a lot of words about nothing.


A dirty trick to remove blocking would be to abuse mathplot lib:

import matplotlib
import matplotlib as mpl

import matplotlib.cbook as cbook
import matplotlib.collections as mcol
import matplotlib.patches as mpatches
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import matplotlib.cm as cm       # colors 
from   mpl_toolkits.mplot3d import Axes3D   # imports options for 3-D plotting
from   matplotlib.backends.backend_pdf import PdfPages

from PyQt5 import QtWidgets, uic
# ============================================================== 
if not QtWidgets.QApplication.instance():
    app = QtWidgets.QApplication(sys.argv)
else:
    app = QtWidgets.QApplication.instance() 
#endelse

MainWindow =  QtWidgets.QMainWindow()
MainWindow=uic.loadUi('E:\Python\Python_lib\MyGui.ui',MainWindow)
MainWindow.show()

# There are two ways to start the gui, and i.e. it looping 
# The correct way if to use app.exec_(), which 
# blocks the command line :


#d=app.exec_()

# However, this will block the command line making 
# We can misuse mathplot lib creating a Figure instead
# which seems to start the Gui loop without blocking the command line: 

ImageFig = Figure((3,4))
ImagePanel = FigureCanvas(ImageFig)
ImagePanel.draw()