]> git.saurik.com Git - wxWidgets.git/blob - wxPython/src/_app_ex.py
don't Printf() the string into itself (replaces patch 1655318)
[wxWidgets.git] / wxPython / src / _app_ex.py
1
2 #----------------------------------------------------------------------
3
4 class PyOnDemandOutputWindow:
5 """
6 A class that can be used for redirecting Python's stdout and
7 stderr streams. It will do nothing until something is wrriten to
8 the stream at which point it will create a Frame with a text area
9 and write the text there.
10 """
11 def __init__(self, title = "wxPython: stdout/stderr"):
12 self.frame = None
13 self.title = title
14 self.pos = wx.DefaultPosition
15 self.size = (450, 300)
16 self.parent = None
17
18 def SetParent(self, parent):
19 """Set the window to be used as the popup Frame's parent."""
20 self.parent = parent
21
22
23 def CreateOutputWindow(self, st):
24 self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size,
25 style=wx.DEFAULT_FRAME_STYLE)
26 self.text = wx.TextCtrl(self.frame, -1, "",
27 style=wx.TE_MULTILINE|wx.TE_READONLY)
28 self.text.AppendText(st)
29 self.frame.Show(True)
30 self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
31
32
33 def OnCloseWindow(self, event):
34 if self.frame is not None:
35 self.frame.Destroy()
36 self.frame = None
37 self.text = None
38
39
40 # These methods provide the file-like output behaviour.
41 def write(self, text):
42 """
43 Create the output window if needed and write the string to it.
44 If not called in the context of the gui thread then uses
45 CallAfter to do the work there.
46 """
47 if self.frame is None:
48 if not wx.Thread_IsMain():
49 wx.CallAfter(self.CreateOutputWindow, text)
50 else:
51 self.CreateOutputWindow(text)
52 else:
53 if not wx.Thread_IsMain():
54 wx.CallAfter(self.text.AppendText, text)
55 else:
56 self.text.AppendText(text)
57
58
59 def close(self):
60 if self.frame is not None:
61 wx.CallAfter(self.frame.Close)
62
63
64 def flush(self):
65 pass
66
67
68
69 #----------------------------------------------------------------------
70
71 _defRedirect = (wx.Platform == '__WXMSW__' or wx.Platform == '__WXMAC__')
72
73 class App(wx.PyApp):
74 """
75 The ``wx.App`` class represents the application and is used to:
76
77 * bootstrap the wxPython system and initialize the underlying
78 gui toolkit
79 * set and get application-wide properties
80 * implement the windowing system main message or event loop,
81 and to dispatch events to window instances
82 * etc.
83
84 Every application must have a ``wx.App`` instance, and all
85 creation of UI objects should be delayed until after the
86 ``wx.App`` object has been created in order to ensure that the gui
87 platform and wxWidgets have been fully initialized.
88
89 Normally you would derive from this class and implement an
90 ``OnInit`` method that creates a frame and then calls
91 ``self.SetTopWindow(frame)``.
92
93 :see: `wx.PySimpleApp` for a simpler app class that can be used
94 directly.
95 """
96
97 outputWindowClass = PyOnDemandOutputWindow
98
99 def __init__(self, redirect=_defRedirect, filename=None,
100 useBestVisual=False, clearSigInt=True):
101 """
102 Construct a ``wx.App`` object.
103
104 :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be
105 redirected? Defaults to True on Windows and Mac, False
106 otherwise. If `filename` is None then output will be
107 redirected to a window that pops up as needed. (You can
108 control what kind of window is created for the output by
109 resetting the class variable ``outputWindowClass`` to a
110 class of your choosing.)
111
112 :param filename: The name of a file to redirect output to, if
113 redirect is True.
114
115 :param useBestVisual: Should the app try to use the best
116 available visual provided by the system (only relevant on
117 systems that have more than one visual.) This parameter
118 must be used instead of calling `SetUseBestVisual` later
119 on because it must be set before the underlying GUI
120 toolkit is initialized.
121
122 :param clearSigInt: Should SIGINT be cleared? This allows the
123 app to terminate upon a Ctrl-C in the console like other
124 GUI apps will.
125
126 :note: You should override OnInit to do applicaition
127 initialization to ensure that the system, toolkit and
128 wxWidgets are fully initialized.
129 """
130
131 wx.PyApp.__init__(self)
132
133 # make sure we can create a GUI
134 if not self.IsDisplayAvailable():
135
136 if wx.Platform == "__WXMAC__":
137 msg = """This program needs access to the screen.
138 Please run with 'pythonw', not 'python', and only when you are logged
139 in on the main display of your Mac."""
140
141 elif wx.Platform == "__WXGTK__":
142 msg ="Unable to access the X Display, is $DISPLAY set properly?"
143
144 else:
145 msg = "Unable to create GUI"
146 # TODO: more description is needed for wxMSW...
147
148 raise SystemExit(msg)
149
150 # This has to be done before OnInit
151 self.SetUseBestVisual(useBestVisual)
152
153 # Set the default handler for SIGINT. This fixes a problem
154 # where if Ctrl-C is pressed in the console that started this
155 # app then it will not appear to do anything, (not even send
156 # KeyboardInterrupt???) but will later segfault on exit. By
157 # setting the default handler then the app will exit, as
158 # expected (depending on platform.)
159 if clearSigInt:
160 try:
161 import signal
162 signal.signal(signal.SIGINT, signal.SIG_DFL)
163 except:
164 pass
165
166 # Save and redirect the stdio to a window?
167 self.stdioWin = None
168 self.saveStdio = (_sys.stdout, _sys.stderr)
169 if redirect:
170 self.RedirectStdio(filename)
171
172 # Use Python's install prefix as the default
173 wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix)
174
175 # Until the new native control for wxMac is up to par, still use the generic one.
176 wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1)
177
178 # This finishes the initialization of wxWindows and then calls
179 # the OnInit that should be present in the derived class
180 self._BootstrapApp()
181
182
183 def OnPreInit(self):
184 """
185 Things that must be done after _BootstrapApp has done its
186 thing, but would be nice if they were already done by the time
187 that OnInit is called.
188 """
189 wx.StockGDI._initStockObjects()
190
191
192 def __del__(self, destroy=wx.PyApp.__del__):
193 self.RestoreStdio() # Just in case the MainLoop was overridden
194 destroy(self)
195
196 def Destroy(self):
197 self.this.own(False)
198 wx.PyApp.Destroy(self)
199
200 def SetTopWindow(self, frame):
201 """Set the \"main\" top level window"""
202 if self.stdioWin:
203 self.stdioWin.SetParent(frame)
204 wx.PyApp.SetTopWindow(self, frame)
205
206
207 def MainLoop(self):
208 """Execute the main GUI event loop"""
209 wx.PyApp.MainLoop(self)
210 self.RestoreStdio()
211
212
213 def RedirectStdio(self, filename=None):
214 """Redirect sys.stdout and sys.stderr to a file or a popup window."""
215 if filename:
216 _sys.stdout = _sys.stderr = open(filename, 'a')
217 else:
218 self.stdioWin = self.outputWindowClass()
219 _sys.stdout = _sys.stderr = self.stdioWin
220
221
222 def RestoreStdio(self):
223 try:
224 _sys.stdout, _sys.stderr = self.saveStdio
225 except:
226 pass
227
228
229 def SetOutputWindowAttributes(self, title=None, pos=None, size=None):
230 """
231 Set the title, position and/or size of the output window if
232 the stdio has been redirected. This should be called before
233 any output would cause the output window to be created.
234 """
235 if self.stdioWin:
236 if title is not None:
237 self.stdioWin.title = title
238 if pos is not None:
239 self.stdioWin.pos = pos
240 if size is not None:
241 self.stdioWin.size = size
242
243
244
245
246 # change from wx.PyApp_XX to wx.App_XX
247 App_GetMacSupportPCMenuShortcuts = _core_.PyApp_GetMacSupportPCMenuShortcuts
248 App_GetMacAboutMenuItemId = _core_.PyApp_GetMacAboutMenuItemId
249 App_GetMacPreferencesMenuItemId = _core_.PyApp_GetMacPreferencesMenuItemId
250 App_GetMacExitMenuItemId = _core_.PyApp_GetMacExitMenuItemId
251 App_GetMacHelpMenuTitleName = _core_.PyApp_GetMacHelpMenuTitleName
252 App_SetMacSupportPCMenuShortcuts = _core_.PyApp_SetMacSupportPCMenuShortcuts
253 App_SetMacAboutMenuItemId = _core_.PyApp_SetMacAboutMenuItemId
254 App_SetMacPreferencesMenuItemId = _core_.PyApp_SetMacPreferencesMenuItemId
255 App_SetMacExitMenuItemId = _core_.PyApp_SetMacExitMenuItemId
256 App_SetMacHelpMenuTitleName = _core_.PyApp_SetMacHelpMenuTitleName
257 App_GetComCtl32Version = _core_.PyApp_GetComCtl32Version
258
259 #----------------------------------------------------------------------------
260
261 class PySimpleApp(wx.App):
262 """
263 A simple application class. You can just create one of these and
264 then then make your top level windows later, and not have to worry
265 about OnInit. For example::
266
267 app = wx.PySimpleApp()
268 frame = wx.Frame(None, title='Hello World')
269 frame.Show()
270 app.MainLoop()
271
272 :see: `wx.App`
273 """
274
275 def __init__(self, redirect=False, filename=None,
276 useBestVisual=False, clearSigInt=True):
277 """
278 :see: `wx.App.__init__`
279 """
280 wx.App.__init__(self, redirect, filename, useBestVisual, clearSigInt)
281
282 def OnInit(self):
283 return True
284
285
286
287 # Is anybody using this one?
288 class PyWidgetTester(wx.App):
289 def __init__(self, size = (250, 100)):
290 self.size = size
291 wx.App.__init__(self, 0)
292
293 def OnInit(self):
294 self.frame = wx.Frame(None, -1, "Widget Tester", pos=(0,0), size=self.size)
295 self.SetTopWindow(self.frame)
296 return True
297
298 def SetWidget(self, widgetClass, *args, **kwargs):
299 w = widgetClass(self.frame, *args, **kwargs)
300 self.frame.Show(True)
301
302 #----------------------------------------------------------------------------
303 # DO NOT hold any other references to this object. This is how we
304 # know when to cleanup system resources that wxWidgets is holding. When
305 # the sys module is unloaded, the refcount on sys.__wxPythonCleanup
306 # goes to zero and it calls the wx.App_CleanUp function.
307
308 class __wxPyCleanup:
309 def __init__(self):
310 self.cleanup = _core_.App_CleanUp
311 def __del__(self):
312 self.cleanup()
313
314 _sys.__wxPythonCleanup = __wxPyCleanup()
315
316 ## # another possible solution, but it gets called too early...
317 ## import atexit
318 ## atexit.register(_core_.wxApp_CleanUp)
319
320
321 #----------------------------------------------------------------------------