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