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).
Related
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 have this code running on a PyQt window on windows:
try:
self.actorUser.findIdfFiles(pathToFolder)
msg = "Processando arquivos..."
self.processingLabel.setText(msg)
self.actorUser.runSimulation(pathToFolder, pathToEpw)
Inside the "runSimulation" code I start a subprocess using the method "call". This blocks my GUI and at the title of the window appears "Python stopping responding", but if I wait a little bit the subprocess finishes normally, and the label is finally changed. But what I want is that the label have is text really changed before the subprocess started. What can I do??
Qt (and most UI frameworks) don't update the display as soon as values are set, only when they are told to repaint.
What you need to do is add a call
QtGui.QApplication.processEvents()
before your long-running subprocess, to make it process all pending events.
Joe P 's answer is quite right.
But this method is change to
QtCore.QCoreApplication.processEvents()
in pyqt5
link: https://doc.qt.io/qt-5/qcoreapplication.html#processEvents
I am new to PyQT and I have just started learning about it through this video: https://www.youtube.com/watch?v=JBME1ZyHiP8
When I ran the code on my Ubuntu 14.04
import sys
from PyQt4 import QtGui # Always have these two imports
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window.setGeometry(50,50,500,300)
window.setWindowTitle("PyQt start")
window.show()
The window crated just flashes and closes down. How do I get the window
to stay so that I can interact with it? The code in the Youtube video
above demonstrated it on a Windows platform. Do I have to append anything Ubuntu specific to my code?
You aren't running the app, add this line to the end:
sys.exit(app.exec_())
From the relevant documentation:
int QApplication.exec_ ()
Enters the main event loop and waits until exit() is called, then returns the value that was set to exit() (which is 0 if exit() is called via quit()).
It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets.
Generally, no user interaction can take place before calling exec(). As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets call exec() to start a local event loop.
Ok here is my problem:
I want to create a PyQt4 Gui, which can be executed from a python console (tested with IDLE, Spyder Console and IPython Console) and then allows the user to change and view variables. After closing the app the user should be able to do further work with the variables in the console. But by closing the Gui the Kernel crashes and it is not possible to make any new input to the console.
I'm working with Python 2.7 and PyQt4. I am using the following code to start an close the application:
app=QtGui.QApplication(sys.argv)
MainApp=plottest()
MainApp.show()
sys.exit(app.exec_())
The easy solution here https://www.reddit.com/r/learnpython/comments/45h05k/solved_kernel_crashing_when_closing_gui_spyder/
only put
if __name__ == "__main__":
app=0 #This is the solution
app = QtGui.QApplication(sys.argv)
MainApp = Dice_Roller()
MainApp.show()
sys.exit(app.exec_())
What you need to do is:
Check that there isn't already a QApplication instance when trying to create a new one
Ensure that the QApplication object is deleted after it's been closed
(See simple IPython example raises exception on sys.exit())
# Check if there's a pre-existing QApplication instance
# If there is, use it. If there isn't, create a new one.
app = QtGui.QApplication.instance()
if not app:
app = QtGui.QApplication(sys.argv)
# Ensure that the app is deleted when we close it
app.aboutToQuit.connect(app.deleteLater)
# Execute the application
MainApp = plottest()
MainApp.show()
sys.exit(app.exec_())
Using this code you can rerun the application as many times as you want in IPython, or anywhere else. Every time you close your Qt application, the app object will be deleted in python.
I do not think you mean a kernel crash. Rather, I think you are talking about exiting the python console. This is caused by sys.exit(app.exec_()). For example try (for example in spyder) the following two codes:
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
widget.setWindowTitle('simple')
widget.show()
#sys.exit(app.exec_())
Here you should get an empty window and the python console will stay alive. The second one, where sys.exit(app.exec_()) is included, will exit the python console at the end and the window disappears:
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
widget.setWindowTitle('simple')
widget.show()
sys.exit(app.exec_())
I hope this helps.
I still don't know the issue and solution. None of the above worked for me. Currently I am coding in the spyder GUI and running on "cmd" by giving 'python' command. In CMD, it is working fine.
Update the solution if I get it. :-)
I think that your problem is that python console closes (its not kernel crash). For example in Spyder python icon on top of console window becomes grey and you cant do anything besides running another console.
Anyway, you should write app.exec() instead of sys.exit(app.exec()).
I believe sys.exit(app.exec()) passes exit code to console and closes it. Using simple app.exec() won't close console.
Concluding your code should look like:
app=QtGui.QApplication(sys.argv)
MainApp=plottest()
MainApp.show()
app.exec_()
I hope it helps.
hdunn's answer worked for me. Have deleted sys.exit() to avoid exiting the application totally. Performing the first step alone, as suggested by others in github forum, solved part of the problem but window never showed up, nor any error message. Performing the second part solved everything like a charm! Thans, hdunn!
# Check if there's a pre-existing QApplication instance
# If there is, use it. If there isn't, create a new one.
app = QtGui.QApplication.instance()
if not app:
app = QtGui.QApplication(sys.argv)
# Ensure that the app is deleted when we close it
app.aboutToQuit.connect(app.deleteLater)
# Execute the application
MainApp = plottest()
MainApp.show()
app.exec_()
If I'm trying to create a window or prompt a file dialog in the IDLE shell, nothing opens and the shell restarts. Is this a bug of some kind? I can't find anything about it. I'm new to PyQt (and Python in general) but had been able to get tutorials to work correctly. The last day or so, if I open IDLE and import PyQt4, QtGui, etc and then run something simple like QFileDialog.getOpenFileName, the shell just restarts. Any ideas?
You need to have a QApplication before you can use anything else from PyQt. Try rereading some of the tutorials you followed, or do a few more. This one for example.
In the first code sample of the above tutorial, pay special attention to these lines (I've included the comments from the tutorial for convenience):
app = QtGui.QApplication(sys.argv)
Every PyQt4 application must create an application object. The
application object is located in the QtGui module. The sys.argv
parameter is a list of arguments from the command line. Python scripts
can be run from the shell. It is a way, how we can control the startup
of our scripts.
and
sys.exit(app.exec_())
Finally, we enter the mainloop of the application. The event handling
starts from this point. The mainloop receives events from the window
system and dispatches them to the application widgets. The mainloop
ends, if we call the exit() method or the main widget is destroyed.
The sys.exit() method ensures a clean exit. The environment will be
informed, how the application ended.
The exec_() method has an underscore. It is because the exec is a
Python keyword. And thus, exec_() was used instead.
It appears you might have forgotten about these. Or maybe you haven't realized that this means that you normally can't use PyQt with a running event loop in the interactive shell. However, there is a trick for that, see here.