Coverage for /Users/Newville/Codes/xraylarch/larch/wxlib/larchframe.py: 16%
503 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1#!/usr/bin/env python
2#
4import sys
5import os
6import time
7from functools import partial
8import wx
9import wx.lib.mixins.inspection
11import numpy
12import scipy
13import larch
14from pyshortcuts import platform
16from wxutils import (MenuItem, Font, Button, Choice, panel_pack)
18from .gui_utils import LarchWxApp
19from .readlinetextctrl import ReadlineTextCtrl
20from .larchfilling import Filling
21from .columnframe import ColumnDataFileFrame
22from .athena_importer import AthenaImporter
23from . import inputhook
25from larch.io import (read_ascii, read_xdi, read_gsexdi,
26 gsescan_group, fix_varname,
27 is_athena_project, AthenaProject)
28from larch.version import make_banner, version_data
29from larch.utils import get_cwd
31FILE_WILDCARDS = "Data Files(*.0*,*.dat,*.xdi)|*.0*;*.dat;*.xdi|All files (*.*)|*.*"
33ICON_FILE = 'larch.ico'
34BACKGROUND_COLOUR = '#FCFCFA'
35FOREGROUND_COLOUR = '#050520'
37FONTSIZE_FW = 14
38if platform == 'win':
39 FONTSIZE_FW = 12
40elif platform == 'darwin':
41 FONTSIZE_FW = 14
43def makeColorPanel(parent, color):
44 p = wx.Panel(parent, -1)
45 p.SetBackgroundColour(color)
46 return p
48def wx_inspect():
49 wx.GetApp().ShowInspectionTool()
51def get_font(size):
52 return wx.Font(size, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
54class LarchWxShell(object):
55 ps1 = 'Larch>'
56 ps2 = ' ... >'
57 def __init__(self, wxparent=None, writer=None, _larch=None,
58 prompt=None, historyfile=None, output=None, input=None):
59 self._larch = _larch
60 self.textstyle = None
61 self.parent = wxparent
62 self.prompt = prompt
63 self.input = input
64 self.output = output
66 if _larch is None:
67 self._larch = larch.Interpreter(historyfile=historyfile,
68 writer=self)
69 self._larch.run_init_scripts()
70 self.writer = self._larch.writer
71 self.symtable = self._larch.symtable
73 self.objtree = wxparent.objtree
75 self.set_textstyle(mode='text')
76 self._larch("_sys.display.colors['text2'] = {'color': 'blue'}",
77 add_history=False)
79 self.symtable.set_symbol('_builtin.force_wxupdate', False)
80 self.symtable.set_symbol('_sys.wx.inputhook', inputhook)
81 self.symtable.set_symbol('_sys.wx.ping', inputhook.ping)
82 self.symtable.set_symbol('_sys.wx.force_wxupdate', False)
83 self.symtable.set_symbol('_sys.wx.wx_inspect', wx_inspect)
84 self.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp())
85 self.symtable.set_symbol('_sys.wx.parent', wx.GetApp().GetTopWindow())
86 self.symtable.set_symbol('_sys.last_eval_time', 0.0)
87 self.fontsize = FONTSIZE_FW
89 if self.output is not None:
90 style = self.output.GetDefaultStyle()
91 bgcol = style.GetBackgroundColour()
92 sfont = style.GetFont()
93 sfont.Family = wx.TELETYPE
94 sfont.Weight = wx.BOLD
95 sfont.PointSize = self.fontsize
96 style.SetFont(sfont)
97 self.output.SetDefaultStyle(style)
98 self.textstyle = wx.TextAttr('black', bgcol, sfont)
99 self.SetPrompt(True)
101 def onUpdate(self, event=None):
102 symtable = self.symtable
103 if symtable.get_symbol('_builtin.force_wxupdate', create=True):
104 app = wx.GetApp()
105 evtloop = wx.EventLoop()
106 while evtloop.Pending():
107 evtloop.Dispatch()
108 app.ProcessIdle()
109 symtable.set_symbol('_builtin.force_wxupdate', False)
112 def SetPrompt(self, complete):
113 if self.prompt is None:
114 return
115 sprompt, scolor = self.ps1, '#000075'
116 if not complete:
117 sprompt, scolor = self.ps2, '#E00075'
118 self.prompt.SetLabel(sprompt)
119 self.prompt.SetForegroundColour(scolor)
120 self.prompt.Refresh()
122 def set_textstyle(self, mode='text'):
123 if self.output is None:
124 return
126 display_colors = self.symtable._sys.display.colors
128 textattrs = display_colors.get(mode, {'color':'black'})
129 color = textattrs['color']
131 style = self.output.GetDefaultStyle()
132 bgcol = BACKGROUND_COLOUR
133 sfont = self.output.GetFont()
134 style.SetFont(sfont)
135 self.output.SetDefaultStyle(style)
136 self.textstyle = wx.TextAttr(color, bgcol, sfont)
138 def write_sys(self, text):
139 sys.stdout.write(text)
140 sys.stdout.flush()
142 def write(self, text, **kws):
143 if text is None:
144 return
145 if self.textstyle is None:
146 self.set_textstyle()
148 if self.output is None or self.textstyle is None:
149 self.write_sys(text)
150 else:
151 self.output.SetInsertionPointEnd()
152 pos0 = self.output.GetLastPosition()
153 self.output.WriteText(text)
154 pos1 = self.output.GetLastPosition()
155 self.output.SetStyle(pos0, pos1, self.textstyle)
156 self.output.SetInsertionPoint(pos1)
157 self.output.Refresh()
158 wx.CallAfter(self.input.SetFocus)
160 def flush(self, *args):
161 self.output.Refresh()
162 self.needs_flush = False
164 def clear_input(self):
165 self._larch.input.clear()
166 self.SetPrompt(True)
168 def onFlushTimer(self, event=None):
169 if self.needs_flush:
170 self.flush()
172 def eval(self, text, add_history=True, **kws):
173 if text is None:
174 return
175 if text.startswith('!'):
176 return os.system(text[1:])
178 elif text.startswith('help(') and text.endswith(')'):
179 topic = text[5:-1]
180 parent = self.symtable.get_parentpath(topic)
181 self.objtree.ShowNode("%s.%s" % (parent, topic))
182 return
183 else:
184 if add_history:
185 self.parent.AddToHistory(text)
186 self.write("%s\n" % text)
187 ret = self._larch.eval(text, add_history=add_history)
188 if self._larch.error:
189 self._larch.input.clear()
190 self._larch.writer.set_textstyle('error')
191 self._larch.show_errors()
192 self._larch.writer.set_textstyle('text')
193 elif ret is not None:
194 self._larch.writer.write("%s\n" % repr(ret))
195 try:
196 self.objtree.onRefresh()
197 except ValueError:
198 pass
199 self.symtable._sys.last_eval_time = time.time()
200 self.SetPrompt(self._larch.input.complete)
201 return ret
203class LarchPanel(wx.Panel):
204 """Larch Input/Output Panel + Data Viewer as a wx.Panel,
205 suitable for embedding into apps
206 """
207 def __init__(self, parent=None, _larch=None, font=None,
208 historyfile='history_larchgui.lar', **kwds):
209 self.parent = parent
210 if not historyfile.startswith(larch.site_config.user_larchdir):
211 historyfile = os.path.join(larch.site_config.user_larchdir,
212 historyfile)
214 wx.Panel.__init__(self, parent, -1, size=(750, 725))
216 self.splitter = splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
217 splitter.SetMinimumPaneSize(150)
219 self.objtree = Filling(splitter, rootLabel='_main',
220 fgcol=FOREGROUND_COLOUR, bgcol=BACKGROUND_COLOUR)
222 self.output = wx.TextCtrl(splitter, -1, '',
223 style=wx.TE_MULTILINE|wx.TE_RICH|wx.TE_READONLY)
225 self.output.SetBackgroundColour(BACKGROUND_COLOUR)
226 self.output.SetForegroundColour(FOREGROUND_COLOUR)
227 if font is None:
228 font = get_font(self.fontsize)
230 self.output.SetFont(font)
231 self.objtree.tree.SetFont(font)
232 self.objtree.text.SetFont(font)
234 self.output.CanCopy()
235 self.output.SetInsertionPointEnd()
236 splitter.SplitHorizontally(self.objtree, self.output, 0)
238 ipanel = wx.Panel(self)
240 self.prompt = wx.StaticText(ipanel, label='Larch>', size=(75,-1),
241 style=wx.ALIGN_CENTER|wx.ALIGN_RIGHT)
243 self.input = wx.TextCtrl(ipanel, value='', size=(525,-1),
244 style=wx.TE_LEFT|wx.TE_PROCESS_ENTER)
246 self.input.Bind(wx.EVT_TEXT_ENTER, self.onText)
247 if sys.platform == 'darwin':
248 self.input.Bind(wx.EVT_KEY_UP, self.onChar)
249 else:
250 self.input.Bind(wx.EVT_CHAR, self.onChar)
252 self.hist_buff = []
253 self.hist_mark = 0
255 isizer = wx.BoxSizer(wx.HORIZONTAL)
256 isizer.Add(self.prompt, 0, wx.BOTTOM|wx.CENTER)
257 isizer.Add(self.input, 1, wx.ALIGN_LEFT|wx.EXPAND)
259 ipanel.SetSizer(isizer)
260 isizer.Fit(ipanel)
262 opts = dict(flag=wx.ALL|wx.EXPAND, border=2)
263 sizer = wx.BoxSizer(wx.VERTICAL)
264 sizer.Add(splitter, 1, **opts)
265 sizer.Add(ipanel, 0, **opts)
267 self.SetSizer(sizer)
268 self.larchshell = LarchWxShell(wxparent=self,
269 _larch = _larch,
270 historyfile=historyfile,
271 prompt = self.prompt,
272 output = self.output,
273 input = self.input)
275 self.objtree.SetRootObject(self.larchshell.symtable)
276 # root = self.objtree.tree.GetRootItem()
279 def write_banner(self):
280 self.larchshell.set_textstyle('text2')
281 self.larchshell.write(make_banner(show_libraries=['numpy', 'scipy', 'matplotlib', 'h5py',
282 'lmfit', 'xraydb', 'wx','wxmplot']))
283 self.larchshell.write("\n \n")
284 self.larchshell.set_textstyle('text')
286 def update(self):
287 self.objtree.onRefresh()
289 def onText(self, event=None):
290 text = event.GetString()
291 self.input.Clear()
292 if text.lower() in ('quit', 'exit', 'quit()', 'exit()'):
293 if self.parent.exit_on_close:
294 self.parent.onExit()
295 else:
296 wx.CallAfter(self.larchshell.eval, text)
298 def onChar(self, event=None):
299 key = event.GetKeyCode()
301 entry = self.input.GetValue().strip()
302 pos = self.input.GetSelection()
303 ctrl = event.ControlDown()
305 if key == wx.WXK_RETURN and len(entry) > 0:
306 pass
307 if key in (wx.WXK_UP, wx.WXK_DOWN):
308 if key == wx.WXK_UP:
309 self.hist_mark = max(0, self.hist_mark-1)
310 else:
311 self.hist_mark += 1
312 try:
313 wx.CallAfter(self.set_input_text, self.hist_buff[self.hist_mark])
314 except IndexError:
315 wx.CallAfter(self.set_input_text, '')
316 event.Skip()
318 def set_input_text(self, text):
319 self.input.SetValue(text)
320 self.input.SetFocus()
321 self.input.SetInsertionPointEnd()
324 def AddToHistory(self, text=''):
325 for tline in text.split('\n'):
326 if len(tline.strip()) > 0:
327 self.hist_buff.append(tline)
328 self.hist_mark = len(self.hist_buff)
331class LarchFrame(wx.Frame):
332 def __init__(self, parent=None, _larch=None, is_standalone=True,
333 historyfile='history_larchgui.lar', with_inspection=False,
334 exit_on_close=False, with_raise=True, **kwds):
336 self.is_standalone = is_standalone
337 self.with_inspection = with_inspection
338 self.exit_on_close = exit_on_close
339 self.parent = parent
340 self.historyfile = historyfile
341 self.subframes = {}
342 self.last_array_sel = {}
343 self.fontsize = FONTSIZE_FW
345 wx.Frame.__init__(self, parent, -1, size=(800, 725),
346 style= wx.DEFAULT_FRAME_STYLE)
347 self.SetTitle('LarchGUI')
349 self.font = get_font(self.fontsize)
350 self.SetFont(self.font)
351 sbar = self.CreateStatusBar(2, wx.CAPTION)
353 self.SetStatusWidths([-2,-1])
354 self.SetStatusText("Larch initializing...", 0)
356 self.mainpanel = LarchPanel(parent=self, _larch=_larch,
357 historyfile=historyfile,
358 font=self.font)
360 self.larchshell = self.mainpanel.larchshell
361 self._larch = self.larchshell._larch
363 sizer = wx.BoxSizer(wx.VERTICAL)
365 sizer.Add(self.mainpanel, 1, wx.ALL|wx.EXPAND)
367 self.SetSizer(sizer)
369 self.Bind(wx.EVT_SHOW, self.onShow)
370 self.BuildMenus()
371 self.onSelectFont(fsize=self.fontsize)
372 # larchdir = larch.site_config.larchdir
374 fico = os.path.join(larch.site_config.icondir, ICON_FILE)
375 if os.path.exists(fico):
376 self.SetIcon(wx.Icon(fico, wx.BITMAP_TYPE_ICO))
377 self.mainpanel.write_banner()
378 if with_raise:
379 self.Raise()
381 def Raise(self):
382 self.SetStatusText("Ready", 0)
383 self.Refresh()
384 wx.Frame.Raise(self)
386 def BuildMenus(self):
387 menuBar = wx.MenuBar()
389 fmenu = wx.Menu()
390 if self.is_standalone:
391 MenuItem(self, fmenu, "&Read Data File\tCtrl+O",
392 "Read Data File", self.onReadData)
393 MenuItem(self, fmenu, "&Read and Run Larch Script\tCtrl+R",
394 "Read and Execute a Larch Script", self.onRunScript)
395 MenuItem(self, fmenu, "&Save Session History\tCtrl+S",
396 "Save Session History to File", self.onSaveHistory)
397 MenuItem(self, fmenu, 'Change Working Directory\tCtrl+W',
398 'Change Directory', self.onChangeDir)
399 MenuItem(self, fmenu, 'Clear Input\tCtrl+D',
400 'Clear Input', self.onClearInput)
402 if self.with_inspection:
403 MenuItem(self, fmenu, 'Show wxPython Inspector\tCtrl+I',
404 'Debug wxPython App', self.onWxInspect)
405 fmenu.AppendSeparator()
407 if self.parent is None and self.exit_on_close:
408 self.Bind(wx.EVT_CLOSE, self.onExit)
409 MenuItem(self, fmenu, 'E&xit', 'End program',
410 self.onExit)
411 else:
412 self.Bind(wx.EVT_CLOSE, self.onClose)
413 MenuItem(self, fmenu, 'Close Display',
414 'Close display', self.onClose)
416 menuBar.Append(fmenu, '&File')
418 _sys = self.larchshell.symtable._sys
419 if self.is_standalone and hasattr(_sys, 'gui_apps'):
420 appmenu = wx.Menu()
421 x_apps = _sys.gui_apps.keys()
422 for appname in sorted(x_apps):
423 label, creator = _sys.gui_apps[appname]
425 MenuItem(self, appmenu, label, label,
426 partial(self.show_subframe,
427 name=appname, creator=creator))
428 menuBar.Append(appmenu, 'Applications')
430 fsmenu = wx.Menu()
431 self.fontsizes = {}
432 for fsize in (10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24):
433 m = MenuItem(self, fsmenu, "%d" % fsize, "%d" % fsize,
434 self.onSelectFont, kind=wx.ITEM_RADIO)
435 self.fontsizes[m.GetId()] = fsize
436 if fsize == self.fontsize:
437 m.Check()
439 menuBar.Append(fsmenu, 'Font Size')
441 hmenu = wx.Menu()
442 MenuItem(self, hmenu, '&About',
443 'Information about this program', self.onAbout)
444 MenuItem(self, hmenu, '&Versions',
445 'Show versions of Larch and libraries', self.onVersions)
446 menuBar.Append(hmenu, '&Help')
447 self.SetMenuBar(menuBar)
449 def onSelectFont(self, event=None, fsize=None):
450 if fsize is None:
451 fsize = self.fontsizes.get(event.GetId(), self.fontsize)
452 self.fontsize = fsize
454 def set_fontsize(obj, fsize):
455 fn = obj.GetFont()
456 f1, f2 = fn.PixelSize
457 fn.SetPixelSize(wx.Size(int((f1*fsize/f2)), fsize))
458 obj.SetFont(fn)
460 self.PointSize = fsize
461 set_fontsize(self, fsize)
462 set_fontsize(self.mainpanel.output, fsize)
463 set_fontsize(self.mainpanel.objtree.tree, fsize)
464 set_fontsize(self.mainpanel.objtree.text, fsize)
465 self.mainpanel.objtree.text.fontsize = fsize
469 def onWxInspect(self, event=None):
470 wx.GetApp().ShowInspectionTool()
472 def onXRFviewer(self, event=None):
473 self.larchshell.eval("xrf_plot()")
475 def onClearInput(self, event=None):
476 self.larchshell.clear_input()
478 def onClearInput(self, event=None):
479 self.larchshell.clear_input()
481 def show_subframe(self, event=None, name=None, creator=None, **opts):
482 if name is None or creator is None:
483 return
484 shown = False
485 if name in self.subframes:
486 try:
487 self.subframes[name].Raise()
488 shown = True
489 except:
490 del self.subframes[name]
491 if not shown:
492 self.subframes[name] = creator(parent=self,
493 _larch=self.larchshell._larch,
494 **opts)
495 self.subframes[name].Show()
497 def onReadData(self, event=None):
498 wildcard = 'Data file (*.dat)|*.dat|All files (*.*)|*.*'
499 dlg = wx.FileDialog(self, message='Open Data File',
500 defaultDir=get_cwd(),
501 wildcard=FILE_WILDCARDS,
502 style=wx.FD_OPEN|wx.FD_CHANGE_DIR)
503 path = None
504 if dlg.ShowModal() == wx.ID_OK:
505 path = os.path.abspath(dlg.GetPath()).replace('\\', '/')
506 dlg.Destroy()
508 if path is None:
509 return
511 if is_athena_project(path):
512 self.show_subframe(name='athena_import', filename=path,
513 creator=AthenaImporter,
514 read_ok_cb=self.onReadAthenaProject_OK)
515 else:
516 filedir, filename = os.path.split(path)
517 pref = fix_varname((filename + '_'*8)[:8]).replace('.', '_').lower()
519 count, maxcount = 1, 9999
520 groupname = "%s%3.3i" % (pref, count)
521 while hasattr(self.larchshell.symtable, groupname) and count < maxcount:
522 count += 1
523 groupname = '%s%3.3i' % (pref, count)
525 fh = open(path, 'r')
526 line1 = fh.readline().lower()
527 fh.close()
528 reader = read_ascii
529 if 'epics stepscan file' in line1:
530 reader = read_gsexdi
531 elif 'epics scan' in line1:
532 reader = gsescan_group
533 elif 'xdi' in line1:
534 reader = read_xdi
536 dgroup = reader(str(path), _larch=self.larchshell._larch)
537 dgroup._path = path
538 dgroup._filename = filename
539 dgroup._groupname = groupname
540 self.show_subframe(name='coledit', event=None,
541 creator=ColumnDataFileFrame,
542 filename=path,
543 last_array_sel=self.last_array_sel,
544 read_ok_cb=self.onReadScan_Success)
547 def onReadScan_Success(self, script, path, groupname=None, array_sel=None,
548 overwrite=False):
549 """ called when column data has been selected and is ready to be used"""
550 self.larchshell.eval(script.format(group=groupname, path=path))
551 if array_sel is not None:
552 self.last_array_sel = array_sel
553 self.larchshell.flush()
555 def onReadAthenaProject_OK(self, path, namelist):
556 """read groups from a list of groups from an athena project file"""
557 read_cmd = "_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)"
558 self.larchshell.eval(read_cmd.format(path=path))
559 dgroup = None
560 script = "{group:s} = extract_athenagroup(_prj.{prjgroup:s})"
561 for gname in namelist:
562 this = getattr(self.larchshell.symtable._prj, gname)
563 gid = str(getattr(this, 'athena_id', gname))
564 self.larchshell.eval(script.format(group=gid, prjgroup=gname))
565 self.larchshell.eval("del _prj")
567 def onRunScript(self, event=None):
568 wildcard = 'Larch file (*.lar)|*.lar|All files (*.*)|*.*'
569 dlg = wx.FileDialog(self, message='Open and Run Larch Script',
570 wildcard=wildcard,
571 style=wx.FD_OPEN|wx.FD_CHANGE_DIR)
572 if dlg.ShowModal() == wx.ID_OK:
573 fout = os.path.abspath(dlg.GetPath())
574 path, fname = os.path.split(fout)
575 os.chdir(path)
576 text = "run('%s')" % fname
577 self.larchshell.write("%s\n" % text)
578 wx.CallAfter(self.larchshell.eval, text)
579 dlg.Destroy()
581 def onSaveHistory(self, event=None):
582 wildcard = 'Larch file (*.lar)|*.lar|All files (*.*)|*.*'
583 deffile = 'history.lar'
584 dlg = wx.FileDialog(self, message='Save Session History File',
585 wildcard=wildcard,
586 defaultFile=deffile,
587 style=wx.FD_SAVE|wx.FD_CHANGE_DIR)
588 if dlg.ShowModal() == wx.ID_OK:
589 fout = os.path.abspath(dlg.GetPath())
590 self._larch.input.history.save(fout, session_only=True)
591 self.SetStatusText("Wrote %s" % fout, 0)
592 dlg.Destroy()
594 def onText(self, event=None):
595 text = event.GetString()
596 self.larchshell.write("%s\n" % text)
597 self.input.Clear()
598 if text.lower() in ('quit', 'exit', 'quit()', 'exit()'):
599 if self.exit_on_close:
600 self.onExit()
601 else:
602 self.panel.AddToHistory(text)
603 wx.CallAfter(self.larchshell.eval, text)
605 def onChangeDir(self, event=None):
606 dlg = wx.DirDialog(None, 'Choose a Working Directory',
607 defaultPath = get_cwd(),
608 style = wx.DD_DEFAULT_STYLE)
610 if dlg.ShowModal() == wx.ID_OK:
611 os.chdir(dlg.GetPath())
612 dlg.Destroy()
613 return get_cwd()
615 def onAbout(self, event=None):
616 about_msg = """LarchGui:
617 %s""" % (make_banner(withlibraries=True))
619 dlg = wx.MessageDialog(self, about_msg,
620 "About LarchGui", wx.OK | wx.ICON_INFORMATION)
621 dlg.ShowModal()
622 dlg.Destroy()
624 def onVersions(self, event=None):
625 vdat = version_data(with_libraries=True)
626 out = []
627 for key, val in vdat.items():
628 out.append(f"{key:20s}: {val}")
629 version_message = '\n'.join(out)
630 dlg = wx.Dialog(self, wx.ID_ANY, size=(700, 400),
631 title='Larch Versions')
633 font = get_font(self.fontsize)
634 dlg.SetFont(font)
635 panel = wx.Panel(dlg)
636 txt = wx.StaticText(panel, label=version_message)
637 s = wx.Sizer
638 sizer = wx.BoxSizer(wx.VERTICAL)
639 sizer.Add(txt, 1, wx.LEFT|wx.ALL, 5)
640 panel.SetSizer(sizer)
641 panel_pack(dlg, panel)
642 dlg.Show()
644 def onShow(self, event=None):
645 if event.Show:
646 self.mainpanel.update()
648 def onClose(self, event=None):
649 try:
650 self.Hide()
651 except:
652 pass
654 def onExit(self, event=None, force=False, with_sysexit=True):
655 if not self.exit_on_close:
656 self.Hide()
657 return
658 if force:
659 ret = wx.ID_YES
660 else:
661 dlg = wx.MessageDialog(None, 'Really Quit?', 'Question',
662 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
663 ret = dlg.ShowModal()
665 if ret == wx.ID_YES:
666 try:
667 self._larch.input.history.save()
668 except:
669 pass
670 try:
671 try:
672 for a in self.GetChildren():
673 a.Destroy()
674 except:
675 pass
676 self.Destroy()
678 except:
679 pass
680 if with_sysexit:
681 sys.exit()
682 else:
683 try:
684 event.Veto()
685 except:
686 pass
688class LarchApp(LarchWxApp):
689 "simple app to wrap LarchFrame"
690 def __init__(self, with_inspection=False, **kws):
691 self.with_inspection = with_inspection
692 LarchWxApp.__init__(self, **kws)
694 def createApp(self):
695 frame = LarchFrame(exit_on_close=True, with_inspection=self.with_inspection)
696 frame.Show()
697 self.SetTopWindow(frame)
698 return True
700if __name__ == '__main__':
701 LarchApp().MainLoop()