##// END OF EJS Templates
Add two examples of GUI applications that can summon Qt consoles....
Fernando Perez -
Show More
@@ -0,0 +1,68 b''
1 #-----------------------------------------------------------------------------
2 # Imports
3 #-----------------------------------------------------------------------------
4
5 import subprocess
6 import sys
7
8 from IPython.zmq.ipkernel import IPKernelApp
9
10 #-----------------------------------------------------------------------------
11 # Functions and classes
12 #-----------------------------------------------------------------------------
13 def pylab_kernel(gui):
14 """Launch and return an IPython kernel with pylab support for the desired gui
15 """
16 kernel = IPKernelApp()
17 # FIXME: we're hardcoding the heartbeat port b/c of a bug in IPython 0.11
18 # that will set it to 0 if not specified. Once this is fixed, the --hb
19 # parameter can be omitted and all ports will be automatic
20 kernel.initialize(['python', '--pylab=%s' % gui, '--hb=19999',
21 #'--log-level=10'
22 ])
23 return kernel
24
25
26 def qtconsole_cmd(kernel):
27 """Compute the command to connect a qt console to an already running kernel
28 """
29 ports = ['--%s=%d' % (name, port) for name, port in kernel.ports.items()]
30 return ['ipython', 'qtconsole', '--existing'] + ports
31
32
33 class InternalIPKernel(object):
34
35 def init_ipkernel(self, backend):
36 # Start IPython kernel with GUI event loop and pylab support
37 self.ipkernel = pylab_kernel(backend)
38 # To create and track active qt consoles
39 self._qtconsole_cmd = qtconsole_cmd(self.ipkernel)
40 self.consoles = []
41
42 # This application will also act on the shell user namespace
43 self.namespace = self.ipkernel.shell.user_ns
44 # Keys present at startup so we don't print the entire pylab/numpy
45 # namespace when the user clicks the 'namespace' button
46 self._init_keys = set(self.namespace.keys())
47
48 # Example: a variable that will be seen by the user in the shell, and
49 # that the GUI modifies (the 'Counter++' button increments it):
50 self.namespace['app_counter'] = 0
51 #self.namespace['ipkernel'] = self.ipkernel # dbg
52
53 def print_namespace(self, evt=None):
54 print "\n***Variables in User namespace***"
55 for k, v in self.namespace.iteritems():
56 if k not in self._init_keys and not k.startswith('_'):
57 print '%s -> %r' % (k, v)
58 sys.stdout.flush()
59
60 def new_qt_console(self, evt=None):
61 self.consoles.append(subprocess.Popen(self._qtconsole_cmd))
62
63 def count(self, evt=None):
64 self.namespace['app_counter'] += 1
65
66 def cleanup_consoles(self, evt=None):
67 for c in self.consoles:
68 c.kill()
@@ -0,0 +1,75 b''
1 #!/usr/bin/env python
2 """Example integrating an IPython kernel into a GUI App.
3
4 This trivial GUI application internally starts an IPython kernel, to which Qt
5 consoles can be connected either by the user at the command line or started
6 from the GUI itself, via a button. The GUI can also manipulate one variable in
7 the kernel's namespace, and print the namespace to the console.
8
9 Play with it by running the script and then opening one or more consoles, and
10 pushing the 'Counter++' and 'Namespace' buttons.
11
12 Upon exit, it should automatically close all consoles opened from the GUI.
13
14 Consoles attached separately from a terminal will not be terminated, though
15 they will notice that their kernel died.
16 """
17 #-----------------------------------------------------------------------------
18 # Imports
19 #-----------------------------------------------------------------------------
20
21 from PyQt4 import Qt
22
23 from internal_ipkernel import InternalIPKernel
24
25 #-----------------------------------------------------------------------------
26 # Functions and classes
27 #-----------------------------------------------------------------------------
28 class SimpleWindow(Qt.QWidget, InternalIPKernel):
29
30 def __init__(self, app):
31 Qt.QWidget.__init__(self)
32 self.app = app
33 self.add_widgets()
34 self.init_ipkernel('qt')
35
36 def add_widgets(self):
37 self.setGeometry(300, 300, 400, 70)
38 self.setWindowTitle('IPython in your app')
39
40 # Add simple buttons:
41 console = Qt.QPushButton('Qt Console', self)
42 console.setGeometry(10, 10, 100, 35)
43 self.connect(console, Qt.SIGNAL('clicked()'), self.new_qt_console)
44
45 namespace = Qt.QPushButton('Namespace', self)
46 namespace.setGeometry(120, 10, 100, 35)
47 self.connect(namespace, Qt.SIGNAL('clicked()'), self.print_namespace)
48
49 count = Qt.QPushButton('Count++', self)
50 count.setGeometry(230, 10, 80, 35)
51 self.connect(count, Qt.SIGNAL('clicked()'), self.count)
52
53 # Quit and cleanup
54 quit = Qt.QPushButton('Quit', self)
55 quit.setGeometry(320, 10, 60, 35)
56 self.connect(quit, Qt.SIGNAL('clicked()'), Qt.qApp, Qt.SLOT('quit()'))
57
58 self.app.connect(self.app, Qt.SIGNAL("lastWindowClosed()"),
59 self.app, Qt.SLOT("quit()"))
60
61 self.app.aboutToQuit.connect(self.cleanup_consoles)
62
63 #-----------------------------------------------------------------------------
64 # Main script
65 #-----------------------------------------------------------------------------
66
67 if __name__ == "__main__":
68 app = Qt.QApplication([])
69 # Create our window
70 win = SimpleWindow(app)
71 win.show()
72
73 # Very important, IPython-specific step: this gets GUI event loop
74 # integration going, and it replaces calling app.exec_()
75 win.ipkernel.start()
@@ -0,0 +1,119 b''
1 #!/usr/bin/env python
2 """Example integrating an IPython kernel into a GUI App.
3
4 This trivial GUI application internally starts an IPython kernel, to which Qt
5 consoles can be connected either by the user at the command line or started
6 from the GUI itself, via a button. The GUI can also manipulate one variable in
7 the kernel's namespace, and print the namespace to the console.
8
9 Play with it by running the script and then opening one or more consoles, and
10 pushing the 'Counter++' and 'Namespace' buttons.
11
12 Upon exit, it should automatically close all consoles opened from the GUI.
13
14 Consoles attached separately from a terminal will not be terminated, though
15 they will notice that their kernel died.
16
17 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
18 """
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22 import sys
23
24 import wx
25
26 from internal_ipkernel import InternalIPKernel
27
28 #-----------------------------------------------------------------------------
29 # Functions and classes
30 #-----------------------------------------------------------------------------
31
32 class MyFrame(wx.Frame, InternalIPKernel):
33 """
34 This is MyFrame. It just shows a few controls on a wxPanel,
35 and has a simple menu.
36 """
37
38 def __init__(self, parent, title):
39 wx.Frame.__init__(self, parent, -1, title,
40 pos=(150, 150), size=(350, 285))
41
42 # Create the menubar
43 menuBar = wx.MenuBar()
44
45 # and a menu
46 menu = wx.Menu()
47
48 # add an item to the menu, using \tKeyName automatically
49 # creates an accelerator, the third param is some help text
50 # that will show up in the statusbar
51 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
52
53 # bind the menu event to an event handler
54 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
55
56 # and put the menu on the menubar
57 menuBar.Append(menu, "&File")
58 self.SetMenuBar(menuBar)
59
60 self.CreateStatusBar()
61
62 # Now create the Panel to put the other controls on.
63 panel = wx.Panel(self)
64
65 # and a few controls
66 text = wx.StaticText(panel, -1, "Hello World!")
67 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
68 text.SetSize(text.GetBestSize())
69 qtconsole_btn = wx.Button(panel, -1, "Qt Console")
70 ns_btn = wx.Button(panel, -1, "Namespace")
71 count_btn = wx.Button(panel, -1, "Count++")
72 close_btn = wx.Button(panel, -1, "Quit")
73
74 # bind the button events to handlers
75 self.Bind(wx.EVT_BUTTON, self.new_qt_console, qtconsole_btn)
76 self.Bind(wx.EVT_BUTTON, self.print_namespace, ns_btn)
77 self.Bind(wx.EVT_BUTTON, self.count, count_btn)
78 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, close_btn)
79
80 # Use a sizer to layout the controls, stacked vertically and with
81 # a 10 pixel border around each
82 sizer = wx.BoxSizer(wx.VERTICAL)
83 for ctrl in [text, qtconsole_btn, ns_btn, count_btn, close_btn]:
84 sizer.Add(ctrl, 0, wx.ALL, 10)
85 panel.SetSizer(sizer)
86 panel.Layout()
87
88 # Start the IPython kernel with gui support
89 self.init_ipkernel('wx')
90
91 def OnTimeToClose(self, evt):
92 """Event handler for the button click."""
93 print "See ya later!"
94 sys.stdout.flush()
95 self.cleanup_consoles(evt)
96 self.Close()
97 # Not sure why, but our IPython kernel seems to prevent normal WX
98 # shutdown, so an explicit exit() call is needed.
99 sys.exit()
100
101
102 class MyApp(wx.App):
103 def OnInit(self):
104 frame = MyFrame(None, "Simple wxPython App")
105 self.SetTopWindow(frame)
106 frame.Show(True)
107 self.ipkernel = frame.ipkernel
108 return True
109
110 #-----------------------------------------------------------------------------
111 # Main script
112 #-----------------------------------------------------------------------------
113
114 if __name__ == '__main__':
115 app = MyApp(redirect=False, clearSigInt=False)
116
117 # Very important, IPython-specific step: this gets GUI event loop
118 # integration going, and it replaces calling app.MainLoop()
119 app.ipkernel.start()
General Comments 0
You need to be logged in to leave comments. Login now