How to debug sporadic freezing of PyQt5 application after exiting? - python

I'm developing PyQt5 application of medium complexity. It has various widgets (both native and third-party) and Qthreads. It woks fine most of the time, but once in about 5 times the application hangs in the background after I exit it.
Here is how I define closeEvent:
def closeEvent(self, event):
qApp.quit()
And I also have defined a quit_action and connected it to the qApp.quit() like this:
self.quit_action.triggered.connect(qApp.quit)
I launch the PyQt5 application the standard way:
app = QApplication([])
window = GUIWindow()
window.show()
sys.exit(app.exec())
I have no idea how to debug such strange error. It happens only once in a few times and I can't reproduce the error.
I run the application in the console:
python main.py
and usually I can close the application without a problem. But once in a few times after I close the application (either by clicking on "x" button of the window or by triggering the quit_action in the menu) the window disappears and the process hangs in the background. I have to press "Ctlr+Z" and then kill the process.
What is the strategy to debug such strange error? How can find what exactly causes the freezing of the application?

This kind of bugs are hard to isolate. It looks like my particular bug emerges as a result of combination of several widgets of the app and it's hard to even provide a minimal working example that reproduces the error. Not to mention the error only happens once in a few runs.
It looks like I've found the main culprit for the bug by inspecting the hanging process through the gdb (see the question from stackoverflow Is there a way to attach a debugger to a multi-threaded Python process?).
When my application has frozen again - I attached to the process via the gdb, investigated threads and found the problematic thread.
EDIT: A temporary solution to make PyQt application close even when qApp.quit() doesn't help:
def closeEvent(self, event):
qApp.quit()
sys.exit()

Related

PYQT Display stops displaying changes periodically, fixes when changing element

I am having a small issue with PYQT that I cannot seem to find an answer for. I have made several apps using PYQT that do a multitude of functions but they all seem to have this one similar issue. When I leave my machine (windows 10) idle for a bit (not moving mouse/keyboard), the display will appear to 'freeze' but it is not actual frozen, just the display. The way to fix this is to change ANY element (increase spinbox value, minimize/maximize screen, etc).
This is particularly a problem with a video app I am working on where a camera is displaying video and suddenly it looks like the app is frozen until I 'fix' it. I am not sure if its a PYQT thing or perhaps windows itself. I will post relevant code below:
I can post more as needed but this is how I start my app:
app = QtWidgets.QApplication(sys.argv)
window = Ui()
widget = QtWidgets.QStackedWidget()
widget.addWidget(window)
widget.showMaximized()
app.exec_()
window.stop_threads()
cv2.destroyAllWindows()

Tkinter Toplevel window and multiple workspaces - place window in originating linux workspace

I run this on Debian Gnome, but I think this is relevant for most UNIX distributions and interfaces:
from time import sleep
from Tkinter import Tk,Toplevel
tk=Tk()
def run():
sleep(3)
Toplevel(tk)
run()
In Gnome, running this and switching a workspace will cause the Toplevel window to appear in your current workspace, instead of the one that actually runs the command. Is there a way to fix this so the new window appears where the command runs? If this is a Gnome specific thing let me know and I'll amend the question and tags.
To be clear: I have an app that can pop these windows up on it's own while working - and I'm doing other things. The sleep in the above is there to emulate that.
This makes sense it would work this way, but I'm wondering if there is any easy bypass? I have an application using Toplevels as "patience, running" windows, and it's annoying when they appear in different workspaces.

How to imbricate a QApplication inside a main QApplication

I'm currently working on a GUI interface that runs a GNU Radio script rendering some Qt windows (plotting real time histogramm, waterfall graph, or other nice gui...). I control its parameters and launch it from my first main windows. I'd like to integrate the QApp created by launching the GNU Radio script inside a widget of my first main windows (which is another QApp).
I already tried to run a second QApp in the same time of my first one, for some reasons, I get errors like QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread.
I did not work around this error because a nicer idea would be to have a kind of container whom I would give a PyQt4.QtGui.QApplication object to make him execute and display it without creating a second windows.
Does that kind of container exist ?
Thanks a lot !

PyQt4 application on Windows is crashing on exit

I am writting a desktop application with PyQt4 and all of the sudden it started to crash on exit.
I reviewed all of my code to make sure I wasn't doing anything funny to make it crash and I don't think there's anything wrong with the code.
I have seen some complaints about this before but it was related to a previous version and people advised to upgrade PyQt4 to the latest version and so I did, but that didn't help with the crashing problem.
So I ask, is there anything that can lead to this behavior with PyQt4, do I need to do some kind on termination procedure to cleanup Qt or anything else I am missing?
I had the same problem with a simple hello world application (QDialog with 20 labels). Weirdly the problem disappears with 10 labels.
I solved by forcing exit as follows:
def closeEvent(self, event):
exit()
This happens on Windows with PyQt v4.10.3 for Python v2.7 (x32) on VirtualBox.
A debugger will only tell us what we already know: The application crashes on exit.
You probably need to set an active window which, when closed, will result in deterministic garbage collection and a clean application exit. There are more proper ways to do this, but the simpl;e example below should require minimum code changes, and is based on a dialog application that I wrote and works fine.
#The application
app = QtGui.QApplication(sys.argv)
#The main window
MainWindow = QtGui.QMainWindow()
app.setActiveWindow(MainWindow) #<---- This is what's probably missing
#the ui
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
#start the application's exec loop, return the exit code to the OS
exit(app.exec_())

Execute Python code from within PyQt event loop

I am testing a gui built using PyQt and I would like the ability to interact with the gui using python code that is executed after the PyQt event loop starts (app.exec_()). Another way of saying this is I would like the call to app.exec_ to return immediately as if the gui were modeless, followed by further python code which interacts with the gui.
I found this example of running the PyQt loop in a thread but don't want to do something so unconventional. Is there any way to get the PyQt message loop to continue processing messages while also executing python code in the main thread after exec_ has been called?
One option here is to use a QtCore.QTimer.singleShot() call to start your python code after calling `exec_()'.
For example:
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
# Setup the GUI.
gui = MyGui()
gui.showMainWindow()
# Post a call to your python code.
QtCore.QTimer.singleShot(1000, somePythonFunction)
sys.exit(app.exec_())
This will execute the function somePythonFunction() after 1 second. You can set the time to zero to have the function added immediately queued for execution.
As a possible easy answer, try not calling app.exec_() in your script and running your PyQt program using python -i My_PyQt_app.py.
For example:
## My_PyQt_app.py
import sys
from PyQt5.QtWidgets import QApplication, QWidget
app = QApplication(sys.argv)
window = QWidget()
window.show()
# Don't start the event loop as you would do normally!
# app.exec_()
Doing this should allow you to run the GUI through the terminal and interact with it in the command line.
I got it. I can execute the test script line-by-line from the main thread using exec and then run the gui from a worker thread.
Not exactly sure what you wanna do. Are you looking for something like Py(known as PyCrust) for PyQt?
The easiest way is to use IPython:
ipython --gui=qt4
See ipython --help or the online documentation for more options (e.g. gtk, tk, etc).

Categories

Resources