2 #----------------------------------------------------------------------------
4 # Purpose: Testing lots of stuff, controls, window types, etc.
8 # Created: A long time ago, in a galaxy far, far away...
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
15 # * Problems with flickering related to ERASE_BACKGROUND
16 # and the splitters. Might be a problem with this 2.5 beta...?
17 # UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
19 # * Annoying switching between tabs and resulting flicker
20 # how to replace a page in the notebook without deleting/adding?
21 # Where is SetPage!? tried freeze...tried reparent of dummy panel....
24 # * UI design more prefessional
25 # * save file positions (new field in demoModules) (@ LoadDemoSource)
26 # * Update main overview
28 # * Why don't we move _treeList into a separate module
30 import sys
, os
, time
, traceback
, types
32 import wx
# This module uses the new wx namespace
39 ##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40 ##print "pid:", os.getpid()
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
52 # managed windows == things with a (optional) caption you can close
53 ('Frames and Dialogs', [
54 'AUI_DockingWindowMgr',
80 # dialogs from libraries
83 'ScrolledMessageDialog',
87 ('Core Windows/Controls', [
125 ('"Book" Controls', [
134 ('Custom Controls', [
151 # controls coming from other libraries
152 ('More Windows/Controls', [
153 'ActiveX_FlashWindow',
154 'ActiveX_IEHtmlWindow',
159 'CheckListCtrlMixin',
176 'MaskedEditControls',
179 'MultiSplitterWindow',
180 'OwnerDrawnComboBox',
198 # How to lay out the controls in a frame/dialog
209 'XmlResourceHandler',
210 'XmlResourceSubclass',
214 ('Process and Events', [
222 ##'infoframe', # needs better explanation and some fixing
226 ('Clipboard and DnD', [
253 ##'DialogUnits', # needs more explanations
274 ('Check out the samples dir too', [
281 #---------------------------------------------------------------------------
282 # Show how to derive a custom wxLog class
284 class MyLog(wx
.PyLog
):
285 def __init__(self
, textCtrl
, logTime
=0):
286 wx
.PyLog
.__init
__(self
)
288 self
.logTime
= logTime
290 def DoLogString(self
, message
, timeStamp
):
291 #print message, timeStamp
293 # message = time.strftime("%X", time.localtime(timeStamp)) + \
296 self
.tc
.AppendText(message
+ '\n')
299 class MyTP(wx
.PyTipProvider
):
301 return "This is my tip"
303 #---------------------------------------------------------------------------
304 # A class to be used to simply display a message in the demo pane
305 # rather than running the sample itself.
307 class MessagePanel(wx
.Panel
):
308 def __init__(self
, parent
, message
, caption
='', flags
=0):
309 wx
.Panel
.__init
__(self
, parent
)
314 if flags
& wx
.ICON_EXCLAMATION
:
315 artid
= wx
.ART_WARNING
316 elif flags
& wx
.ICON_ERROR
:
318 elif flags
& wx
.ICON_QUESTION
:
319 artid
= wx
.ART_QUESTION
320 elif flags
& wx
.ICON_INFORMATION
:
321 artid
= wx
.ART_INFORMATION
323 if artid
is not None:
324 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
325 icon
= wx
.StaticBitmap(self
, -1, bmp
)
327 icon
= (32,32) # make a spacer instead
330 caption
= wx
.StaticText(self
, -1, caption
)
331 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
333 message
= wx
.StaticText(self
, -1, message
)
335 # add to sizers for layout
336 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
342 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
349 box
= wx
.BoxSizer(wx
.VERTICAL
)
351 box
.Add(hbox
, 0, wx
.EXPAND
)
358 #---------------------------------------------------------------------------
359 # A class to be used to display source code in the demo. Try using the
360 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
361 # if there is an error, such as the stc module not being present.
365 ##raise ImportError # for testing the alternate implementation
367 from StyledTextCtrl_2
import PythonSTC
369 class DemoCodeEditor(PythonSTC
):
370 def __init__(self
, parent
):
371 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
374 # Some methods to make it compatible with how the wxTextCtrl is used
375 def SetValue(self
, value
):
377 value
= value
.decode('iso8859_1')
379 self
.EmptyUndoBuffer()
382 def IsModified(self
):
383 return self
.GetModify()
388 def SetInsertionPoint(self
, pos
):
389 self
.SetCurrentPos(pos
)
392 def ShowPosition(self
, pos
):
393 line
= self
.LineFromPosition(pos
)
394 #self.EnsureVisible(line)
397 def GetLastPosition(self
):
398 return self
.GetLength()
400 def GetPositionFromLine(self
, line
):
401 return self
.PositionFromLine(line
)
403 def GetRange(self
, start
, end
):
404 return self
.GetTextRange(start
, end
)
406 def GetSelection(self
):
407 return self
.GetAnchor(), self
.GetCurrentPos()
409 def SetSelection(self
, start
, end
):
410 self
.SetSelectionStart(start
)
411 self
.SetSelectionEnd(end
)
413 def SelectLine(self
, line
):
414 start
= self
.PositionFromLine(line
)
415 end
= self
.GetLineEndPosition(line
)
416 self
.SetSelection(start
, end
)
418 def SetUpEditor(self
):
420 This method carries out the work of setting up the demo editor.
421 It's seperate so as not to clutter up the init code.
425 self
.SetLexer(stc
.STC_LEX_PYTHON
)
426 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
429 self
.SetProperty("fold", "1" )
431 # Highlight tab/space mixing (shouldn't be any)
432 self
.SetProperty("tab.timmy.whinge.level", "1")
434 # Set left and right margins
437 # Set up the numbers in the margin for margin #1
438 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
439 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
440 self
.SetMarginWidth(1, 40)
442 # Indentation and tab stuff
443 self
.SetIndent(4) # Proscribed indent size for wx
444 self
.SetIndentationGuides(True) # Show indent guides
445 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
446 self
.SetTabIndents(True) # Tab key indents
447 self
.SetTabWidth(4) # Proscribed tab size for wx
448 self
.SetUseTabs(False) # Use spaces rather than tabs, or
449 # TabTimmy will complain!
451 self
.SetViewWhiteSpace(False) # Don't view white space
453 # EOL: Since we are loading/saving ourselves, and the
454 # strings will always have \n's in them, set the STC to
455 # edit them that way.
456 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
457 self
.SetViewEOL(False)
459 # No right-edge mode indicator
460 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
462 # Setup a margin to hold fold markers
463 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
464 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
465 self
.SetMarginSensitive(2, True)
466 self
.SetMarginWidth(2, 12)
468 # and now set up the fold markers
469 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
470 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
471 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
472 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
473 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
474 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
475 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
477 # Global default style
478 if wx
.Platform
== '__WXMSW__':
479 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
480 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
481 elif wx
.Platform
== '__WXMAC__':
482 # TODO: if this looks fine on Linux too, remove the Mac-specific case
483 # and use this whenever OS != MSW.
484 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
485 'fore:#000000,back:#FFFFFF,face:Courier')
487 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
488 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
490 # Clear styles and revert to default.
493 # Following style specs only indicate differences from default.
494 # The rest remains unchanged.
496 # Line numbers in margin
497 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
499 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
501 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
503 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
506 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
508 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
509 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
511 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
512 # Strings and characters
513 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
514 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
516 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
518 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
519 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
521 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
523 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
525 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
526 # Identifiers. I leave this as not bold because everything seems
527 # to be an identifier if it doesn't match the above criterae
528 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
531 self
.SetCaretForeground("BLUE")
532 # Selection background
533 self
.SetSelBackground(1, '#66CCFF')
535 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
536 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
538 def RegisterModifiedEvent(self
, eventHandler
):
539 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
543 class DemoCodeEditor(wx
.TextCtrl
):
544 def __init__(self
, parent
):
545 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
546 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
548 def RegisterModifiedEvent(self
, eventHandler
):
549 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
551 def SetReadOnly(self
, flag
):
552 self
.SetEditable(not flag
)
553 # NOTE: STC already has this method
556 return self
.GetValue()
558 def GetPositionFromLine(self
, line
):
559 return self
.XYToPosition(0,line
)
561 def GotoLine(self
, line
):
562 pos
= self
.GetPositionFromLine(line
)
563 self
.SetInsertionPoint(pos
)
564 self
.ShowPosition(pos
)
566 def SelectLine(self
, line
):
567 start
= self
.GetPositionFromLine(line
)
568 end
= start
+ self
.GetLineLength(line
)
569 self
.SetSelection(start
, end
)
572 #---------------------------------------------------------------------------
573 # Constants for module versions
577 modDefault
= modOriginal
579 #---------------------------------------------------------------------------
581 class DemoCodePanel(wx
.Panel
):
582 """Panel for the 'Demo Code' tab"""
583 def __init__(self
, parent
, mainFrame
):
584 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
585 if 'wxMSW' in wx
.PlatformInfo
:
587 self
.mainFrame
= mainFrame
588 self
.editor
= DemoCodeEditor(self
)
589 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
591 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
592 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
593 self
.btnSave
.Enable(False)
594 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
595 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
597 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
598 modModified
: wx
.RadioButton(self
, -1, "Modified") }
600 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
601 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
602 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
603 for modID
, radioButton
in self
.radioButtons
.items():
604 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
605 radioButton
.modID
= modID
# makes it easier for the event handler
606 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
608 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
609 self
.controlBox
.Add(self
.btnRestore
, 0)
611 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
612 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
613 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
614 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
617 self
.SetSizer(self
.box
)
620 # Loads a demo from a DemoModules object
621 def LoadDemo(self
, demoModules
):
622 self
.demoModules
= demoModules
623 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
624 demoModules
.SetActive(modModified
)
626 demoModules
.SetActive(modOriginal
)
627 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
628 self
.ActiveModuleChanged()
631 def ActiveModuleChanged(self
):
632 self
.LoadDemoSource(self
.demoModules
.GetSource())
633 self
.UpdateControlState()
637 def LoadDemoSource(self
, source
):
639 self
.editor
.SetValue(source
)
641 self
.btnSave
.Enable(False)
644 def JumpToLine(self
, line
, highlight
=False):
645 self
.editor
.GotoLine(line
)
646 self
.editor
.SetFocus()
648 self
.editor
.SelectLine(line
)
651 def UpdateControlState(self
):
652 active
= self
.demoModules
.GetActiveID()
653 # Update the radio/restore buttons
654 for moduleID
in self
.radioButtons
:
655 btn
= self
.radioButtons
[moduleID
]
656 if moduleID
== active
:
661 if self
.demoModules
.Exists(moduleID
):
663 if moduleID
== modModified
:
664 self
.btnRestore
.Enable(True)
667 if moduleID
== modModified
:
668 self
.btnRestore
.Enable(False)
671 def OnRadioButton(self
, event
):
672 radioSelected
= event
.GetEventObject()
673 modSelected
= radioSelected
.modID
674 if modSelected
!= self
.demoModules
.GetActiveID():
675 busy
= wx
.BusyInfo("Reloading demo module...")
676 self
.demoModules
.SetActive(modSelected
)
677 self
.ActiveModuleChanged()
680 def ReloadDemo(self
):
681 if self
.demoModules
.name
!= __name__
:
682 self
.mainFrame
.RunModule()
685 def OnCodeModified(self
, event
):
686 self
.btnSave
.Enable(self
.editor
.IsModified())
689 def OnSave(self
, event
):
690 if self
.demoModules
.Exists(modModified
):
691 if self
.demoModules
.GetActiveID() == modOriginal
:
692 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
693 "Do you want to continue?"
694 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
695 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
696 result
= dlg
.ShowModal()
697 if result
== wx
.ID_NO
:
701 self
.demoModules
.SetActive(modModified
)
702 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
704 # Create the demo directory if one doesn't already exist
705 if not os
.path
.exists(GetModifiedDirectory()):
707 os
.makedirs(GetModifiedDirectory())
708 if not os
.path
.exists(GetModifiedDirectory()):
709 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
712 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
715 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
718 f
= open(modifiedFilename
, "wt")
719 source
= self
.editor
.GetText()
725 busy
= wx
.BusyInfo("Reloading demo module...")
726 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
727 self
.ActiveModuleChanged()
730 def OnRestore(self
, event
): # Handles the "Delete Modified" button
731 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
732 self
.demoModules
.Delete(modModified
)
733 os
.unlink(modifiedFilename
) # Delete the modified copy
734 busy
= wx
.BusyInfo("Reloading demo module...")
735 self
.ActiveModuleChanged()
738 #---------------------------------------------------------------------------
741 """Convert paths to the platform-specific separator"""
742 str = apply(os
.path
.join
, tuple(path
.split('/')))
743 # HACK: on Linux, a leading / gets lost...
744 if path
.startswith('/'):
749 def GetModifiedDirectory():
751 Returns the directory where modified versions of the demo files
754 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
757 def GetModifiedFilename(name
):
759 Returns the filename of the modified version of the specified demo
761 if not name
.endswith(".py"):
763 return GetModifiedDirectory() + name
766 def GetOriginalFilename(name
):
768 Returns the filename of the original version of the specified demo
770 if not name
.endswith(".py"):
775 def DoesModifiedExist(name
):
776 """Returns whether the specified demo has a modified copy"""
777 if os
.path
.exists(GetModifiedFilename(name
)):
783 #---------------------------------------------------------------------------
785 class ModuleDictWrapper
:
786 """Emulates a module with a dynamically compiled __dict__"""
787 def __init__(self
, dict):
790 def __getattr__(self
, name
):
791 if name
in self
.dict:
792 return self
.dict[name
]
798 Dynamically manages the original/modified versions of a demo
801 def __init__(self
, name
):
805 # (dict , source , filename , description , error information )
806 # ( 0 , 1 , 2 , 3 , 4 )
807 self
.modules
= [[None, "" , "" , "<original>" , None],
808 [None, "" , "" , "<modified>" , None]]
810 # load original module
811 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
812 self
.SetActive(modOriginal
)
814 # load modified module (if one exists)
815 if DoesModifiedExist(name
):
816 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
819 def LoadFromFile(self
, modID
, filename
):
820 self
.modules
[modID
][2] = filename
821 file = open(filename
, "rt")
822 self
.LoadFromSource(modID
, file.read())
826 def LoadFromSource(self
, modID
, source
):
827 self
.modules
[modID
][1] = source
831 def LoadDict(self
, modID
):
832 if self
.name
!= __name__
:
833 source
= self
.modules
[modID
][1]
834 #description = self.modules[modID][3]
835 description
= self
.modules
[modID
][2]
838 self
.modules
[modID
][0] = {}
839 code
= compile(source
, description
, "exec")
840 exec code
in self
.modules
[modID
][0]
842 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
843 self
.modules
[modID
][0] = None
845 self
.modules
[modID
][4] = None
848 def SetActive(self
, modID
):
849 if modID
!= modOriginal
and modID
!= modModified
:
852 self
.modActive
= modID
856 dict = self
.modules
[self
.modActive
][0]
860 return ModuleDictWrapper(dict)
863 def GetActiveID(self
):
864 return self
.modActive
867 def GetSource(self
, modID
= None):
869 modID
= self
.modActive
870 return self
.modules
[modID
][1]
873 def GetFilename(self
, modID
= None):
875 modID
= self
.modActive
876 return self
.modules
[self
.modActive
][2]
879 def GetErrorInfo(self
, modID
= None):
881 modID
= self
.modActive
882 return self
.modules
[self
.modActive
][4]
885 def Exists(self
, modID
):
886 return self
.modules
[modID
][1] != ""
889 def UpdateFile(self
, modID
= None):
890 """Updates the file from which a module was loaded
891 with (possibly updated) source"""
893 modID
= self
.modActive
895 source
= self
.modules
[modID
][1]
896 filename
= self
.modules
[modID
][2]
899 file = open(filename
, "wt")
905 def Delete(self
, modID
):
906 if self
.modActive
== modID
:
909 self
.modules
[modID
][0] = None
910 self
.modules
[modID
][1] = ""
911 self
.modules
[modID
][2] = ""
914 #---------------------------------------------------------------------------
917 """Wraps and stores information about the current exception"""
918 def __init__(self
, exc_info
):
921 excType
, excValue
= exc_info
[:2]
922 # traceback list entries: (filename, line number, function name, text)
923 self
.traceback
= traceback
.extract_tb(exc_info
[2])
925 # --Based on traceback.py::format_exception_only()--
926 if type(excType
) == types
.ClassType
:
927 self
.exception_type
= excType
.__name
__
929 self
.exception_type
= excType
931 # If it's a syntax error, extra information needs
932 # to be added to the traceback
933 if excType
is SyntaxError:
935 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
940 filename
= "<string>"
942 self
.traceback
.append( (filename
, lineno
, "", line
) )
945 self
.exception_details
= str(excValue
)
947 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
954 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
957 #---------------------------------------------------------------------------
959 class DemoErrorPanel(wx
.Panel
):
960 """Panel put into the demo tab when the demo fails to run due to errors"""
962 def __init__(self
, parent
, codePanel
, demoError
, log
):
963 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
964 self
.codePanel
= codePanel
968 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
971 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
972 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
974 # Exception Information
975 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
976 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
977 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
978 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
979 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
980 boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 )
981 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
982 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
983 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
984 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
986 # Set up the traceback list
987 # This one automatically resizes last column to take up remaining space
988 from ListCtrl
import TestListCtrl
989 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
990 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
991 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
992 self
.list.InsertColumn(0, "Filename")
993 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
994 self
.list.InsertColumn(2, "Function")
995 self
.list.InsertColumn(3, "Code")
996 self
.InsertTraceback(self
.list, demoError
.traceback
)
997 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
998 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
999 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1000 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1001 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1002 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1003 + "Double-click on them to go to the offending line")
1004 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1007 self
.SetSizer(self
.box
)
1010 def InsertTraceback(self
, list, traceback
):
1011 #Add the traceback data
1012 for x
in range(len(traceback
)):
1014 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1015 list.SetStringItem(x
, 1, str(data
[1])) # Line
1016 list.SetStringItem(x
, 2, str(data
[2])) # Function
1017 list.SetStringItem(x
, 3, str(data
[3])) # Code
1019 # Check whether this entry is from the demo module
1020 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1021 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1022 # Give it a blue colour
1023 item
= self
.list.GetItem(x
)
1024 item
.SetTextColour(wx
.BLUE
)
1025 self
.list.SetItem(item
)
1027 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1030 def OnItemSelected(self
, event
):
1031 # This occurs before OnDoubleClick and can be used to set the
1032 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1033 self
.currentItem
= event
.m_itemIndex
1037 def OnDoubleClick(self
, event
):
1038 # If double-clicking on a demo's entry, jump to the line number
1039 line
= self
.list.GetItemData(self
.currentItem
)
1041 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1042 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1046 #---------------------------------------------------------------------------
1048 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1049 TBMENU_RESTORE
= wx
.NewId()
1050 TBMENU_CLOSE
= wx
.NewId()
1051 TBMENU_CHANGE
= wx
.NewId()
1052 TBMENU_REMOVE
= wx
.NewId()
1054 def __init__(self
, frame
):
1055 wx
.TaskBarIcon
.__init
__(self
)
1059 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1060 self
.SetIcon(icon
, "wxPython Demo")
1064 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1065 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1066 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1067 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1068 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1071 def CreatePopupMenu(self
):
1073 This method is called by the base class when it needs to popup
1074 the menu for the default EVT_RIGHT_DOWN event. Just create
1075 the menu how you want it and return it from this function,
1076 the base class takes care of the rest.
1079 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1080 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1081 menu
.AppendSeparator()
1082 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1083 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1087 def MakeIcon(self
, img
):
1089 The various platforms have different requirements for the
1092 if "wxMSW" in wx
.PlatformInfo
:
1093 img
= img
.Scale(16, 16)
1094 elif "wxGTK" in wx
.PlatformInfo
:
1095 img
= img
.Scale(22, 22)
1096 # wxMac can be any size upto 128x128, so leave the source img alone....
1097 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1101 def OnTaskBarActivate(self
, evt
):
1102 if self
.frame
.IsIconized():
1103 self
.frame
.Iconize(False)
1104 if not self
.frame
.IsShown():
1105 self
.frame
.Show(True)
1109 def OnTaskBarClose(self
, evt
):
1113 def OnTaskBarChange(self
, evt
):
1114 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1115 name
= names
[self
.imgidx
]
1117 getFunc
= getattr(images
, "get%sImage" % name
)
1119 if self
.imgidx
>= len(names
):
1122 icon
= self
.MakeIcon(getFunc())
1123 self
.SetIcon(icon
, "This is a new icon: " + name
)
1126 def OnTaskBarRemove(self
, evt
):
1130 #---------------------------------------------------------------------------
1131 class wxPythonDemo(wx
.Frame
):
1132 overviewText
= "wxPython Overview"
1134 def __init__(self
, parent
, title
):
1135 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1136 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1138 self
.SetMinSize((640,480))
1141 self
.cwd
= os
.getcwd()
1142 self
.curOverview
= ""
1143 self
.demoPage
= None
1144 self
.codePage
= None
1146 self
.firstTime
= True
1149 icon
= images
.getWXPdemoIcon()
1153 self
.tbicon
= DemoTaskBarIcon(self
)
1157 wx
.CallAfter(self
.ShowTip
)
1159 self
.otherWin
= None
1160 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1161 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1162 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1163 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1165 self
.Centre(wx
.BOTH
)
1166 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1168 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1169 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1171 def EmptyHandler(evt
): pass
1172 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1173 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1175 # Prevent TreeCtrl from displaying all items after destruction when True
1179 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1182 self
.mainmenu
= wx
.MenuBar()
1184 item
= menu
.Append(-1, '&Redirect Output',
1185 'Redirect print statements to a window',
1187 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1189 exitItem
= menu
.Append(-1, 'E&xit\tCtrl-Q', 'Get the heck outta here!')
1190 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, exitItem
)
1191 wx
.App
.SetMacExitMenuItemId(exitItem
.GetId())
1192 self
.mainmenu
.Append(menu
, '&File')
1196 for item
in _treeList
[:-1]:
1198 for childItem
in item
[1]:
1199 mi
= submenu
.Append(-1, childItem
)
1200 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1201 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1202 self
.mainmenu
.Append(menu
, '&Demo')
1207 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1208 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1209 menu
.AppendSeparator()
1211 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1212 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1213 inspToolItem
= menu
.Append(-1, 'Open &Widget Inspector\tF6',
1214 'A tool that lets you browse the live widgets and sizers in an application')
1215 menu
.AppendSeparator()
1216 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1217 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1219 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1220 self
.Bind(wx
.EVT_MENU
, self
.OnOpenWidgetInspector
, inspToolItem
)
1221 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1222 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1223 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1224 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1225 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1226 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1227 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1228 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1229 self
.mainmenu
.Append(menu
, '&Help')
1230 self
.SetMenuBar(self
.mainmenu
)
1232 self
.finddata
= wx
.FindReplaceData()
1233 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1236 # This is another way to set Accelerators, in addition to
1237 # using the '\t<key>' syntax in the menu items.
1238 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitItem
.GetId()),
1239 (wx
.ACCEL_CTRL
, ord('H'), helpItem
.GetId()),
1240 (wx
.ACCEL_CTRL
, ord('F'), findItem
.GetId()),
1241 (wx
.ACCEL_NORMAL
, wx
.WXK_F3
, findnextItem
.GetId()),
1242 (wx
.ACCEL_NORMAL
, wx
.WXK_F9
, shellItem
.GetId()),
1244 self
.SetAcceleratorTable(aTable
)
1249 leftPanel
= wx
.Panel(splitter
)
1251 self
.filter = wx
.SearchCtrl(leftPanel
)
1252 self
.filter.ShowCancelButton(True)
1253 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1254 self
.filter.Bind(wx
.EVT_SEARCHCTRL_CANCEL_BTN
,
1255 lambda e
: self
.filter.SetValue(''))
1258 self
.tree
= wx
.TreeCtrl(leftPanel
, tID
, style
=
1259 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1262 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1264 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1265 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1266 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1267 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1269 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1270 # we put it in a panel first because there seems to be a
1271 # refresh bug of some sort (wxGTK) when it is directly in
1274 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1275 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1277 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1278 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1279 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1280 self
.nb
.AddPage(panel
, self
.overviewText
)
1282 def OnOvrSize(evt
, ovr
=self
.ovr
):
1283 ovr
.SetSize(evt
.GetSize())
1284 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1285 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1287 if "gtk2" in wx
.PlatformInfo
:
1288 self
.ovr
.SetStandardFonts()
1289 self
.SetOverview(self
.overviewText
, mainOverview
)
1292 # Set up a log window
1293 self
.log
= wx
.TextCtrl(splitter2
, -1,
1294 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1295 if wx
.Platform
== "__WXMAC__":
1296 self
.log
.MacCheckSpelling(False)
1298 # Set the wxWindows log target to be this textctrl
1299 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1301 # But instead of the above we want to show how to use our own wx.Log class
1302 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1304 # for serious debugging
1305 #wx.Log_SetActiveTarget(wx.LogStderr())
1306 #wx.Log_SetTraceMask(wx.TraceMessages)
1309 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1310 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1312 # add the windows to the splitter and split it.
1313 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1314 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1315 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1316 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1317 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1318 leftPanel
.SetSizer(leftBox
)
1319 splitter
.SplitVertically(leftPanel
, splitter2
, 220)
1321 splitter
.SetMinimumPaneSize(120)
1322 splitter2
.SetMinimumPaneSize(60)
1324 # Make the splitter on the right expand the top window when resized
1325 def SplitterOnSize(evt
):
1326 splitter
= evt
.GetEventObject()
1327 sz
= splitter
.GetSize()
1328 splitter
.SetSashPosition(sz
.height
- 160, False)
1331 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1333 # select initial items
1334 self
.nb
.SetSelection(0)
1335 self
.tree
.SelectItem(self
.root
)
1337 # Load 'Main' module
1338 self
.LoadDemo(self
.overviewText
)
1341 # select some other initial module?
1342 if len(sys
.argv
) > 1:
1344 if arg
.endswith('.py'):
1346 selectedDemo
= self
.treeMap
.get(arg
, None)
1348 self
.tree
.SelectItem(selectedDemo
)
1349 self
.tree
.EnsureVisible(selectedDemo
)
1352 #---------------------------------------------
1354 def RecreateTree(self
, evt
=None):
1356 self
.tree
.DeleteAllItems()
1357 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1359 filter = self
.filter.GetValue()
1360 for category
, items
in _treeList
:
1362 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1364 child
= self
.tree
.AppendItem(self
.root
, category
)
1365 if not firstChild
: firstChild
= child
1366 for childItem
in items
:
1367 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1368 self
.treeMap
[childItem
] = theDemo
1370 self
.tree
.Expand(self
.root
)
1372 self
.tree
.Expand(firstChild
)
1374 self
.tree
.ExpandAll()
1377 def WriteText(self
, text
):
1378 if text
[-1:] == '\n':
1382 def write(self
, txt
):
1385 #---------------------------------------------
1386 def OnItemExpanded(self
, event
):
1387 item
= event
.GetItem()
1388 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1391 #---------------------------------------------
1392 def OnItemCollapsed(self
, event
):
1393 item
= event
.GetItem()
1394 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1397 #---------------------------------------------
1398 def OnTreeLeftDown(self
, event
):
1399 # reset the overview text if the tree item is clicked on again
1400 pt
= event
.GetPosition();
1401 item
, flags
= self
.tree
.HitTest(pt
)
1402 if item
== self
.tree
.GetSelection():
1403 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1406 #---------------------------------------------
1407 def OnSelChanged(self
, event
):
1408 if self
.dying
or not self
.loaded
:
1411 item
= event
.GetItem()
1412 itemText
= self
.tree
.GetItemText(item
)
1413 self
.LoadDemo(itemText
)
1415 #---------------------------------------------
1416 def LoadDemo(self
, demoName
):
1418 wx
.BeginBusyCursor()
1421 self
.ShutdownDemoModule()
1423 if demoName
== self
.overviewText
:
1424 # User selected the "wxPython Overview" node
1426 # Changing the main window at runtime not yet supported...
1427 self
.demoModules
= DemoModules(__name__
)
1428 self
.SetOverview(self
.overviewText
, mainOverview
)
1429 self
.LoadDemoSource()
1430 self
.UpdateNotebook(0)
1432 if os
.path
.exists(GetOriginalFilename(demoName
)):
1433 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1434 self
.demoModules
= DemoModules(demoName
)
1435 self
.LoadDemoSource()
1438 self
.SetOverview("wxPython", mainOverview
)
1439 self
.codePage
= None
1440 self
.UpdateNotebook(0)
1444 #---------------------------------------------
1445 def LoadDemoSource(self
):
1446 self
.codePage
= None
1447 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1448 self
.codePage
.LoadDemo(self
.demoModules
)
1450 #---------------------------------------------
1451 def RunModule(self
):
1452 """Runs the active module"""
1454 module
= self
.demoModules
.GetActive()
1455 self
.ShutdownDemoModule()
1458 # o The RunTest() for all samples must now return a window that can
1459 # be palced in a tab in the main notebook.
1460 # o If an error occurs (or has occurred before) an error tab is created.
1462 if module
is not None:
1463 wx
.LogMessage("Running demo module...")
1464 if hasattr(module
, "overview"):
1465 overviewText
= module
.overview
1468 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1470 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1471 DemoError(sys
.exc_info()), self
)
1473 assert self
.demoPage
is not None, "runTest must return a window!"
1476 # There was a previous error in compiling or exec-ing
1477 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1478 self
.demoModules
.GetErrorInfo(), self
)
1480 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1483 # cahnge to the demo page the first time a module is run
1484 self
.UpdateNotebook(2)
1485 self
.firstTime
= False
1487 # otherwise just stay on the same tab in case the user has changed to another one
1488 self
.UpdateNotebook()
1490 #---------------------------------------------
1491 def ShutdownDemoModule(self
):
1493 # inform the window that it's time to quit if it cares
1494 if hasattr(self
.demoPage
, "ShutdownDemo"):
1495 self
.demoPage
.ShutdownDemo()
1496 wx
.YieldIfNeeded() # in case the page has pending events
1497 self
.demoPage
= None
1499 #---------------------------------------------
1500 def UpdateNotebook(self
, select
= -1):
1504 def UpdatePage(page
, pageText
):
1507 for i
in range(nb
.GetPageCount()):
1508 if nb
.GetPageText(i
) == pageText
:
1516 nb
.AddPage(page
, pageText
)
1517 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1519 if nb
.GetPage(pagePos
) != page
:
1520 # Reload an existing page
1522 nb
.DeletePage(pagePos
)
1523 nb
.InsertPage(pagePos
, page
, pageText
)
1525 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1527 # Excellent! No redraw/flicker
1528 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1531 nb
.DeletePage(pagePos
)
1532 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1534 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1537 select
= nb
.GetSelection()
1539 UpdatePage(self
.codePage
, "Demo Code")
1540 UpdatePage(self
.demoPage
, "Demo")
1542 if select
>= 0 and select
< nb
.GetPageCount():
1543 nb
.SetSelection(select
)
1545 #---------------------------------------------
1546 def SetOverview(self
, name
, text
):
1547 self
.curOverview
= text
1549 if lead
!= '<html>' and lead
!= '<HTML>':
1550 text
= '<br>'.join(text
.split('\n'))
1552 text
= text
.decode('iso8859_1')
1553 self
.ovr
.SetPage(text
)
1554 self
.nb
.SetPageText(0, name
)
1556 #---------------------------------------------
1558 def OnFileExit(self
, *event
):
1561 def OnToggleRedirect(self
, event
):
1565 print "Print statements and other standard output will now be directed to this window."
1568 print "Print statements and other standard output will now be sent to the usual location."
1570 def OnHelpAbout(self
, event
):
1571 from About
import MyAboutBox
1572 about
= MyAboutBox(self
)
1576 def OnHelpFind(self
, event
):
1577 if self
.finddlg
!= None:
1580 self
.nb
.SetSelection(1)
1581 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1582 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1583 self
.finddlg
.Show(True)
1586 def OnUpdateFindItems(self
, evt
):
1587 evt
.Enable(self
.finddlg
== None)
1590 def OnFind(self
, event
):
1591 editor
= self
.codePage
.editor
1592 self
.nb
.SetSelection(1)
1593 end
= editor
.GetLastPosition()
1594 textstring
= editor
.GetRange(0, end
).lower()
1595 findstring
= self
.finddata
.GetFindString().lower()
1596 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1598 start
= editor
.GetSelection()[0]
1599 loc
= textstring
.rfind(findstring
, 0, start
)
1601 start
= editor
.GetSelection()[1]
1602 loc
= textstring
.find(findstring
, start
)
1603 if loc
== -1 and start
!= 0:
1604 # string not found, start at beginning
1607 loc
= textstring
.rfind(findstring
, 0, start
)
1610 loc
= textstring
.find(findstring
, start
)
1612 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1613 'Find String Not Found in Demo File',
1614 wx
.OK | wx
.ICON_INFORMATION
)
1619 self
.finddlg
.SetFocus()
1622 self
.finddlg
.Destroy()
1624 editor
.ShowPosition(loc
)
1625 editor
.SetSelection(loc
, loc
+ len(findstring
))
1629 def OnFindNext(self
, event
):
1630 if self
.finddata
.GetFindString():
1633 self
.OnHelpFind(event
)
1635 def OnFindClose(self
, event
):
1636 event
.GetDialog().Destroy()
1640 def OnOpenShellWindow(self
, evt
):
1642 # if it already exists then just make sure it's visible
1648 # Make a PyShell window
1650 namespace
= { 'wx' : wx
,
1651 'app' : wx
.GetApp(),
1654 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1655 self
.shell
.SetSize((640,480))
1658 # Hook the close event of the main frame window so that we
1659 # close the shell at the same time if it still exists
1660 def CloseShell(evt
):
1664 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1667 def OnOpenWidgetInspector(self
, evt
):
1668 # Activate the widget inspection tool
1669 from wx
.lib
.inspection
import InspectionTool
1670 if not InspectionTool().initialized
:
1671 InspectionTool().Init()
1673 # Find a widget to be selected in the tree. Use either the
1674 # one under the cursor, if any, or this frame.
1675 wnd
= wx
.FindWindowAtPointer()
1678 InspectionTool().Show(wnd
, True)
1681 #---------------------------------------------
1682 def OnCloseWindow(self
, event
):
1684 self
.demoPage
= None
1685 self
.codePage
= None
1686 self
.mainmenu
= None
1687 if self
.tbicon
is not None:
1688 self
.tbicon
.Destroy()
1692 #---------------------------------------------
1693 def OnIdle(self
, event
):
1695 self
.otherWin
.Raise()
1696 self
.demoPage
= self
.otherWin
1697 self
.otherWin
= None
1700 #---------------------------------------------
1703 showTipText
= open(opj("data/showTips")).read()
1704 showTip
, index
= eval(showTipText
)
1706 showTip
, index
= (1, 0)
1708 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1710 showTip
= wx
.ShowTip(self
, tp
)
1711 index
= tp
.GetCurrentTip()
1712 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1715 #---------------------------------------------
1716 def OnDemoMenu(self
, event
):
1718 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1722 self
.tree
.SelectItem(selectedDemo
)
1723 self
.tree
.EnsureVisible(selectedDemo
)
1727 #---------------------------------------------
1728 def OnIconfiy(self
, evt
):
1729 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1732 #---------------------------------------------
1733 def OnMaximize(self
, evt
):
1734 wx
.LogMessage("OnMaximize")
1737 #---------------------------------------------
1738 def OnActivate(self
, evt
):
1739 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1742 #---------------------------------------------
1743 def OnAppActivate(self
, evt
):
1744 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1747 #---------------------------------------------------------------------------
1748 #---------------------------------------------------------------------------
1750 class MySplashScreen(wx
.SplashScreen
):
1752 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1753 wx
.SplashScreen
.__init
__(self
, bmp
,
1754 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1756 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1757 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1760 def OnClose(self
, evt
):
1761 # Make sure the default handler runs too so this window gets
1766 # if the timer is still running then go ahead and show the
1768 if self
.fc
.IsRunning():
1774 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1776 if self
.fc
.IsRunning():
1780 class MyApp(wx
.App
):
1783 Create and show the splash screen. It will then create and show
1784 the main frame when it is time to do so.
1787 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1790 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1792 # Normally when using a SplashScreen you would create it, show
1793 # it and then continue on with the applicaiton's
1794 # initialization, finally creating and showing the main
1795 # application window(s). In this case we have nothing else to
1796 # do so we'll delay showing the main frame until later (see
1797 # ShowMain above) so the users can see the SplashScreen effect.
1798 splash
= MySplashScreen()
1805 #---------------------------------------------------------------------------
1809 demoPath
= os
.path
.dirname(__file__
)
1816 #---------------------------------------------------------------------------
1819 mainOverview
= """<html><body>
1822 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1823 language. It allows Python programmers to create programs with a
1824 robust, highly functional graphical user interface, simply and easily.
1825 It is implemented as a Python extension module (native code) that
1826 wraps the popular wxWindows cross platform GUI library, which is
1829 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1830 means that it is free for anyone to use and the source code is
1831 available for anyone to look at and modify. Or anyone can contribute
1832 fixes or enhancements to the project.
1834 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1835 same program will run on multiple platforms without modification.
1836 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1837 or unix-like systems, and Macintosh OS X. Since the language is
1838 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1841 <p> <b>This demo</b> is not only a collection of test cases for
1842 wxPython, but is also designed to help you learn about and how to use
1843 wxPython. Each sample is listed in the tree control on the left.
1844 When a sample is selected in the tree then a module is loaded and run
1845 (usually in a tab of this notebook,) and the source code of the module
1846 is loaded in another tab for you to browse and learn from.
1851 #----------------------------------------------------------------------------
1852 #----------------------------------------------------------------------------
1854 if __name__
== '__main__':
1858 #----------------------------------------------------------------------------