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