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()
I wants to build some GUI for retrieving and displaying some data in real time. So I though of embedding a matplotlib figure in a pyqt5 GUI, and followed this example here (https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html). However, there will be some resource for my application that require a safe destruction at exit. So I tried to overwrite the closeEvent() function of MyMplCanvas with
def closeEvent(self,ce):
print('closeEvent')
super().closeEvent(ce)
But it does not seem to show up when I run the program. Is this expected or is there anything wrong with the program? If this is not the proper way to do so, what is the right way to do some clean-up during the destruction of a QWidget?
Thanks a lot!
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 !
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_())
I've been trying for hours to get this simple script working, but nothing I do seems to help. It's a slight modification of the most basic animated plot sample code from the Matplotlib website, that should just show a few frames of noise (I have the same issue with the unmodified code from their website BTW).
On my computer with the TkAgg backend I get about 20 frames (out of 60) before the plot window freezes. With Qt4Agg I just get a frozen, black window and no frames at all are plotted. I've tried multiple combinations of different NumPy, PyQt, Python and Matplotlib versions, but always get the same result.
Please let me know if this works for you or if anything looks wrong. I'm pretty sure this did work in the past, so I'm thinking it may be a Windows issue or something related to ion().
FYI I'm using Windows 7 (32 bit) and I've tested with Python 2.6/2.7, MPL 1.0.0/0.9.9.8, PyQt 4.6/4.7, Numpy 1.4/1.5b.
import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
from pylab import *
import time
ion()
hold(False)
# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)
for i in range(60):
print 'frame:', i
d = randn(10)
line.set_ydata(d)
draw()
time.sleep(10e-3)
This simpler version also freezes after the first couple frames:
from pylab import *
ion()
hold(False)
for i in range(40):
plot(randn(10))
draw()
show()
Thanks!
EDIT: These people seem to be having the same or a similar problem as me:
mail-archive.com/matplotlib-users#lists.sourceforge.net/msg10844.html
stackoverflow.com/questions/2604119/matplotlib-pyplot-pylab-not-updating-figure-while-isinteractive-using-ipython
mail-archive.com/matplotlib-users#lists.sourceforge.net/msg01283.html
Doesn't look like any of them were able to fix it either :(
Typically, GUI frameworks need to 'own' the main loop of the program. Sitting in a tight loop with sleeps to delay iterations will usually 'break' GUI applications (your problem description is consistent with typical breakage along these lines). It's possible that the matplotlib devs have implemented some behind the scenes logic to pevent these lockups from happening for certain toolkits but restructuring your program slightly should eliminate any chance of mainloop ownership being the problem (which is very likely I think). The matplotlib animation wiki also suggests using native event loops for anything nontrivial (probably for this reason)
Rather than sitting in a loop with sleeps, I suggest that, instead, you use the GUI toolkit to schedule a function call after a certain delay.
def update_function():
# do frame calculation here
refresh_timer = QtCore.QTimer()
QtCore.QObject.connect( refresh_timer, QtCore.SIGNAL('timeout()'), update_function )
refresh_timer.start( 1.0 / 30 ) # have update_function called at 30Hz
Looking at the matplotlib documentation suggests that it may be possible to use their API natively but I couldn't find any good examples using just a quick search.
When you say freezes after the first couple of frames do you mean 2 or 3, or say, 40 or 60, as those are the upper limits of your loop?
If you want the animation to continue indefinitely you need something like
while True:
d = randn(10)
line.set_ydata(d)
draw()
time.sleep(10e-3)
But you'll have to force quit your program.
Generally you can't use show() and draw() like this. As the Posts are suggesting, you need a small GUI loop, just look at the Animations examples on the Matplotlib page.
After many hours fighting with this same issue I think I've found the answer: To do these simple animations with matplotlib you can only use the GTKAgg backend. This is stated as a passing remark in the scipy cookbook, but I think it should be stressed more clearly. When I use it, I can run your animations until the end without freezes or any other problem.
Beware that to use this backend you need to install PyGTK. I don't know what else you need on Windows (because I'm on Linux) but that seems the minimum. Besides, if you want to use it by default you have to add this line to your matplotlibrc (on Linux placed on ~/.matplotlib/matplotlibrc):
backend : GTKAgg
To use the other backends you need to follow the official matplotlib examples, but that means you have to build a mini-gui application just to run a simple animation, and I find that quite awful!
I was struggling with this same problem for quite a while. I would recommend taking a look at this example: http://matplotlib.sourceforge.net/examples/animation/strip_chart_demo.html
I thought I was following this example exactly, but it wasn't working. It would only run the "update" function one time. Turns out the only difference in my code was that the animation.FuncAnimation() was not assigned to a variable. As soon as I assigned the return value of animation.FuncAnimation() to a value, everything worked.
I was having (I think) the same trouble, where the window would freeze if I took the focus off it or tried to drag it around, using Python 2.7 on Windows 7 with Matplotlib 1.3, and TKAgg backend. I had a call to time.sleep(1) in my main while loop, and when I replaced that with plt.pause(1), that fixed the problem. So, try and use matplotlib's pause function rather than time module sleep function, it worked for me.
calling time.sleep() or plt.pause() causes flicker on the graph window when using blitting, but I got good results by simply calling the event loop explicitely :
fig.canvas.blit() # or draw()
fig.canvas.start_event_loop(0.001) #1 ms seems enough
greetings from the future.
Here's how you'd do it in python 3:
import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
import matplotlib.pylab as plt
import time
# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)
for i in range(60):
print('frame:', i)
d = randn(10)
line.set_ydata(d)
draw()
#replace time.sleep() with plt.pause()
plt.pause(0.5)
I got rid of the call to ion() and hold(False). I also replaced time.sleep with plt.pause