##// END OF EJS Templates
In-progress work on trying to get a robust inputhook setup....
Fernando Perez -
Show More
@@ -0,0 +1,57 b''
1 """Test the new %gui command. Run this in ipython as
2
3 %run switchgui [backend]
4
5 where the optional backend can be one of: qt4, gtk, tk, wx.
6 """
7
8 import sys
9 import time
10
11 import IPython.core.ipapi as ipapi
12 ip = ipapi.get()
13
14 from IPython.lib import inputhook
15
16 try:
17 backend = sys.argv[1]
18 #a = ip.magic('gui -a %s' % backend)
19 #a = ip.magic('gui %s' % backend)
20 except IndexError:
21 backend = 'qt'
22
23 backends = dict(wx='wxagg', qt='qt4agg', gtk='gtkagg', tk='tkagg')
24
25 import matplotlib
26 matplotlib.use(backends[backend])
27 #matplotlib.interactive(True)
28
29 import matplotlib
30 from matplotlib import pyplot as plt, mlab, pylab
31 import numpy as np
32
33 from numpy import *
34 from matplotlib.pyplot import *
35
36 x = np.linspace(0,pi,100)
37
38 print "A plot has been created"
39 line, = plot(x,sin(2*x))
40 plt.show()
41 inputhook.spin_qt4()
42
43 #raw_input("Press Enter to continue")
44
45 print "I will now count until 10, please hit Ctrl-C before I'm done..."
46 print "IPython should stop counting and return to the prompt without crashing."
47 print
48 line_x = line.get_data()[0]
49 for i in range(1,51):
50 print i,
51 sys.stdout.flush()
52 line.set_data(line_x,sin(x*i))
53 plt.title('i=%d' % i)
54 #plt.show()
55 plt.draw()
56 inputhook.spin_qt4()
57 #time.sleep(0.04)
@@ -1,333 +1,352 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: 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
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Code
22 # Code
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 def appstart_qt4():
26 from PyQt4 import QtCore, QtGui
27
28 app = QtCore.QCoreApplication.instance()
29 print 'qtapp:', app
30 if app is not None:
31 if current_gui() == 'qt4':
32 pass
33 else:
34 app.exec_()
35
36
25 class _DummyMainloop(object):
37 class _DummyMainloop(object):
26 """A special manager to hijack GUI mainloops that is mostly a no-op.
38 """A special manager to hijack GUI mainloops that is mostly a no-op.
27
39
28 This does have, however, special logic.
40 This does have, however, special logic.
29 """
41 """
30 def __init__(self, ml, ihm, gui_type):
42 def __init__(self, ml, ihm, gui_type):
31 self.ml = ml
43 self.ml = ml
32 self.ihm = ihm
44 self.ihm = ihm
33 self.gui_type = gui_type
45 self.gui_type = gui_type
34
46
35
47
36 def __call__(self, *args, **kw):
48 def __call__(self, *args, **kw):
49 force = kw.pop('force', False)
50 force = False
51 if force:
52 #print 'forced spin' # dbg
53 self.ml(*args, **kw)
54
37 if self.ihm.current_gui() == self.gui_type:
55 if self.ihm.current_gui() == self.gui_type:
38 pass
56 pass
39 else:
57 else:
40 self.ml(*args, **kw)
58 self.ml(*args, **kw)
41
59
42
60
43 def spin_qt4():
61 def spin_qt4():
44 from PyQt4 import QtCore, QtGui
62 from PyQt4 import QtCore, QtGui
45
63
46 app = QtCore.QCoreApplication.instance()
64 app = QtCore.QCoreApplication.instance()
47 if (app is not None) and (app.thread() == QtCore.QThread.currentThread()):
65 if (app is not None) and (app.thread() == QtCore.QThread.currentThread()):
48 timer = QtCore.QTimer()
66 ## timer = QtCore.QTimer()
49 QtCore.QObject.connect(timer,
67 ## QtCore.QObject.connect(timer,
50 QtCore.SIGNAL('timeout()'),
68 ## QtCore.SIGNAL('timeout()'),
51 app,
69 ## app,
52 QtCore.SLOT('quit()'))
70 ## QtCore.SLOT('quit()'))
53 timer.start(100)
71 ## timer.start(100)
54 QtCore.QCoreApplication.exec_()
72 #QtCore.QCoreApplication.exec_(force=True)
55 timer.stop()
73 QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents)
74 ##timer.stop()
56
75
57
76
58 def spin_wx():
77 def spin_wx():
59 app = wx.GetApp()
78 app = wx.GetApp()
60 if app is not None and wx.Thread_IsMain():
79 if app is not None and wx.Thread_IsMain():
61 evtloop = wx.EventLoop()
80 evtloop = wx.EventLoop()
62 ea = wx.EventLoopActivator(evtloop)
81 ea = wx.EventLoopActivator(evtloop)
63 while evtloop.Pending():
82 while evtloop.Pending():
64 evtloop.Dispatch()
83 evtloop.Dispatch()
65 app.ProcessIdle()
84 app.ProcessIdle()
66 del ea
85 del ea
67
86
68
87
69 class InputHookManager(object):
88 class InputHookManager(object):
70 """Manage PyOS_InputHook for different GUI toolkits.
89 """Manage PyOS_InputHook for different GUI toolkits.
71
90
72 This class installs various hooks under ``PyOSInputHook`` to handle
91 This class installs various hooks under ``PyOSInputHook`` to handle
73 GUI event loop integration.
92 GUI event loop integration.
74 """
93 """
75
94
76 def __init__(self):
95 def __init__(self):
77 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
96 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
78 self._apps = {}
97 self._apps = {}
79 self._reset()
98 self._reset()
80
99
81 def _reset(self):
100 def _reset(self):
82 self._callback_pyfunctype = None
101 self._callback_pyfunctype = None
83 self._callback = None
102 self._callback = None
84 self._installed = False
103 self._installed = False
85 self._current_gui = None
104 self._current_gui = None
86
105
87 def _hijack_wx(self):
106 def _hijack_wx(self):
88 """Hijack the wx mainloop so a user calling it won't cause badness."""
107 """Hijack the wx mainloop so a user calling it won't cause badness."""
89 import wx
108 import wx
90 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
109 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
91 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
110 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
92 else: raise AttributeError('Could not find wx core module')
111 else: raise AttributeError('Could not find wx core module')
93 orig_mainloop = core.PyApp_MainLoop
112 orig_mainloop = core.PyApp_MainLoop
94 core.PyApp_MainLoop = _DummyMainloop
113 core.PyApp_MainLoop = _DummyMainloop
95 return orig_mainloop
114 return orig_mainloop
96
115
97 def _hijack_qt4(self):
116 def _hijack_qt4(self):
98 """Hijack the qt4 mainloop so a user calling it won't cause badness."""
117 """Hijack the qt4 mainloop so a user calling it won't cause badness."""
99 from PyQt4 import QtGui, QtCore
118 from PyQt4 import QtGui, QtCore
100 orig_mainloop = QtGui.qApp.exec_
119 orig_mainloop = QtGui.qApp.exec_
101 dumb_ml = _DummyMainloop(orig_mainloop, self, 'qt4')
120 dumb_ml = _DummyMainloop(orig_mainloop, self, 'qt4')
102 QtGui.qApp.exec_ = dumb_ml
121 QtGui.qApp.exec_ = dumb_ml
103 QtGui.QApplication.exec_ = dumb_ml
122 QtGui.QApplication.exec_ = dumb_ml
104 QtCore.QCoreApplication.exec_ = dumb_ml
123 QtCore.QCoreApplication.exec_ = dumb_ml
105 return orig_mainloop
124 return orig_mainloop
106
125
107 def _hijack_gtk(self):
126 def _hijack_gtk(self):
108 """Hijack the gtk mainloop so a user calling it won't cause badness."""
127 """Hijack the gtk mainloop so a user calling it won't cause badness."""
109 import gtk
128 import gtk
110 orig_mainloop = gtk.main
129 orig_mainloop = gtk.main
111 gtk.mainloop = _DummyMainloop
130 gtk.mainloop = _DummyMainloop
112 gtk.main = _DummyMainloop
131 gtk.main = _DummyMainloop
113 return orig_mainloop
132 return orig_mainloop
114
133
115 def _hijack_tk(self):
134 def _hijack_tk(self):
116 """Hijack the tk mainloop so a user calling it won't cause badness."""
135 """Hijack the tk mainloop so a user calling it won't cause badness."""
117 import Tkinter
136 import Tkinter
118 Tkinter.Misc.mainloop = _DummyMainloop
137 Tkinter.Misc.mainloop = _DummyMainloop
119 Tkinter.mainloop = _DummyMainloop
138 Tkinter.mainloop = _DummyMainloop
120
139
121 def get_pyos_inputhook(self):
140 def get_pyos_inputhook(self):
122 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
141 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
123 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
142 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
124
143
125 def get_pyos_inputhook_as_func(self):
144 def get_pyos_inputhook_as_func(self):
126 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
145 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
127 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
146 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
128
147
129 def set_inputhook(self, callback):
148 def set_inputhook(self, callback):
130 """Set PyOS_InputHook to callback and return the previous one."""
149 """Set PyOS_InputHook to callback and return the previous one."""
131 self._callback = callback
150 self._callback = callback
132 self._callback_pyfunctype = self.PYFUNC(callback)
151 self._callback_pyfunctype = self.PYFUNC(callback)
133 pyos_inputhook_ptr = self.get_pyos_inputhook()
152 pyos_inputhook_ptr = self.get_pyos_inputhook()
134 original = self.get_pyos_inputhook_as_func()
153 original = self.get_pyos_inputhook_as_func()
135 pyos_inputhook_ptr.value = \
154 pyos_inputhook_ptr.value = \
136 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
155 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
137 self._installed = True
156 self._installed = True
138 return original
157 return original
139
158
140 def clear_inputhook(self):
159 def clear_inputhook(self):
141 """Set PyOS_InputHook to NULL and return the previous one."""
160 """Set PyOS_InputHook to NULL and return the previous one."""
142 pyos_inputhook_ptr = self.get_pyos_inputhook()
161 pyos_inputhook_ptr = self.get_pyos_inputhook()
143 original = self.get_pyos_inputhook_as_func()
162 original = self.get_pyos_inputhook_as_func()
144 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
163 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
145 self._reset()
164 self._reset()
146 return original
165 return original
147
166
148 def clear_app_refs(self, gui=None):
167 def clear_app_refs(self, gui=None):
149 """Clear IPython's internal reference to an application instance.
168 """Clear IPython's internal reference to an application instance.
150
169
151 Whenever we create an app for a user on qt4 or wx, we hold a
170 Whenever we create an app for a user on qt4 or wx, we hold a
152 reference to the app. This is needed because in some cases bad things
171 reference to the app. This is needed because in some cases bad things
153 can happen if a user doesn't hold a reference themselves. This
172 can happen if a user doesn't hold a reference themselves. This
154 method is provided to clear the references we are holding.
173 method is provided to clear the references we are holding.
155
174
156 Parameters
175 Parameters
157 ----------
176 ----------
158 gui : None or str
177 gui : None or str
159 If None, clear all app references. If ('wx', 'qt4') clear
178 If None, clear all app references. If ('wx', 'qt4') clear
160 the app for that toolkit. References are not held for gtk or tk
179 the app for that toolkit. References are not held for gtk or tk
161 as those toolkits don't have the notion of an app.
180 as those toolkits don't have the notion of an app.
162 """
181 """
163 if gui is None:
182 if gui is None:
164 self._apps = {}
183 self._apps = {}
165 elif self._apps.has_key(gui):
184 elif self._apps.has_key(gui):
166 del self._apps[gui]
185 del self._apps[gui]
167
186
168 def enable_wx(self, app=False):
187 def enable_wx(self, app=False):
169 """Enable event loop integration with wxPython.
188 """Enable event loop integration with wxPython.
170
189
171 Parameters
190 Parameters
172 ----------
191 ----------
173 app : bool
192 app : bool
174 Create a running application object or not.
193 Create a running application object or not.
175
194
176 Notes
195 Notes
177 -----
196 -----
178 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
197 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
179 the wxPython to integrate with terminal based applications like
198 the wxPython to integrate with terminal based applications like
180 IPython.
199 IPython.
181
200
182 If ``app`` is True, we create an :class:`wx.App` as follows::
201 If ``app`` is True, we create an :class:`wx.App` as follows::
183
202
184 import wx
203 import wx
185 app = wx.App(redirect=False, clearSigInt=False)
204 app = wx.App(redirect=False, clearSigInt=False)
186
205
187 Both options this constructor are important for things to work
206 Both options this constructor are important for things to work
188 properly in an interactive context.
207 properly in an interactive context.
189
208
190 But, we first check to see if an application has already been
209 But, we first check to see if an application has already been
191 created. If so, we simply return that instance.
210 created. If so, we simply return that instance.
192 """
211 """
193 from IPython.lib.inputhookwx import inputhook_wx
212 from IPython.lib.inputhookwx import inputhook_wx
194 self.set_inputhook(inputhook_wx)
213 self.set_inputhook(inputhook_wx)
195 self._current_gui = 'wx'
214 self._current_gui = 'wx'
196 self._hijack_wx()
215 self._hijack_wx()
197 if app:
216 if app:
198 import wx
217 import wx
199 app = wx.GetApp()
218 app = wx.GetApp()
200 if app is None:
219 if app is None:
201 app = wx.App(redirect=False, clearSigInt=False)
220 app = wx.App(redirect=False, clearSigInt=False)
202 self._apps['wx'] = app
221 self._apps['wx'] = app
203 return app
222 return app
204
223
205 def disable_wx(self):
224 def disable_wx(self):
206 """Disable event loop integration with wxPython.
225 """Disable event loop integration with wxPython.
207
226
208 This merely sets PyOS_InputHook to NULL.
227 This merely sets PyOS_InputHook to NULL.
209 """
228 """
210 self.clear_inputhook()
229 self.clear_inputhook()
211
230
212 def enable_qt4(self, app=False):
231 def enable_qt4(self, app=False):
213 """Enable event loop integration with PyQt4.
232 """Enable event loop integration with PyQt4.
214
233
215 Parameters
234 Parameters
216 ----------
235 ----------
217 app : bool
236 app : bool
218 Create a running application object or not.
237 Create a running application object or not.
219
238
220 Notes
239 Notes
221 -----
240 -----
222 This methods sets the PyOS_InputHook for PyQt4, which allows
241 This methods sets the PyOS_InputHook for PyQt4, which allows
223 the PyQt4 to integrate with terminal based applications like
242 the PyQt4 to integrate with terminal based applications like
224 IPython.
243 IPython.
225
244
226 If ``app`` is True, we create an :class:`QApplication` as follows::
245 If ``app`` is True, we create an :class:`QApplication` as follows::
227
246
228 from PyQt4 import QtCore
247 from PyQt4 import QtCore
229 app = QtGui.QApplication(sys.argv)
248 app = QtGui.QApplication(sys.argv)
230
249
231 But, we first check to see if an application has already been
250 But, we first check to see if an application has already been
232 created. If so, we simply return that instance.
251 created. If so, we simply return that instance.
233 """
252 """
234 from PyQt4 import QtCore
253 from PyQt4 import QtCore
235 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
254 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
236 # was set when QtCore was imported, but if it ever got removed,
255 # was set when QtCore was imported, but if it ever got removed,
237 # you couldn't reset it. For earlier versions we can
256 # you couldn't reset it. For earlier versions we can
238 # probably implement a ctypes version.
257 # probably implement a ctypes version.
239 try:
258 try:
240 QtCore.pyqtRestoreInputHook()
259 QtCore.pyqtRestoreInputHook()
241 except AttributeError:
260 except AttributeError:
242 pass
261 pass
243 self._current_gui = 'qt4'
262 self._current_gui = 'qt4'
244 self._hijack_qt4()
263 #self._hijack_qt4()
245 if app:
264 if app:
246 from PyQt4 import QtGui
265 from PyQt4 import QtGui
247 app = QtCore.QCoreApplication.instance()
266 app = QtCore.QCoreApplication.instance()
248 if app is None:
267 if app is None:
249 app = QtGui.QApplication(sys.argv)
268 app = QtGui.QApplication(sys.argv)
250 self._apps['qt4'] = app
269 self._apps['qt4'] = app
251 return app
270 return app
252
271
253 def disable_qt4(self):
272 def disable_qt4(self):
254 """Disable event loop integration with PyQt4.
273 """Disable event loop integration with PyQt4.
255
274
256 This merely sets PyOS_InputHook to NULL.
275 This merely sets PyOS_InputHook to NULL.
257 """
276 """
258 self.clear_inputhook()
277 self.clear_inputhook()
259
278
260 def enable_gtk(self, app=False):
279 def enable_gtk(self, app=False):
261 """Enable event loop integration with PyGTK.
280 """Enable event loop integration with PyGTK.
262
281
263 Parameters
282 Parameters
264 ----------
283 ----------
265 app : bool
284 app : bool
266 Create a running application object or not. Because gtk does't
285 Create a running application object or not. Because gtk does't
267 have an app class, this does nothing.
286 have an app class, this does nothing.
268
287
269 Notes
288 Notes
270 -----
289 -----
271 This methods sets the PyOS_InputHook for PyGTK, which allows
290 This methods sets the PyOS_InputHook for PyGTK, which allows
272 the PyGTK to integrate with terminal based applications like
291 the PyGTK to integrate with terminal based applications like
273 IPython.
292 IPython.
274 """
293 """
275 import gtk
294 import gtk
276 try:
295 try:
277 gtk.set_interactive(True)
296 gtk.set_interactive(True)
278 self._current_gui = 'gtk'
297 self._current_gui = 'gtk'
279 except AttributeError:
298 except AttributeError:
280 # For older versions of gtk, use our own ctypes version
299 # For older versions of gtk, use our own ctypes version
281 from IPython.lib.inputhookgtk import inputhook_gtk
300 from IPython.lib.inputhookgtk import inputhook_gtk
282 self.set_inputhook(inputhook_gtk)
301 self.set_inputhook(inputhook_gtk)
283 self._current_gui = 'gtk'
302 self._current_gui = 'gtk'
284 self._hijack_gtk()
303 self._hijack_gtk()
285
304
286 def disable_gtk(self):
305 def disable_gtk(self):
287 """Disable event loop integration with PyGTK.
306 """Disable event loop integration with PyGTK.
288
307
289 This merely sets PyOS_InputHook to NULL.
308 This merely sets PyOS_InputHook to NULL.
290 """
309 """
291 self.clear_inputhook()
310 self.clear_inputhook()
292
311
293 def enable_tk(self, app=False):
312 def enable_tk(self, app=False):
294 """Enable event loop integration with Tk.
313 """Enable event loop integration with Tk.
295
314
296 Parameters
315 Parameters
297 ----------
316 ----------
298 app : bool
317 app : bool
299 Create a running application object or not.
318 Create a running application object or not.
300
319
301 Notes
320 Notes
302 -----
321 -----
303 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
322 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
304 sets ``PyOS_InputHook``.
323 sets ``PyOS_InputHook``.
305 """
324 """
306 self._current_gui = 'tk'
325 self._current_gui = 'tk'
307 self._hijack_tk()
326 self._hijack_tk()
308
327
309 def disable_tk(self):
328 def disable_tk(self):
310 """Disable event loop integration with Tkinter.
329 """Disable event loop integration with Tkinter.
311
330
312 This merely sets PyOS_InputHook to NULL.
331 This merely sets PyOS_InputHook to NULL.
313 """
332 """
314 self.clear_inputhook()
333 self.clear_inputhook()
315
334
316 def current_gui(self):
335 def current_gui(self):
317 """Return a string indicating the currently active GUI or None."""
336 """Return a string indicating the currently active GUI or None."""
318 return self._current_gui
337 return self._current_gui
319
338
320 inputhook_manager = InputHookManager()
339 inputhook_manager = InputHookManager()
321
340
322 enable_wx = inputhook_manager.enable_wx
341 enable_wx = inputhook_manager.enable_wx
323 disable_wx = inputhook_manager.disable_wx
342 disable_wx = inputhook_manager.disable_wx
324 enable_qt4 = inputhook_manager.enable_qt4
343 enable_qt4 = inputhook_manager.enable_qt4
325 disable_qt4 = inputhook_manager.disable_qt4
344 disable_qt4 = inputhook_manager.disable_qt4
326 enable_gtk = inputhook_manager.enable_gtk
345 enable_gtk = inputhook_manager.enable_gtk
327 disable_gtk = inputhook_manager.disable_gtk
346 disable_gtk = inputhook_manager.disable_gtk
328 enable_tk = inputhook_manager.enable_tk
347 enable_tk = inputhook_manager.enable_tk
329 disable_tk = inputhook_manager.disable_tk
348 disable_tk = inputhook_manager.disable_tk
330 clear_inputhook = inputhook_manager.clear_inputhook
349 clear_inputhook = inputhook_manager.clear_inputhook
331 set_inputhook = inputhook_manager.set_inputhook
350 set_inputhook = inputhook_manager.set_inputhook
332 current_gui = inputhook_manager.current_gui
351 current_gui = inputhook_manager.current_gui
333 clear_app_refs = inputhook_manager.clear_app_refs
352 clear_app_refs = inputhook_manager.clear_app_refs
@@ -1,37 +1,42 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 app.exec_()
37 try:
38 import IPython.lib.inputhook as i; i.appstart_qt4()
39 except ImportError:
40 app.exec_()
41
42 #import time; time.sleep(10)
General Comments 0
You need to be logged in to leave comments. Login now