Update PyQt widget through ipython/jupyter notebook cells

若如初见. 提交于 2019-12-09 19:00:25

问题


I have an annoying issue that I have not been able to solve for the past few months. Basically, I'm using jupyter/ipython notebook to call pyqt and display 3d geometric data. This is how I initialize the app into an object and after I add some polygons and points, I call show():

class Figure(object):
    '''
    Main API functions
    '''

    def __init__(self):
        print "... initializing canvas ..."
        self.app = QApplication(sys.argv)
        self.app.processEvents()
        ...

    def show(self):   #Show
        self.GUI = GLWindow(data)   
        self.app.exec_()

I'd like to continuously interact/update the widget through the notebook cells. But once I call the show() command in the jupyter notebook I can't run any more cells or update the widget as the notebook output gets queued (?) and locked out:

#Initialize figure object inside the notebook
fig = plb.figure()
...
fig.show()  #Locks out any further jupyter commands while widget on screen
fig.update() #Does not get executed until widget is closed

It seems the .show() function called through the notebook gives up control of the python kernel (?) but it's unclear how to get it back, and also how to then connect it to the widget being displayed.

Mouse and keyboards events do interact with the widget, but they use intrinsic functions like mouseMoveEvent() that are inside the widget code:

    class GLWindow(QtGui.QWidget):

        def __init__(self, fig, parent=None):
            QtGui.QWidget.__init__(self, parent)

            self.glWidget = GLWidget(fig, parent=self)
            ...

    class GLWidget(QtOpenGL.QGLWidget):

            def __init__(self, fig, parent=None):
                QtOpenGL.QGLWidget.__init__(self, parent)
                ...

            def mouseMoveEvent(self, event):
                buttons = event.buttons()
                modifiers = event.modifiers()
                dx = event.x() - self.lastPos.x()
                dy = event.y() - self.lastPos.y()
                ...

I've tried to follow related suggestions but I don't understand how to use connections or events outside of the widget.

Any help is appreciated, I've spent so many hours on trying to fix this it's embarrassing. Cat


回答1:


I found the solution with help from the jupyter forums. Apparently there's a runtime trick in the notebook that's described here that allows you to dynamically interact with the glwindow. Very happy to finally solve this...

https://github.com/ipython/ipython/blob/master/examples/IPython%20Kernel/gui/gui-qt.py

Here's the entire function, in case that example is deleted in the future:

#!/usr/bin/env python
"""Simple Qt4 example to manually test event loop integration.
This is meant to run tests manually in ipython as:

In [5]: %gui qt

In [6]: %run gui-qt.py

Ref: Modified from http://zetcode.com/tutorials/pyqt4/firstprograms/
"""

from PyQt4 import QtGui, QtCore

class SimpleWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 200, 80)
        self.setWindowTitle('Hello World')

        quit = QtGui.QPushButton('Close', self)
        quit.setGeometry(10, 10, 60, 35)

        self.connect(quit, QtCore.SIGNAL('clicked()'),
                     self, QtCore.SLOT('close()'))

if __name__ == '__main__':
    app = QtCore.QCoreApplication.instance()
    if app is None:
        app = QtGui.QApplication([])

    sw = SimpleWindow()
    sw.show()

    try:
        from IPython.lib.guisupport import start_event_loop_qt4
        start_event_loop_qt4(app)
    except ImportError:
        app.exec_()


来源:https://stackoverflow.com/questions/40063873/update-pyqt-widget-through-ipython-jupyter-notebook-cells

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!