closing a pyqt widget in ipython notebook without using sys.exit() - python

I am trying to run through some pyqt5 tutorials in the ipython notebook, but have an issue where every second time I run a code block the kernal undergoes a forced restart. Here is the smallest code which causes the problem:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
I am running the Ipython3 notebook and python 3, as well as pyqt5, and using Ubuntu 14.04. It should be noted that this problem does not occur when running this same code via a script in terminal.
Some other unrelated questions have suggested that my problem could be due to sys.exit() messing with the instance of python(I hope that is the correct term) instead of just closing my pyqt application. This happens the first time I run the code, so that the second time it runs the kernel is forced to restart. Is this the problem? and if so how do I work around this?
If more info is required, please ask.

I tried out Taar's solution but still got a dead kernel after calling the cell with main more than twice.The problem is creating multiple Qapplications, this crashes the notebook.
There is multiple solutions I found, but to just being able to run a qt application use the following in the first cell:
%gui qt
from PyQt5.QtWidgets import QApplication, QWidget
and in the second cell:
if __name__ == '__main__':
w = QWidget()
w.setWindowTitle('Simple')
w.show()
You can call the second cell as many times as you want and it will work. the magic line %gui qt opens a QApplication for your notebook.
If you need more control (like being able to exit() it) there is various solutions that amount to checking if there is a Qapplication instance open. Here is an example:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5 import QtCore
second cell:
if __name__ == '__main__':
app = QtCore.QCoreApplication.instance()
if app is None:
app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle('Simple')
w.show()
app.exec_()
This method does require closing the window before rerunning it (else they will be queued up: run 3x without closing the window, now you need to close the window 3x in a row). It will at least get you started with a properly loaded screen upon executing the cell. (anyone feel welcome to correct this example).
Some references for the second example: here, and here. But I don't know enough about how the qt gui interacts with the notebook to solve any problem with the above example.

Related

Getting unittest PySide and Maya on commandline to work

I have a Maya environment with a PySide window which gets generated on the fly with whatever is in that Maya scene. I'm trying to now take that to command-line and make unittests out of it.
I have everything working, minus one problem.
Most PyQt/PySide unittest documentation state to create a QApplication like this:
app = QApplication(sys.argv)
win = SomeWindow()
sys.exit(app.exec_())
This doesn't work because there's already a QApplication instance, built from Maya.
RuntimeError: A QApplication instance already exists.
Excluding these steps though yields this error and the tests fail:
QWidget: Cannot create a QWidget when no GUI is being used
I know that there's a QApplication instance in the scene, because this command yields a QApplication instance:
QApplication.instance()
So how do I associate the GUI that I want to create with that instance? You can't exec_() Maya's running QApplication so I'm not sure how to get my GUI to see the QApplication.
_
Found the solution. The issue was that I wasn't holding a global reference to the same instance across all of my tests (multiple Maya files were being created/destroyed over and over).
So somewhere at the top of the file, you just write
APP = None
Then in each test, import another file that keeps a link to that QApplication instance as a singleton and set APP equal to it

Using WinPython; console window closes after running a GUI script.py

this is my first question, but needless to say I've been lurking here all the time.
Currently started converting my code to a GUI application using Qt4. Running WinPython-64bit-3.4.4.3. I've registered the version and it seems that it successfully added the necessary PATH lines.
Now I wanted to make my GUI app run just by double-clicking on the specific specific python script (let's call it main.py). This works like a charm, problem is that when I close the GUI window, the console window disappears also. I really want to make it stay, especially when there's a critical error appears that I did not caught - so that I can see python console output - where the problem was.
The code is super simple:
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If I add a forced error to the code (some random bs) like w.sss() the console window will just flash and disappear.
How do I make it stay? Can you guys advise here?

Cannot run matplotlib and pyqt4 at the same time

I am running some code using PyQt4, and I would like to plot a figure using its data. But when I try to do that, it will report
QPixmap: Must construct a QGuiApplication before a QPixmap
Below is the code:
from PyQt4 import QtCore
import sys
import matplotlib.pyplot as plt
import numpy as np
def run():
#here is some code, I delete them since they are useless for this question
return data1 #data1 is a list with 30 elements
app = QtCore.QCoreApplication(sys.argv)
client.finished.connect(app.quit)
QtCore.QTimer().singleShot(0,lambda:client.timed_range_stream(5000))
app.exec_()
fig = plt.figure()
ax1 = fig.add_subplot(111)
data2 = run()
datalen = np.linspace(0,10,len(data2))
ax1.plot(datalen,data2,lw = 2)
plt.show()
Since the matplotlib is using pyqt4 as backend, I am so confused why this error happened. It should create a QGuiApplication automatically. I mean whether I use pyqt4 before or not, the code below 'app.exec_()' should create a QGuiApplication automatically. Please point out if I am wrong.
Really appreciate your help! Please give me some advice.
The complaint by PyQt is that you are not running a Gui EventLoop. app.exec_() sure starts an event loop, but that depends on what app is. In your case its QCoreApplication object. How do you expect it to start a Gui EventLoop? It's like buying a saucepan and expecting it to cook pizza.
matplotlib is based on PyQt for sure. I'm sure you can use it in console only applications as well. Hence PyQt will not be able to tell if you want a gui or a console app.
QCoreApplication is used when you are writing a console-based application. Fewer events and processes to manage. If you want to show a window, even a simple one, it takes much more work. And the beast to handle that extra work in QGuiApplication
Now to the Qt version. You are using PyQt4, but the complaint says you need to create a QGuiApplication. However, there is no QGuiApplication or any reference to it in Qt4/PyQt4. This leads me to believe that, your matplotlib copy might be using PyQt5, or PyQt5 dependency comes in from some obscure source, I'm not sure. Check the details of the PyQt version used.
If you are using PyQt4 add from PyQt4 import QtGui in the beginning.
Then change the app = QtCore.QCoreApplication(...) to app = QtGui.QApplication(...).
In case of PyQt5 add from PyQt5 import QtGui, QtWidgets in the beginning.
Then change the app = QtCore.QCoreApplication(...) to app = QtWidgets.QApplication(...).
That'll solve your problem.
PS: Remember, you cannot mix PyQt4 and PyQt5.

Python Kernel crashes after closing an PyQt4 Gui Application

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_()

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