If you're following a PyQt5 tutorial and running your code in Spyder, you may have hit an annoying problem: the console freezes as soon as your window appears, clicking the close button ("x") doesn't work, and you're forced to restart the kernel. This is a well-known issue with how Spyder handles Qt event loops, and the fix is straightforward.
Why does this happen?
Spyder itself is built with PyQt5. It runs its own Qt event loop behind the scenes to power its interface. When you launch a second PyQt5 application from within Spyder — your application — the two event loops can conflict with each other, causing the console to lock up and your window to become unresponsive.
The typical code that triggers this looks something like:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
app = QApplication(sys.argv)
window = QMainWindow()
window.show()
app.exec()
Running this in Spyder can cause the IDE to hang because app.exec() starts a blocking event loop that clashes with Spyder's own loop. If you're just getting started with PyQt5, see our tutorial on creating your first PyQt window for the basics of how QApplication and the event loop work.
The fix: change Spyder's graphics backend
Spyder has a built-in setting that lets it share its own Qt event loop with your application. When this is enabled, you don't need to create your own QApplication or call app.exec() — Spyder takes care of it for you.
Here's how to enable it:
- In Spyder, go to Tools → Preferences (or Python → Preferences on macOS).
- Select IPython console from the left-hand panel.
- Click on the Graphics tab.
- Under Graphics backend, change the dropdown to Qt5.
- Click OK and restart the kernel (go to Consoles → Restart kernel, or press the restart button in the console toolbar).
After doing this, Spyder's IPython console will integrate with the Qt event loop automatically.
Adjusting your code for Spyder
With the Qt5 backend enabled, you'll want to modify your code slightly so it works both inside Spyder and as a standalone script. The main change is to check whether a QApplication instance already exists before creating a new one:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle("My Window")
window.show()
app.exec()
QApplication.instance() returns the existing application object if one is already running (which it will be inside Spyder with the Qt5 backend). If there isn't one — for example, when you run the script from a terminal — it creates a new one as usual.
This pattern means your script will work correctly in both environments.
Alternative: run your scripts externally
If you'd rather not change Spyder's settings, another option is to run your PyQt5 scripts in an external terminal instead of Spyder's built-in console.
- Go to Run → Configuration per file (or press Ctrl+F6).
- Under Console, select Execute in an external system terminal.
- Click OK and run the script.
Your PyQt5 application will open in a separate process, completely independent of Spyder's event loop. This avoids the conflict entirely and behaves the same as running python your_script.py from a terminal.
You might also consider using a different IDE altogether. VS Code and PyCharm are both popular alternatives that don't share a Qt event loop with your application, so they avoid this issue entirely.
Summary
The freezing issue happens because Spyder and your PyQt5 application both try to run their own Qt event loops. You can fix it by either:
- Setting Spyder's graphics backend to Qt5, which lets Spyder manage the event loop for you.
- Running your script in an external terminal, which keeps the two processes separate.
Both approaches work well. The graphics backend approach is convenient for quick experimentation in the console, while the external terminal approach keeps your code identical to what you'd run outside of Spyder. Pick whichever fits your workflow best.
If you're considering upgrading to PyQt6 or PySide6 for your projects, take a look at our comparison of PyQt6 vs PySide6 to help you decide which is right for you.
PyQt/PySide 1:1 Coaching with Martin Fitzpatrick
Save yourself time and frustration. Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.