##// END OF EJS Templates
Make gui support code and examples uniform and all working correctly....
Fernando Perez -
Show More
@@ -1,339 +1,345 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # coding: utf-8
2 # coding: utf-8
3 """
3 """
4 Inputhook management for GUI event loop integration.
4 Inputhook management for GUI event loop integration.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import ctypes
18 import ctypes
19 import sys
19 import sys
20 import warnings
20 import warnings
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Constants
23 # Constants
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 # Constants for identifying the GUI toolkits.
26 # Constants for identifying the GUI toolkits.
27 GUI_WX = 'wx'
27 GUI_WX = 'wx'
28 GUI_QT = 'qt'
28 GUI_QT = 'qt'
29 GUI_QT4 = 'qt4'
29 GUI_QT4 = 'qt4'
30 GUI_GTK = 'gtk'
30 GUI_GTK = 'gtk'
31 GUI_TK = 'tk'
31 GUI_TK = 'tk'
32 GUI_OSX = 'osx'
32 GUI_OSX = 'osx'
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Utility classes
35 # Utility classes
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Main InputHookManager class
40 # Main InputHookManager class
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 class InputHookManager(object):
44 class InputHookManager(object):
45 """Manage PyOS_InputHook for different GUI toolkits.
45 """Manage PyOS_InputHook for different GUI toolkits.
46
46
47 This class installs various hooks under ``PyOSInputHook`` to handle
47 This class installs various hooks under ``PyOSInputHook`` to handle
48 GUI event loop integration.
48 GUI event loop integration.
49 """
49 """
50
50
51 def __init__(self):
51 def __init__(self):
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
53 self._apps = {}
53 self._apps = {}
54 self._reset()
54 self._reset()
55
55
56 def _reset(self):
56 def _reset(self):
57 self._callback_pyfunctype = None
57 self._callback_pyfunctype = None
58 self._callback = None
58 self._callback = None
59 self._installed = False
59 self._installed = False
60 self._current_gui = None
60 self._current_gui = None
61
61
62 def get_pyos_inputhook(self):
62 def get_pyos_inputhook(self):
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
65
65
66 def get_pyos_inputhook_as_func(self):
66 def get_pyos_inputhook_as_func(self):
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
69
69
70 def set_inputhook(self, callback):
70 def set_inputhook(self, callback):
71 """Set PyOS_InputHook to callback and return the previous one."""
71 """Set PyOS_InputHook to callback and return the previous one."""
72 self._callback = callback
72 self._callback = callback
73 self._callback_pyfunctype = self.PYFUNC(callback)
73 self._callback_pyfunctype = self.PYFUNC(callback)
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
75 original = self.get_pyos_inputhook_as_func()
75 original = self.get_pyos_inputhook_as_func()
76 pyos_inputhook_ptr.value = \
76 pyos_inputhook_ptr.value = \
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
78 self._installed = True
78 self._installed = True
79 return original
79 return original
80
80
81 def clear_inputhook(self, app=None):
81 def clear_inputhook(self, app=None):
82 """Set PyOS_InputHook to NULL and return the previous one.
82 """Set PyOS_InputHook to NULL and return the previous one.
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 app : optional, ignored
86 app : optional, ignored
87 This parameter is allowed only so that clear_inputhook() can be
87 This parameter is allowed only so that clear_inputhook() can be
88 called with a similar interface as all the ``enable_*`` methods. But
88 called with a similar interface as all the ``enable_*`` methods. But
89 the actual value of the parameter is ignored. This uniform interface
89 the actual value of the parameter is ignored. This uniform interface
90 makes it easier to have user-level entry points in the main IPython
90 makes it easier to have user-level entry points in the main IPython
91 app like :meth:`enable_gui`."""
91 app like :meth:`enable_gui`."""
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
93 original = self.get_pyos_inputhook_as_func()
93 original = self.get_pyos_inputhook_as_func()
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
95 self._reset()
95 self._reset()
96 return original
96 return original
97
97
98 def clear_app_refs(self, gui=None):
98 def clear_app_refs(self, gui=None):
99 """Clear IPython's internal reference to an application instance.
99 """Clear IPython's internal reference to an application instance.
100
100
101 Whenever we create an app for a user on qt4 or wx, we hold a
101 Whenever we create an app for a user on qt4 or wx, we hold a
102 reference to the app. This is needed because in some cases bad things
102 reference to the app. This is needed because in some cases bad things
103 can happen if a user doesn't hold a reference themselves. This
103 can happen if a user doesn't hold a reference themselves. This
104 method is provided to clear the references we are holding.
104 method is provided to clear the references we are holding.
105
105
106 Parameters
106 Parameters
107 ----------
107 ----------
108 gui : None or str
108 gui : None or str
109 If None, clear all app references. If ('wx', 'qt4') clear
109 If None, clear all app references. If ('wx', 'qt4') clear
110 the app for that toolkit. References are not held for gtk or tk
110 the app for that toolkit. References are not held for gtk or tk
111 as those toolkits don't have the notion of an app.
111 as those toolkits don't have the notion of an app.
112 """
112 """
113 if gui is None:
113 if gui is None:
114 self._apps = {}
114 self._apps = {}
115 elif self._apps.has_key(gui):
115 elif self._apps.has_key(gui):
116 del self._apps[gui]
116 del self._apps[gui]
117
117
118 def enable_wx(self):
118 def enable_wx(self, app=None):
119 """Enable event loop integration with wxPython.
119 """Enable event loop integration with wxPython.
120
120
121 Parameters
121 Parameters
122 ----------
122 ----------
123 app : bool
123 app : WX Application, optional.
124 Create a running application object or not.
124 Running application to use. If not given, we probe WX for an
125 existing application object, and create a new one if none is found.
125
126
126 Notes
127 Notes
127 -----
128 -----
128 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
129 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
129 the wxPython to integrate with terminal based applications like
130 the wxPython to integrate with terminal based applications like
130 IPython.
131 IPython.
131
132
132 If ``app`` is True, we create an :class:`wx.App` as follows::
133 If ``app`` is not given we probe for an existing one, and return it if
134 found. If no existing app is found, we create an :class:`wx.App` as
135 follows::
133
136
134 import wx
137 import wx
135 app = wx.App(redirect=False, clearSigInt=False)
138 app = wx.App(redirect=False, clearSigInt=False)
136
137 Both options this constructor are important for things to work
138 properly in an interactive context.
139
140 But, we first check to see if an application has already been
141 created. If so, we simply return that instance.
142 """
139 """
143 from IPython.lib.inputhookwx import inputhook_wx
140 from IPython.lib.inputhookwx import inputhook_wx
144 self.set_inputhook(inputhook_wx)
141 self.set_inputhook(inputhook_wx)
145 self._current_gui = GUI_WX
142 self._current_gui = GUI_WX
146 import wx
143 import wx
147 app = wx.GetApp()
144 if app is None:
145 app = wx.GetApp()
148 if app is None:
146 if app is None:
149 app = wx.App(redirect=False, clearSigInt=False)
147 app = wx.App(redirect=False, clearSigInt=False)
150 app._in_event_loop = True
148 app._in_event_loop = True
151 self._apps[GUI_WX] = app
149 self._apps[GUI_WX] = app
152 return app
150 return app
153
151
154 def disable_wx(self):
152 def disable_wx(self):
155 """Disable event loop integration with wxPython.
153 """Disable event loop integration with wxPython.
156
154
157 This merely sets PyOS_InputHook to NULL.
155 This merely sets PyOS_InputHook to NULL.
158 """
156 """
159 if self._apps.has_key(GUI_WX):
157 if self._apps.has_key(GUI_WX):
160 self._apps[GUI_WX]._in_event_loop = False
158 self._apps[GUI_WX]._in_event_loop = False
161 self.clear_inputhook()
159 self.clear_inputhook()
162
160
163 def enable_qt4(self):
161 def enable_qt4(self, app=None):
164 """Enable event loop integration with PyQt4.
162 """Enable event loop integration with PyQt4.
165
163
166 Parameters
164 Parameters
167 ----------
165 ----------
168 app : bool
166 app : Qt Application, optional.
169 Create a running application object or not.
167 Running application to use. If not given, we probe Qt for an
168 existing application object, and create a new one if none is found.
170
169
171 Notes
170 Notes
172 -----
171 -----
173 This methods sets the PyOS_InputHook for PyQt4, which allows
172 This methods sets the PyOS_InputHook for PyQt4, which allows
174 the PyQt4 to integrate with terminal based applications like
173 the PyQt4 to integrate with terminal based applications like
175 IPython.
174 IPython.
176
175
177 If ``app`` is True, we create an :class:`QApplication` as follows::
176 If ``app`` is not given we probe for an existing one, and return it if
177 found. If no existing app is found, we create an :class:`QApplication`
178 as follows::
178
179
179 from PyQt4 import QtCore
180 from PyQt4 import QtCore
180 app = QtGui.QApplication(sys.argv)
181 app = QtGui.QApplication(sys.argv)
181
182 But, we first check to see if an application has already been
183 created. If so, we simply return that instance.
184 """
182 """
185 from IPython.external.qt_for_kernel import QtCore, QtGui
183 from IPython.external.qt_for_kernel import QtCore, QtGui
186
184
187 if 'pyreadline' in sys.modules:
185 if 'pyreadline' in sys.modules:
188 # see IPython GitHub Issue #281 for more info on this issue
186 # see IPython GitHub Issue #281 for more info on this issue
189 # Similar intermittent behavior has been reported on OSX,
187 # Similar intermittent behavior has been reported on OSX,
190 # but not consistently reproducible
188 # but not consistently reproducible
191 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
189 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
192 in interactive input. If you do see this issue, we recommend using another GUI
190 in interactive input. If you do see this issue, we recommend using another GUI
193 toolkit if you can, or disable readline with the configuration option
191 toolkit if you can, or disable readline with the configuration option
194 'TerminalInteractiveShell.readline_use=False', specified in a config file or
192 'TerminalInteractiveShell.readline_use=False', specified in a config file or
195 at the command-line""",
193 at the command-line""",
196 RuntimeWarning)
194 RuntimeWarning)
197
195
198 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
196 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
199 # was set when QtCore was imported, but if it ever got removed,
197 # was set when QtCore was imported, but if it ever got removed,
200 # you couldn't reset it. For earlier versions we can
198 # you couldn't reset it. For earlier versions we can
201 # probably implement a ctypes version.
199 # probably implement a ctypes version.
202 try:
200 try:
203 QtCore.pyqtRestoreInputHook()
201 QtCore.pyqtRestoreInputHook()
204 except AttributeError:
202 except AttributeError:
205 pass
203 pass
206
204
207 self._current_gui = GUI_QT4
205 self._current_gui = GUI_QT4
208 app = QtCore.QCoreApplication.instance()
206 if app is None:
207 app = QtCore.QCoreApplication.instance()
209 if app is None:
208 if app is None:
210 app = QtGui.QApplication([" "])
209 app = QtGui.QApplication([" "])
211 app._in_event_loop = True
210 app._in_event_loop = True
212 self._apps[GUI_QT4] = app
211 self._apps[GUI_QT4] = app
213 return app
212 return app
214
213
215 def disable_qt4(self):
214 def disable_qt4(self):
216 """Disable event loop integration with PyQt4.
215 """Disable event loop integration with PyQt4.
217
216
218 This merely sets PyOS_InputHook to NULL.
217 This merely sets PyOS_InputHook to NULL.
219 """
218 """
220 if self._apps.has_key(GUI_QT4):
219 if self._apps.has_key(GUI_QT4):
221 self._apps[GUI_QT4]._in_event_loop = False
220 self._apps[GUI_QT4]._in_event_loop = False
222 self.clear_inputhook()
221 self.clear_inputhook()
223
222
224 def enable_gtk(self, app=False):
223 def enable_gtk(self, app=None):
225 """Enable event loop integration with PyGTK.
224 """Enable event loop integration with PyGTK.
226
225
227 Parameters
226 Parameters
228 ----------
227 ----------
229 app : bool
228 app : ignored
230 Create a running application object or not. Because gtk does't
229 Ignored, it's only a placeholder to keep the call signature of all
231 have an app class, this does nothing.
230 gui activation methods consistent, which simplifies the logic of
231 supporting magics.
232
232
233 Notes
233 Notes
234 -----
234 -----
235 This methods sets the PyOS_InputHook for PyGTK, which allows
235 This methods sets the PyOS_InputHook for PyGTK, which allows
236 the PyGTK to integrate with terminal based applications like
236 the PyGTK to integrate with terminal based applications like
237 IPython.
237 IPython.
238 """
238 """
239 import gtk
239 import gtk
240 try:
240 try:
241 gtk.set_interactive(True)
241 gtk.set_interactive(True)
242 self._current_gui = GUI_GTK
242 self._current_gui = GUI_GTK
243 except AttributeError:
243 except AttributeError:
244 # For older versions of gtk, use our own ctypes version
244 # For older versions of gtk, use our own ctypes version
245 from IPython.lib.inputhookgtk import inputhook_gtk
245 from IPython.lib.inputhookgtk import inputhook_gtk
246 self.set_inputhook(inputhook_gtk)
246 self.set_inputhook(inputhook_gtk)
247 self._current_gui = GUI_GTK
247 self._current_gui = GUI_GTK
248
248
249 def disable_gtk(self):
249 def disable_gtk(self):
250 """Disable event loop integration with PyGTK.
250 """Disable event loop integration with PyGTK.
251
251
252 This merely sets PyOS_InputHook to NULL.
252 This merely sets PyOS_InputHook to NULL.
253 """
253 """
254 self.clear_inputhook()
254 self.clear_inputhook()
255
255
256 def enable_tk(self, app=False):
256 def enable_tk(self, app=None):
257 """Enable event loop integration with Tk.
257 """Enable event loop integration with Tk.
258
258
259 Parameters
259 Parameters
260 ----------
260 ----------
261 app : bool
261 app : toplevel :class:`Tkinter.Tk` widget, optional.
262 Create a running application object or not.
262 Running application to use. If not given, we probe Qt for an
263 existing application object, and create a new one if none is found.
263
264
264 Notes
265 Notes
265 -----
266 -----
266 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
267 If you have already created a :class:`Tkinter.Tk` object, the only
268 thing done by this method is to register with the
269 :class:`InputHookManager`, since creating that object automatically
267 sets ``PyOS_InputHook``.
270 sets ``PyOS_InputHook``.
268 """
271 """
269 self._current_gui = GUI_TK
272 self._current_gui = GUI_TK
270 if app:
273 if app is None:
271 import Tkinter
274 import Tkinter
272 app = Tkinter.Tk()
275 app = Tkinter.Tk()
273 app.withdraw()
276 app.withdraw()
274 self._apps[GUI_TK] = app
277 self._apps[GUI_TK] = app
275 return app
278 return app
276
279
277 def disable_tk(self):
280 def disable_tk(self):
278 """Disable event loop integration with Tkinter.
281 """Disable event loop integration with Tkinter.
279
282
280 This merely sets PyOS_InputHook to NULL.
283 This merely sets PyOS_InputHook to NULL.
281 """
284 """
282 self.clear_inputhook()
285 self.clear_inputhook()
283
286
284 def current_gui(self):
287 def current_gui(self):
285 """Return a string indicating the currently active GUI or None."""
288 """Return a string indicating the currently active GUI or None."""
286 return self._current_gui
289 return self._current_gui
287
290
288 inputhook_manager = InputHookManager()
291 inputhook_manager = InputHookManager()
289
292
290 enable_wx = inputhook_manager.enable_wx
293 enable_wx = inputhook_manager.enable_wx
291 disable_wx = inputhook_manager.disable_wx
294 disable_wx = inputhook_manager.disable_wx
292 enable_qt4 = inputhook_manager.enable_qt4
295 enable_qt4 = inputhook_manager.enable_qt4
293 disable_qt4 = inputhook_manager.disable_qt4
296 disable_qt4 = inputhook_manager.disable_qt4
294 enable_gtk = inputhook_manager.enable_gtk
297 enable_gtk = inputhook_manager.enable_gtk
295 disable_gtk = inputhook_manager.disable_gtk
298 disable_gtk = inputhook_manager.disable_gtk
296 enable_tk = inputhook_manager.enable_tk
299 enable_tk = inputhook_manager.enable_tk
297 disable_tk = inputhook_manager.disable_tk
300 disable_tk = inputhook_manager.disable_tk
298 clear_inputhook = inputhook_manager.clear_inputhook
301 clear_inputhook = inputhook_manager.clear_inputhook
299 set_inputhook = inputhook_manager.set_inputhook
302 set_inputhook = inputhook_manager.set_inputhook
300 current_gui = inputhook_manager.current_gui
303 current_gui = inputhook_manager.current_gui
301 clear_app_refs = inputhook_manager.clear_app_refs
304 clear_app_refs = inputhook_manager.clear_app_refs
302
305
303
306
304 # Convenience function to switch amongst them
307 # Convenience function to switch amongst them
305 def enable_gui(gui=None):
308 def enable_gui(gui=None, app=None):
306 """Switch amongst GUI input hooks by name.
309 """Switch amongst GUI input hooks by name.
307
310
308 This is just a utility wrapper around the methods of the InputHookManager
311 This is just a utility wrapper around the methods of the InputHookManager
309 object.
312 object.
310
313
311 Parameters
314 Parameters
312 ----------
315 ----------
313 gui : optional, string or None
316 gui : optional, string or None
314 If None, clears input hook, otherwise it must be one of the recognized
317 If None, clears input hook, otherwise it must be one of the recognized
315 GUI names (see ``GUI_*`` constants in module).
318 GUI names (see ``GUI_*`` constants in module).
316
319
317 app : optional, bool
320 app : optional, existing application object.
318 If true, create an app object and return it.
321 For toolkits that have the concept of a global app, you can supply an
322 existing one. If not given, the toolkit will be probed for one, and if
323 none is found, a new one will be created. Note that GTK does not have
324 this concept, and passing an app if `gui`=="GTK" will raise an error.
319
325
320 Returns
326 Returns
321 -------
327 -------
322 The output of the underlying gui switch routine, typically the actual
328 The output of the underlying gui switch routine, typically the actual
323 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
329 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
324 one.
330 one.
325 """
331 """
326 guis = {None: clear_inputhook,
332 guis = {None: clear_inputhook,
327 GUI_OSX: lambda app=False: None,
333 GUI_OSX: lambda app=False: None,
328 GUI_TK: enable_tk,
334 GUI_TK: enable_tk,
329 GUI_GTK: enable_gtk,
335 GUI_GTK: enable_gtk,
330 GUI_WX: enable_wx,
336 GUI_WX: enable_wx,
331 GUI_QT: enable_qt4, # qt3 not supported
337 GUI_QT: enable_qt4, # qt3 not supported
332 GUI_QT4: enable_qt4 }
338 GUI_QT4: enable_qt4 }
333 try:
339 try:
334 gui_hook = guis[gui]
340 gui_hook = guis[gui]
335 except KeyError:
341 except KeyError:
336 e="Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
342 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
337 raise ValueError(e)
343 raise ValueError(e)
338 return gui_hook()
344 return gui_hook(app)
339
345
@@ -1,43 +1,40 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Simple GTK example to manually test event loop integration.
2 """Simple GTK example to manually test event loop integration.
3
3
4 This is meant to run tests manually in ipython as:
4 This is meant to run tests manually in ipython as:
5
5
6 In [5]: %gui gtk
6 In [5]: %gui gtk
7
7
8 In [6]: %run gui-gtk.py
8 In [6]: %run gui-gtk.py
9 """
9 """
10
10
11
11
12 import pygtk
12 import pygtk
13 pygtk.require('2.0')
13 pygtk.require('2.0')
14 import gtk
14 import gtk
15
15
16
16
17 def hello_world(wigdet, data=None):
17 def hello_world(wigdet, data=None):
18 print "Hello World"
18 print "Hello World"
19
19
20 def delete_event(widget, event, data=None):
20 def delete_event(widget, event, data=None):
21 return False
21 return False
22
22
23 def destroy(widget, data=None):
23 def destroy(widget, data=None):
24 gtk.main_quit()
24 gtk.main_quit()
25
25
26 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
26 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
27 window.connect("delete_event", delete_event)
27 window.connect("delete_event", delete_event)
28 window.connect("destroy", destroy)
28 window.connect("destroy", destroy)
29 button = gtk.Button("Hello World")
29 button = gtk.Button("Hello World")
30 button.connect("clicked", hello_world, None)
30 button.connect("clicked", hello_world, None)
31
31
32 window.add(button)
32 window.add(button)
33 button.show()
33 button.show()
34 window.show()
34 window.show()
35
35
36 try:
36 try:
37 from IPython.lib.inputhook import enable_gtk
37 from IPython.lib.inputhook import enable_gtk
38 enable_gtk()
38 enable_gtk()
39 except ImportError:
39 except ImportError:
40 gtk.main()
40 gtk.main()
41
42
43
@@ -1,41 +1,49 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Simple Qt4 example to manually test event loop integration.
2 """Simple Qt4 example to manually test event loop integration.
3
3
4 This is meant to run tests manually in ipython as:
4 This is meant to run tests manually in ipython as:
5
5
6 In [5]: %gui qt
6 In [5]: %gui qt
7
7
8 In [6]: %run gui-qt.py
8 In [6]: %run gui-qt.py
9
9
10 Ref: Modified from http://zetcode.com/tutorials/pyqt4/firstprograms/
10 Ref: Modified from http://zetcode.com/tutorials/pyqt4/firstprograms/
11 """
11 """
12
12
13 import sys
13 import sys
14 from PyQt4 import QtGui, QtCore
14 from PyQt4 import QtGui, QtCore
15
15
16 class SimpleWindow(QtGui.QWidget):
16 class SimpleWindow(QtGui.QWidget):
17 def __init__(self, parent=None):
17 def __init__(self, parent=None):
18 QtGui.QWidget.__init__(self, parent)
18 QtGui.QWidget.__init__(self, parent)
19
19
20 self.setGeometry(300, 300, 200, 80)
20 self.setGeometry(300, 300, 200, 80)
21 self.setWindowTitle('Hello World')
21 self.setWindowTitle('Hello World')
22
22
23 quit = QtGui.QPushButton('Close', self)
23 quit = QtGui.QPushButton('Close', self)
24 quit.setGeometry(10, 10, 60, 35)
24 quit.setGeometry(10, 10, 60, 35)
25
25
26 self.connect(quit, QtCore.SIGNAL('clicked()'),
26 self.connect(quit, QtCore.SIGNAL('clicked()'),
27 self, QtCore.SLOT('close()'))
27 self, QtCore.SLOT('close()'))
28
28
29 if __name__ == '__main__':
29 if __name__ == '__main__':
30 app = QtCore.QCoreApplication.instance()
30 app = QtCore.QCoreApplication.instance()
31 if app is None:
31 if app is None:
32 app = QtGui.QApplication([])
32 app = QtGui.QApplication([])
33
33
34 sw = SimpleWindow()
34 sw = SimpleWindow()
35 sw.show()
35 sw.show()
36
36
37 try:
37 try:
38 from IPython.lib.inputhook import enable_qt4
38 # Note: the following form allows this script to work both inside
39 enable_qt4()
39 # ipython and without it, but `%gui qt` MUST be run first (or
40 # equivalently, ipython could have been started with `--gui=qt`).
41 from IPython.lib.guisupport import start_event_loop_qt4
42 start_event_loop_qt4(app)
43
44 # This from doesn't require the gui support to have been enabled in
45 # advance, but it won't work if the script is run as a standalone app
46 # outside of IPython while the user does have IPython available.
47 #from IPython.lib.inputhook import enable_qt4; enable_qt4(app)
40 except ImportError:
48 except ImportError:
41 app.exec_()
49 app.exec_()
@@ -1,32 +1,32 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Simple Tk example to manually test event loop integration.
2 """Simple Tk example to manually test event loop integration.
3
3
4 This is meant to run tests manually in ipython as:
4 This is meant to run tests manually in ipython as:
5
5
6 In [5]: %gui tk
6 In [5]: %gui tk
7
7
8 In [6]: %run gui-tk.py
8 In [6]: %run gui-tk.py
9 """
9 """
10
10
11 from Tkinter import *
11 from Tkinter import *
12
12
13 class MyApp:
13 class MyApp:
14
14
15 def __init__(self, root):
15 def __init__(self, root):
16 frame = Frame(root)
16 frame = Frame(root)
17 frame.pack()
17 frame.pack()
18
18
19 self.button = Button(frame, text="Hello", command=self.hello_world)
19 self.button = Button(frame, text="Hello", command=self.hello_world)
20 self.button.pack(side=LEFT)
20 self.button.pack(side=LEFT)
21
21
22 def hello_world(self):
22 def hello_world(self):
23 print "Hello World!"
23 print "Hello World!"
24
24
25 root = Tk()
25 root = Tk()
26
26
27 app = MyApp(root)
27 app = MyApp(root)
28
28
29 try:
29 try:
30 from IPython import enable_tk; enable_tk(root)
30 from IPython.lib.inputhook import enable_tk; enable_tk(root)
31 except ImportError:
31 except ImportError:
32 root.mainloop()
32 root.mainloop()
@@ -1,109 +1,111 b''
1 #!/usr/bin/env python
1 """A Simple wx example to test IPython's event loop integration.
2 """A Simple wx example to test IPython's event loop integration.
2
3
3 To run this do:
4 To run this do:
4
5
5 In [5]: %gui wx
6 In [5]: %gui wx
6
7
7 In [6]: %run gui-wx.py
8 In [6]: %run gui-wx.py
8
9
9 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
10 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
10
11
11 This example can only be run once in a given IPython session because when
12 This example can only be run once in a given IPython session because when
12 the frame is closed, wx goes through its shutdown sequence, killing further
13 the frame is closed, wx goes through its shutdown sequence, killing further
13 attempts. I am sure someone who knows wx can fix this issue.
14 attempts. I am sure someone who knows wx can fix this issue.
14
15
15 Furthermore, once this example is run, the Wx event loop is mostly dead, so
16 Furthermore, once this example is run, the Wx event loop is mostly dead, so
16 even other new uses of Wx may not work correctly. If you know how to better
17 even other new uses of Wx may not work correctly. If you know how to better
17 handle this, please contact the ipython developers and let us know.
18 handle this, please contact the ipython developers and let us know.
18
19
19 Note however that we will work with the Matplotlib and Enthought developers so
20 Note however that we will work with the Matplotlib and Enthought developers so
20 that the main interactive uses of Wx we are aware of, namely these tools, will
21 that the main interactive uses of Wx we are aware of, namely these tools, will
21 continue to work well with IPython interactively.
22 continue to work well with IPython interactively.
22 """
23 """
23
24
24 import wx
25 import wx
25
26
26
27
27 class MyFrame(wx.Frame):
28 class MyFrame(wx.Frame):
28 """
29 """
29 This is MyFrame. It just shows a few controls on a wxPanel,
30 This is MyFrame. It just shows a few controls on a wxPanel,
30 and has a simple menu.
31 and has a simple menu.
31 """
32 """
32 def __init__(self, parent, title):
33 def __init__(self, parent, title):
33 wx.Frame.__init__(self, parent, -1, title,
34 wx.Frame.__init__(self, parent, -1, title,
34 pos=(150, 150), size=(350, 200))
35 pos=(150, 150), size=(350, 200))
35
36
36 # Create the menubar
37 # Create the menubar
37 menuBar = wx.MenuBar()
38 menuBar = wx.MenuBar()
38
39
39 # and a menu
40 # and a menu
40 menu = wx.Menu()
41 menu = wx.Menu()
41
42
42 # add an item to the menu, using \tKeyName automatically
43 # add an item to the menu, using \tKeyName automatically
43 # creates an accelerator, the third param is some help text
44 # creates an accelerator, the third param is some help text
44 # that will show up in the statusbar
45 # that will show up in the statusbar
45 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
46 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
46
47
47 # bind the menu event to an event handler
48 # bind the menu event to an event handler
48 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
49 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
49
50
50 # and put the menu on the menubar
51 # and put the menu on the menubar
51 menuBar.Append(menu, "&File")
52 menuBar.Append(menu, "&File")
52 self.SetMenuBar(menuBar)
53 self.SetMenuBar(menuBar)
53
54
54 self.CreateStatusBar()
55 self.CreateStatusBar()
55
56
56 # Now create the Panel to put the other controls on.
57 # Now create the Panel to put the other controls on.
57 panel = wx.Panel(self)
58 panel = wx.Panel(self)
58
59
59 # and a few controls
60 # and a few controls
60 text = wx.StaticText(panel, -1, "Hello World!")
61 text = wx.StaticText(panel, -1, "Hello World!")
61 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
62 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
62 text.SetSize(text.GetBestSize())
63 text.SetSize(text.GetBestSize())
63 btn = wx.Button(panel, -1, "Close")
64 btn = wx.Button(panel, -1, "Close")
64 funbtn = wx.Button(panel, -1, "Just for fun...")
65 funbtn = wx.Button(panel, -1, "Just for fun...")
65
66
66 # bind the button events to handlers
67 # bind the button events to handlers
67 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
68 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
68 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
69 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
69
70
70 # Use a sizer to layout the controls, stacked vertically and with
71 # Use a sizer to layout the controls, stacked vertically and with
71 # a 10 pixel border around each
72 # a 10 pixel border around each
72 sizer = wx.BoxSizer(wx.VERTICAL)
73 sizer = wx.BoxSizer(wx.VERTICAL)
73 sizer.Add(text, 0, wx.ALL, 10)
74 sizer.Add(text, 0, wx.ALL, 10)
74 sizer.Add(btn, 0, wx.ALL, 10)
75 sizer.Add(btn, 0, wx.ALL, 10)
75 sizer.Add(funbtn, 0, wx.ALL, 10)
76 sizer.Add(funbtn, 0, wx.ALL, 10)
76 panel.SetSizer(sizer)
77 panel.SetSizer(sizer)
77 panel.Layout()
78 panel.Layout()
78
79
79
80
80 def OnTimeToClose(self, evt):
81 def OnTimeToClose(self, evt):
81 """Event handler for the button click."""
82 """Event handler for the button click."""
82 print "See ya later!"
83 print "See ya later!"
83 self.Close()
84 self.Close()
84
85
85 def OnFunButton(self, evt):
86 def OnFunButton(self, evt):
86 """Event handler for the button click."""
87 """Event handler for the button click."""
87 print "Having fun yet?"
88 print "Having fun yet?"
88
89
89
90
90 class MyApp(wx.App):
91 class MyApp(wx.App):
91 def OnInit(self):
92 def OnInit(self):
92 frame = MyFrame(None, "Simple wxPython App")
93 frame = MyFrame(None, "Simple wxPython App")
93 self.SetTopWindow(frame)
94 self.SetTopWindow(frame)
94
95
95 print "Print statements go to this stdout window by default."
96 print "Print statements go to this stdout window by default."
96
97
97 frame.Show(True)
98 frame.Show(True)
98 return True
99 return True
99
100
100 app = wx.GetApp()
101 if __name__ == '__main__':
101 if app is None:
102 app = wx.GetApp()
102 app = MyApp(redirect=False, clearSigInt=False)
103 if app is None:
104 app = MyApp(redirect=False, clearSigInt=False)
103
105
104 try:
106 try:
105 from IPython.lib.inputhook import enable_wx
107 from IPython.lib.inputhook import enable_wx
106 enable_wx(app)
108 enable_wx(app)
107 except ImportError:
109 except ImportError:
108 app.MainLoop()
110 app.MainLoop()
109
111
General Comments 0
You need to be logged in to leave comments. Login now