Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add two examples of GUI applications that can summon Qt consoles.

These show how to instantiate a kernel inside a GUI app and then
connect Qt consoles to talk to it, providing interactive access to the
namespace of the GUI.
  • Loading branch information...
commit 8af09932f39a2e522801976310ad6a2cdc48a272 1 parent b63d2de
@fperez fperez authored
View
68 docs/examples/lib/internal_ipkernel.py
@@ -0,0 +1,68 @@
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import subprocess
+import sys
+
+from IPython.zmq.ipkernel import IPKernelApp
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+def pylab_kernel(gui):
+ """Launch and return an IPython kernel with pylab support for the desired gui
+ """
+ kernel = IPKernelApp()
+ # FIXME: we're hardcoding the heartbeat port b/c of a bug in IPython 0.11
+ # that will set it to 0 if not specified. Once this is fixed, the --hb
+ # parameter can be omitted and all ports will be automatic
+ kernel.initialize(['python', '--pylab=%s' % gui, '--hb=19999',
+ #'--log-level=10'
+ ])
+ return kernel
+
+
+def qtconsole_cmd(kernel):
+ """Compute the command to connect a qt console to an already running kernel
+ """
+ ports = ['--%s=%d' % (name, port) for name, port in kernel.ports.items()]
+ return ['ipython', 'qtconsole', '--existing'] + ports
+
+
+class InternalIPKernel(object):
+
+ def init_ipkernel(self, backend):
+ # Start IPython kernel with GUI event loop and pylab support
+ self.ipkernel = pylab_kernel(backend)
+ # To create and track active qt consoles
+ self._qtconsole_cmd = qtconsole_cmd(self.ipkernel)
+ self.consoles = []
+
+ # This application will also act on the shell user namespace
+ self.namespace = self.ipkernel.shell.user_ns
+ # Keys present at startup so we don't print the entire pylab/numpy
+ # namespace when the user clicks the 'namespace' button
+ self._init_keys = set(self.namespace.keys())
+
+ # Example: a variable that will be seen by the user in the shell, and
+ # that the GUI modifies (the 'Counter++' button increments it):
+ self.namespace['app_counter'] = 0
+ #self.namespace['ipkernel'] = self.ipkernel # dbg
+
+ def print_namespace(self, evt=None):
+ print "\n***Variables in User namespace***"
+ for k, v in self.namespace.iteritems():
+ if k not in self._init_keys and not k.startswith('_'):
+ print '%s -> %r' % (k, v)
+ sys.stdout.flush()
+
+ def new_qt_console(self, evt=None):
+ self.consoles.append(subprocess.Popen(self._qtconsole_cmd))
+
+ def count(self, evt=None):
+ self.namespace['app_counter'] += 1
+
+ def cleanup_consoles(self, evt=None):
+ for c in self.consoles:
+ c.kill()
View
75 docs/examples/lib/ipkernel_qtapp.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+"""Example integrating an IPython kernel into a GUI App.
+
+This trivial GUI application internally starts an IPython kernel, to which Qt
+consoles can be connected either by the user at the command line or started
+from the GUI itself, via a button. The GUI can also manipulate one variable in
+the kernel's namespace, and print the namespace to the console.
+
+Play with it by running the script and then opening one or more consoles, and
+pushing the 'Counter++' and 'Namespace' buttons.
+
+Upon exit, it should automatically close all consoles opened from the GUI.
+
+Consoles attached separately from a terminal will not be terminated, though
+they will notice that their kernel died.
+"""
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from PyQt4 import Qt
+
+from internal_ipkernel import InternalIPKernel
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+class SimpleWindow(Qt.QWidget, InternalIPKernel):
+
+ def __init__(self, app):
+ Qt.QWidget.__init__(self)
+ self.app = app
+ self.add_widgets()
+ self.init_ipkernel('qt')
+
+ def add_widgets(self):
+ self.setGeometry(300, 300, 400, 70)
+ self.setWindowTitle('IPython in your app')
+
+ # Add simple buttons:
+ console = Qt.QPushButton('Qt Console', self)
+ console.setGeometry(10, 10, 100, 35)
+ self.connect(console, Qt.SIGNAL('clicked()'), self.new_qt_console)
+
+ namespace = Qt.QPushButton('Namespace', self)
+ namespace.setGeometry(120, 10, 100, 35)
+ self.connect(namespace, Qt.SIGNAL('clicked()'), self.print_namespace)
+
+ count = Qt.QPushButton('Count++', self)
+ count.setGeometry(230, 10, 80, 35)
+ self.connect(count, Qt.SIGNAL('clicked()'), self.count)
+
+ # Quit and cleanup
+ quit = Qt.QPushButton('Quit', self)
+ quit.setGeometry(320, 10, 60, 35)
+ self.connect(quit, Qt.SIGNAL('clicked()'), Qt.qApp, Qt.SLOT('quit()'))
+
+ self.app.connect(self.app, Qt.SIGNAL("lastWindowClosed()"),
+ self.app, Qt.SLOT("quit()"))
+
+ self.app.aboutToQuit.connect(self.cleanup_consoles)
+
+#-----------------------------------------------------------------------------
+# Main script
+#-----------------------------------------------------------------------------
+
+if __name__ == "__main__":
+ app = Qt.QApplication([])
+ # Create our window
+ win = SimpleWindow(app)
+ win.show()
+
+ # Very important, IPython-specific step: this gets GUI event loop
+ # integration going, and it replaces calling app.exec_()
+ win.ipkernel.start()
View
119 docs/examples/lib/ipkernel_wxapp.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+"""Example integrating an IPython kernel into a GUI App.
+
+This trivial GUI application internally starts an IPython kernel, to which Qt
+consoles can be connected either by the user at the command line or started
+from the GUI itself, via a button. The GUI can also manipulate one variable in
+the kernel's namespace, and print the namespace to the console.
+
+Play with it by running the script and then opening one or more consoles, and
+pushing the 'Counter++' and 'Namespace' buttons.
+
+Upon exit, it should automatically close all consoles opened from the GUI.
+
+Consoles attached separately from a terminal will not be terminated, though
+they will notice that their kernel died.
+
+Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
+"""
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+import sys
+
+import wx
+
+from internal_ipkernel import InternalIPKernel
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+
+class MyFrame(wx.Frame, InternalIPKernel):
+ """
+ This is MyFrame. It just shows a few controls on a wxPanel,
+ and has a simple menu.
+ """
+
+ def __init__(self, parent, title):
+ wx.Frame.__init__(self, parent, -1, title,
+ pos=(150, 150), size=(350, 285))
+
+ # Create the menubar
+ menuBar = wx.MenuBar()
+
+ # and a menu
+ menu = wx.Menu()
+
+ # add an item to the menu, using \tKeyName automatically
+ # creates an accelerator, the third param is some help text
+ # that will show up in the statusbar
+ menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
+
+ # bind the menu event to an event handler
+ self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
+
+ # and put the menu on the menubar
+ menuBar.Append(menu, "&File")
+ self.SetMenuBar(menuBar)
+
+ self.CreateStatusBar()
+
+ # Now create the Panel to put the other controls on.
+ panel = wx.Panel(self)
+
+ # and a few controls
+ text = wx.StaticText(panel, -1, "Hello World!")
+ text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
+ text.SetSize(text.GetBestSize())
+ qtconsole_btn = wx.Button(panel, -1, "Qt Console")
+ ns_btn = wx.Button(panel, -1, "Namespace")
+ count_btn = wx.Button(panel, -1, "Count++")
+ close_btn = wx.Button(panel, -1, "Quit")
+
+ # bind the button events to handlers
+ self.Bind(wx.EVT_BUTTON, self.new_qt_console, qtconsole_btn)
+ self.Bind(wx.EVT_BUTTON, self.print_namespace, ns_btn)
+ self.Bind(wx.EVT_BUTTON, self.count, count_btn)
+ self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, close_btn)
+
+ # Use a sizer to layout the controls, stacked vertically and with
+ # a 10 pixel border around each
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ for ctrl in [text, qtconsole_btn, ns_btn, count_btn, close_btn]:
+ sizer.Add(ctrl, 0, wx.ALL, 10)
+ panel.SetSizer(sizer)
+ panel.Layout()
+
+ # Start the IPython kernel with gui support
+ self.init_ipkernel('wx')
+
+ def OnTimeToClose(self, evt):
+ """Event handler for the button click."""
+ print "See ya later!"
+ sys.stdout.flush()
+ self.cleanup_consoles(evt)
+ self.Close()
+ # Not sure why, but our IPython kernel seems to prevent normal WX
+ # shutdown, so an explicit exit() call is needed.
+ sys.exit()
+
+
+class MyApp(wx.App):
+ def OnInit(self):
+ frame = MyFrame(None, "Simple wxPython App")
+ self.SetTopWindow(frame)
+ frame.Show(True)
+ self.ipkernel = frame.ipkernel
+ return True
+
+#-----------------------------------------------------------------------------
+# Main script
+#-----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ app = MyApp(redirect=False, clearSigInt=False)
+
+ # Very important, IPython-specific step: this gets GUI event loop
+ # integration going, and it replaces calling app.MainLoop()
+ app.ipkernel.start()
Please sign in to comment.
Something went wrong with that request. Please try again.