0

Ich habe ein großes Python-Programm mit GUI basierend auf PyQt4 erstellt. Ich möchte, dass das Paket sowohl in einem IPython-Notizbuch (alte Installation mit Python 2.7 unter Windows) als auch in Jupyter-Notizbuch (Python 3.5 kürzlich mit Anaconda installiert) und als Python-Programm in der Befehlszeile ausgeführt wird. Ich habe Probleme beim Ausführen des Codes im Jupyter-Notizbuch (siehe unten).Warum verhält sich PyQt4 zwischen Jupyter und IPython-Notebook anders?

Mein Modul mymodule.py sieht wie folgt aus (extrem vereinfacht, etwa 10k Zeilen vor der Show aus vielen anderen Python-Dateien):

from PyQt4 import QtCore, QtGui 

class MyModule(object): 
    def __init__(self): 
     self.window = QtGui.QMainWindow() 
     self.window.show() 

Die typische Verwendung von Befehlszeile ist

python myscript.py 

mit der folgenden Datei myscript.py

from PyQt4 import QtCore, QtGui 
import mymodule 

m = mymodule.MyModule() 

APP = QtGui.QApplication.instance() 
APP.exec_() 

Das funktioniert gut. Ich verstehe, dass APP.exec() benötigt wird, um eine Art von EventLoop zu starten, die durch die Gui-Interaktionsereignisse funktioniert.

In einem IPython Notebook, in der Regel der Benutzer tut

import mymodule 
m = mymodule.MyModule() # opens the gui 
# this still leaves the console active to allow things like this: 
m.change_color("red") 

ich ohne Probleme laufen kann dies, wo ich understant dass IPython nimmt irgendwie Pflege der Ereignisschleife hinter der Szene.

Jetzt, die gleichen Befehle in Jupyter Notizbuch ausgeführt, öffnet sich ein Fenster, aber friert ein, bevor jede Benutzerinteraktion zugelassen wird. Ich glaube also, dass das Jupyter Notizbuch die Ereignisse nicht richtig behandelt, weil ich es nicht gesagt habe. Eine Möglichkeit, die ich gefunden habe, ist die Ausführung des Befehls %pylab vor dem Ausführen meines Codes. Ich stoße jedoch häufig auf damit zusammenhängende Probleme, zum Beispiel wenn ich %pylab und %matplotlib inline in direkter Folge vor dem Start meines Programms starte, führt das wieder zum Einfrieren, sobald ich meinen Code geladen habe (kurioserweise funktioniert die umgekehrte Reihenfolge der beiden magischen Befehle wieder) . Außerdem möchte ich den Benutzer meines Programms nicht dazu zwingen,% pylab in jedem neuen Notizbuch auszuführen, wenn es vermieden werden kann (auch weil ich glaube, dass dies eine Matlab-Installation erfordert, was für mein Programm nicht erforderlich ist).

Welchen Code muss ich in mymodule.py hinzufügen, um die Kompatibilität mit dem beschriebenen Benutzercode im Jupyter Notebook herzustellen? Kann jemand klarer erklären, wie IPython Notebook und Jupyter Notebook die QEventLoop/QApplication (oder was ist das wichtige Konzept hier) anders handhaben und wie die magischen Befehle damit umgehen? Ich habe deshalb Angst vor versteckten Fehlern in meinem Programm und möchte es so robust wie möglich machen, um die Benutzer nicht zu frustrieren.

Antwort

0

Hier ist eine funktionierende Lösung, die es ermöglicht, den Code auszuführen, ohne zwischen verschiedenen IPython/Jupyter-Versionen und 'rohem' Python zu unterscheiden. Meine __init__.py Datei enthält diesen Abschnitt am Anfang:

# enable IPython QtGui support if needed 
try: 
    from IPython import get_ipython 
    get_ipython().magic('gui qt') 
except BaseException as e: 
    # issued if code runs in bare Python 
    print('Could not enable IPython gui support: %s.' % e) 

# get QApplication instance 
from PyQt4 import QtCore, QtGui 
APP = QtGui.QApplication.instance() 
if APP is None: 
    print('Creating new QApplication instance "mymodule"') 
    APP = QtGui.QApplication(['mymodule']) 

Das Skript auf rohen Python läuft dann muss nur das:

import mymodule # imports the above code 
from PyQt4 import QtCore, QtGui 
if __name__ == '__main__': 
    QtGui.QApplication.instance().exec_() 

ich keinen Anwendungsfall gefunden, wo dies nicht funktioniert.

Verwandte Themen