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', [
51 'AUI_DockingWindowMgr',
80 # managed windows == things with a (optional) caption you can close
81 ('Frames and Dialogs', [
82 'AUI_DockingWindowMgr',
103 'SingleChoiceDialog',
107 # dialogs from libraries
110 'ScrolledMessageDialog',
114 ('Core Windows/Controls', [
151 ('"Book" Controls', [
160 ('Custom Controls', [
177 # controls coming from other libraries
178 ('More Windows/Controls', [
179 'ActiveX_FlashWindow',
180 'ActiveX_IEHtmlWindow',
185 'CheckListCtrlMixin',
202 'MaskedEditControls',
205 'MultiSplitterWindow',
206 'OwnerDrawnComboBox',
223 # How to lay out the controls in a frame/dialog
233 'XmlResourceHandler',
234 'XmlResourceSubclass',
238 ('Process and Events', [
246 ##'infoframe', # needs better explanation and some fixing
250 ('Clipboard and DnD', [
277 ##'DialogUnits', # needs more explanations
298 ('Check out the samples dir too', [
305 #---------------------------------------------------------------------------
306 # Show how to derive a custom wxLog class
308 class MyLog(wx
.PyLog
):
309 def __init__(self
, textCtrl
, logTime
=0):
310 wx
.PyLog
.__init
__(self
)
312 self
.logTime
= logTime
314 def DoLogString(self
, message
, timeStamp
):
315 #print message, timeStamp
317 # message = time.strftime("%X", time.localtime(timeStamp)) + \
320 self
.tc
.AppendText(message
+ '\n')
323 class MyTP(wx
.PyTipProvider
):
325 return "This is my tip"
327 #---------------------------------------------------------------------------
328 # A class to be used to simply display a message in the demo pane
329 # rather than running the sample itself.
331 class MessagePanel(wx
.Panel
):
332 def __init__(self
, parent
, message
, caption
='', flags
=0):
333 wx
.Panel
.__init
__(self
, parent
)
338 if flags
& wx
.ICON_EXCLAMATION
:
339 artid
= wx
.ART_WARNING
340 elif flags
& wx
.ICON_ERROR
:
342 elif flags
& wx
.ICON_QUESTION
:
343 artid
= wx
.ART_QUESTION
344 elif flags
& wx
.ICON_INFORMATION
:
345 artid
= wx
.ART_INFORMATION
347 if artid
is not None:
348 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
349 icon
= wx
.StaticBitmap(self
, -1, bmp
)
351 icon
= (32,32) # make a spacer instead
354 caption
= wx
.StaticText(self
, -1, caption
)
355 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
357 message
= wx
.StaticText(self
, -1, message
)
359 # add to sizers for layout
360 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
366 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
373 box
= wx
.BoxSizer(wx
.VERTICAL
)
375 box
.Add(hbox
, 0, wx
.EXPAND
)
382 #---------------------------------------------------------------------------
383 # A class to be used to display source code in the demo. Try using the
384 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
385 # if there is an error, such as the stc module not being present.
389 ##raise ImportError # for testing the alternate implementation
391 from StyledTextCtrl_2
import PythonSTC
393 class DemoCodeEditor(PythonSTC
):
394 def __init__(self
, parent
):
395 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
398 # Some methods to make it compatible with how the wxTextCtrl is used
399 def SetValue(self
, value
):
401 value
= value
.decode('iso8859_1')
403 self
.EmptyUndoBuffer()
406 def IsModified(self
):
407 return self
.GetModify()
412 def SetInsertionPoint(self
, pos
):
413 self
.SetCurrentPos(pos
)
416 def ShowPosition(self
, pos
):
417 line
= self
.LineFromPosition(pos
)
418 #self.EnsureVisible(line)
421 def GetLastPosition(self
):
422 return self
.GetLength()
424 def GetPositionFromLine(self
, line
):
425 return self
.PositionFromLine(line
)
427 def GetRange(self
, start
, end
):
428 return self
.GetTextRange(start
, end
)
430 def GetSelection(self
):
431 return self
.GetAnchor(), self
.GetCurrentPos()
433 def SetSelection(self
, start
, end
):
434 self
.SetSelectionStart(start
)
435 self
.SetSelectionEnd(end
)
437 def SelectLine(self
, line
):
438 start
= self
.PositionFromLine(line
)
439 end
= self
.GetLineEndPosition(line
)
440 self
.SetSelection(start
, end
)
442 def SetUpEditor(self
):
444 This method carries out the work of setting up the demo editor.
445 It's seperate so as not to clutter up the init code.
449 self
.SetLexer(stc
.STC_LEX_PYTHON
)
450 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
453 self
.SetProperty("fold", "1" )
455 # Highlight tab/space mixing (shouldn't be any)
456 self
.SetProperty("tab.timmy.whinge.level", "1")
458 # Set left and right margins
461 # Set up the numbers in the margin for margin #1
462 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
463 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
464 self
.SetMarginWidth(1, 40)
466 # Indentation and tab stuff
467 self
.SetIndent(4) # Proscribed indent size for wx
468 self
.SetIndentationGuides(True) # Show indent guides
469 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
470 self
.SetTabIndents(True) # Tab key indents
471 self
.SetTabWidth(4) # Proscribed tab size for wx
472 self
.SetUseTabs(False) # Use spaces rather than tabs, or
473 # TabTimmy will complain!
475 self
.SetViewWhiteSpace(False) # Don't view white space
477 # EOL: Since we are loading/saving ourselves, and the
478 # strings will always have \n's in them, set the STC to
479 # edit them that way.
480 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
481 self
.SetViewEOL(False)
483 # No right-edge mode indicator
484 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
486 # Setup a margin to hold fold markers
487 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
488 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
489 self
.SetMarginSensitive(2, True)
490 self
.SetMarginWidth(2, 12)
492 # and now set up the fold markers
493 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
494 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
495 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
496 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
497 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
498 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
499 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
501 # Global default style
502 if wx
.Platform
== '__WXMSW__':
503 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
504 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
505 elif wx
.Platform
== '__WXMAC__':
506 # TODO: if this looks fine on Linux too, remove the Mac-specific case
507 # and use this whenever OS != MSW.
508 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
509 'fore:#000000,back:#FFFFFF,face:Courier')
511 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
512 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
514 # Clear styles and revert to default.
517 # Following style specs only indicate differences from default.
518 # The rest remains unchanged.
520 # Line numbers in margin
521 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
523 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
525 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
527 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
530 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
532 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
533 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
535 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
536 # Strings and characters
537 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
538 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
540 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
542 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
543 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
545 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
547 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
549 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
550 # Identifiers. I leave this as not bold because everything seems
551 # to be an identifier if it doesn't match the above criterae
552 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
555 self
.SetCaretForeground("BLUE")
556 # Selection background
557 self
.SetSelBackground(1, '#66CCFF')
559 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
560 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
562 def RegisterModifiedEvent(self
, eventHandler
):
563 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
567 class DemoCodeEditor(wx
.TextCtrl
):
568 def __init__(self
, parent
):
569 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
570 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
572 def RegisterModifiedEvent(self
, eventHandler
):
573 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
575 def SetReadOnly(self
, flag
):
576 self
.SetEditable(not flag
)
577 # NOTE: STC already has this method
580 return self
.GetValue()
582 def GetPositionFromLine(self
, line
):
583 return self
.XYToPosition(0,line
)
585 def GotoLine(self
, line
):
586 pos
= self
.GetPositionFromLine(line
)
587 self
.SetInsertionPoint(pos
)
588 self
.ShowPosition(pos
)
590 def SelectLine(self
, line
):
591 start
= self
.GetPositionFromLine(line
)
592 end
= start
+ self
.GetLineLength(line
)
593 self
.SetSelection(start
, end
)
596 #---------------------------------------------------------------------------
597 # Constants for module versions
601 modDefault
= modOriginal
603 #---------------------------------------------------------------------------
605 class DemoCodePanel(wx
.Panel
):
606 """Panel for the 'Demo Code' tab"""
607 def __init__(self
, parent
, mainFrame
):
608 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
609 if 'wxMSW' in wx
.PlatformInfo
:
611 self
.mainFrame
= mainFrame
612 self
.editor
= DemoCodeEditor(self
)
613 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
615 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
616 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
617 self
.btnSave
.Enable(False)
618 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
619 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
621 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
622 modModified
: wx
.RadioButton(self
, -1, "Modified") }
624 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
625 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
626 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
627 for modID
, radioButton
in self
.radioButtons
.items():
628 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
629 radioButton
.modID
= modID
# makes it easier for the event handler
630 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
632 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
633 self
.controlBox
.Add(self
.btnRestore
, 0)
635 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
636 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
637 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
638 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
641 self
.SetSizer(self
.box
)
644 # Loads a demo from a DemoModules object
645 def LoadDemo(self
, demoModules
):
646 self
.demoModules
= demoModules
647 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
648 demoModules
.SetActive(modModified
)
650 demoModules
.SetActive(modOriginal
)
651 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
652 self
.ActiveModuleChanged()
655 def ActiveModuleChanged(self
):
656 self
.LoadDemoSource(self
.demoModules
.GetSource())
657 self
.UpdateControlState()
661 def LoadDemoSource(self
, source
):
663 self
.editor
.SetValue(source
)
665 self
.btnSave
.Enable(False)
668 def JumpToLine(self
, line
, highlight
=False):
669 self
.editor
.GotoLine(line
)
670 self
.editor
.SetFocus()
672 self
.editor
.SelectLine(line
)
675 def UpdateControlState(self
):
676 active
= self
.demoModules
.GetActiveID()
677 # Update the radio/restore buttons
678 for moduleID
in self
.radioButtons
:
679 btn
= self
.radioButtons
[moduleID
]
680 if moduleID
== active
:
685 if self
.demoModules
.Exists(moduleID
):
687 if moduleID
== modModified
:
688 self
.btnRestore
.Enable(True)
691 if moduleID
== modModified
:
692 self
.btnRestore
.Enable(False)
695 def OnRadioButton(self
, event
):
696 radioSelected
= event
.GetEventObject()
697 modSelected
= radioSelected
.modID
698 if modSelected
!= self
.demoModules
.GetActiveID():
699 busy
= wx
.BusyInfo("Reloading demo module...")
700 self
.demoModules
.SetActive(modSelected
)
701 self
.ActiveModuleChanged()
704 def ReloadDemo(self
):
705 if self
.demoModules
.name
!= __name__
:
706 self
.mainFrame
.RunModule()
709 def OnCodeModified(self
, event
):
710 self
.btnSave
.Enable(self
.editor
.IsModified())
713 def OnSave(self
, event
):
714 if self
.demoModules
.Exists(modModified
):
715 if self
.demoModules
.GetActiveID() == modOriginal
:
716 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
717 "Do you want to continue?"
718 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
719 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
720 result
= dlg
.ShowModal()
721 if result
== wx
.ID_NO
:
725 self
.demoModules
.SetActive(modModified
)
726 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
728 # Create the demo directory if one doesn't already exist
729 if not os
.path
.exists(GetModifiedDirectory()):
731 os
.makedirs(GetModifiedDirectory())
732 if not os
.path
.exists(GetModifiedDirectory()):
733 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
736 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
739 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
742 f
= open(modifiedFilename
, "wt")
743 source
= self
.editor
.GetText()
749 busy
= wx
.BusyInfo("Reloading demo module...")
750 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
751 self
.ActiveModuleChanged()
754 def OnRestore(self
, event
): # Handles the "Delete Modified" button
755 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
756 self
.demoModules
.Delete(modModified
)
757 os
.unlink(modifiedFilename
) # Delete the modified copy
758 busy
= wx
.BusyInfo("Reloading demo module...")
759 self
.ActiveModuleChanged()
762 #---------------------------------------------------------------------------
765 """Convert paths to the platform-specific separator"""
766 str = apply(os
.path
.join
, tuple(path
.split('/')))
767 # HACK: on Linux, a leading / gets lost...
768 if path
.startswith('/'):
773 def GetModifiedDirectory():
775 Returns the directory where modified versions of the demo files
778 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
781 def GetModifiedFilename(name
):
783 Returns the filename of the modified version of the specified demo
785 if not name
.endswith(".py"):
787 return GetModifiedDirectory() + name
790 def GetOriginalFilename(name
):
792 Returns the filename of the original version of the specified demo
794 if not name
.endswith(".py"):
799 def DoesModifiedExist(name
):
800 """Returns whether the specified demo has a modified copy"""
801 if os
.path
.exists(GetModifiedFilename(name
)):
807 #---------------------------------------------------------------------------
809 class ModuleDictWrapper
:
810 """Emulates a module with a dynamically compiled __dict__"""
811 def __init__(self
, dict):
814 def __getattr__(self
, name
):
815 if name
in self
.dict:
816 return self
.dict[name
]
822 Dynamically manages the original/modified versions of a demo
825 def __init__(self
, name
):
829 # (dict , source , filename , description , error information )
830 # ( 0 , 1 , 2 , 3 , 4 )
831 self
.modules
= [[None, "" , "" , "<original>" , None],
832 [None, "" , "" , "<modified>" , None]]
834 # load original module
835 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
836 self
.SetActive(modOriginal
)
838 # load modified module (if one exists)
839 if DoesModifiedExist(name
):
840 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
843 def LoadFromFile(self
, modID
, filename
):
844 self
.modules
[modID
][2] = filename
845 file = open(filename
, "rt")
846 self
.LoadFromSource(modID
, file.read())
850 def LoadFromSource(self
, modID
, source
):
851 self
.modules
[modID
][1] = source
855 def LoadDict(self
, modID
):
856 if self
.name
!= __name__
:
857 source
= self
.modules
[modID
][1]
858 #description = self.modules[modID][3]
859 description
= self
.modules
[modID
][2]
862 self
.modules
[modID
][0] = {}
863 code
= compile(source
, description
, "exec")
864 exec code
in self
.modules
[modID
][0]
866 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
867 self
.modules
[modID
][0] = None
869 self
.modules
[modID
][4] = None
872 def SetActive(self
, modID
):
873 if modID
!= modOriginal
and modID
!= modModified
:
876 self
.modActive
= modID
880 dict = self
.modules
[self
.modActive
][0]
884 return ModuleDictWrapper(dict)
887 def GetActiveID(self
):
888 return self
.modActive
891 def GetSource(self
, modID
= None):
893 modID
= self
.modActive
894 return self
.modules
[modID
][1]
897 def GetFilename(self
, modID
= None):
899 modID
= self
.modActive
900 return self
.modules
[self
.modActive
][2]
903 def GetErrorInfo(self
, modID
= None):
905 modID
= self
.modActive
906 return self
.modules
[self
.modActive
][4]
909 def Exists(self
, modID
):
910 return self
.modules
[modID
][1] != ""
913 def UpdateFile(self
, modID
= None):
914 """Updates the file from which a module was loaded
915 with (possibly updated) source"""
917 modID
= self
.modActive
919 source
= self
.modules
[modID
][1]
920 filename
= self
.modules
[modID
][2]
923 file = open(filename
, "wt")
929 def Delete(self
, modID
):
930 if self
.modActive
== modID
:
933 self
.modules
[modID
][0] = None
934 self
.modules
[modID
][1] = ""
935 self
.modules
[modID
][2] = ""
938 #---------------------------------------------------------------------------
941 """Wraps and stores information about the current exception"""
942 def __init__(self
, exc_info
):
945 excType
, excValue
= exc_info
[:2]
946 # traceback list entries: (filename, line number, function name, text)
947 self
.traceback
= traceback
.extract_tb(exc_info
[2])
949 # --Based on traceback.py::format_exception_only()--
950 if type(excType
) == types
.ClassType
:
951 self
.exception_type
= excType
.__name
__
953 self
.exception_type
= excType
955 # If it's a syntax error, extra information needs
956 # to be added to the traceback
957 if excType
is SyntaxError:
959 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
964 filename
= "<string>"
966 self
.traceback
.append( (filename
, lineno
, "", line
) )
969 self
.exception_details
= str(excValue
)
971 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
978 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
981 #---------------------------------------------------------------------------
983 class DemoErrorPanel(wx
.Panel
):
984 """Panel put into the demo tab when the demo fails to run due to errors"""
986 def __init__(self
, parent
, codePanel
, demoError
, log
):
987 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
988 self
.codePanel
= codePanel
992 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
995 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
996 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
998 # Exception Information
999 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
1000 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
1001 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
1002 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
1003 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
1004 boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 )
1005 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
1006 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
1007 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
1008 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
1010 # Set up the traceback list
1011 # This one automatically resizes last column to take up remaining space
1012 from ListCtrl
import TestListCtrl
1013 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
1014 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
1015 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
1016 self
.list.InsertColumn(0, "Filename")
1017 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
1018 self
.list.InsertColumn(2, "Function")
1019 self
.list.InsertColumn(3, "Code")
1020 self
.InsertTraceback(self
.list, demoError
.traceback
)
1021 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1022 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1023 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1024 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1025 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1026 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1027 + "Double-click on them to go to the offending line")
1028 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1031 self
.SetSizer(self
.box
)
1034 def InsertTraceback(self
, list, traceback
):
1035 #Add the traceback data
1036 for x
in range(len(traceback
)):
1038 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1039 list.SetStringItem(x
, 1, str(data
[1])) # Line
1040 list.SetStringItem(x
, 2, str(data
[2])) # Function
1041 list.SetStringItem(x
, 3, str(data
[3])) # Code
1043 # Check whether this entry is from the demo module
1044 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1045 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1046 # Give it a blue colour
1047 item
= self
.list.GetItem(x
)
1048 item
.SetTextColour(wx
.BLUE
)
1049 self
.list.SetItem(item
)
1051 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1054 def OnItemSelected(self
, event
):
1055 # This occurs before OnDoubleClick and can be used to set the
1056 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1057 self
.currentItem
= event
.m_itemIndex
1061 def OnDoubleClick(self
, event
):
1062 # If double-clicking on a demo's entry, jump to the line number
1063 line
= self
.list.GetItemData(self
.currentItem
)
1065 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1066 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1070 #---------------------------------------------------------------------------
1072 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1073 TBMENU_RESTORE
= wx
.NewId()
1074 TBMENU_CLOSE
= wx
.NewId()
1075 TBMENU_CHANGE
= wx
.NewId()
1076 TBMENU_REMOVE
= wx
.NewId()
1078 def __init__(self
, frame
):
1079 wx
.TaskBarIcon
.__init
__(self
)
1083 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1084 self
.SetIcon(icon
, "wxPython Demo")
1088 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1089 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1090 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1091 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1092 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1095 def CreatePopupMenu(self
):
1097 This method is called by the base class when it needs to popup
1098 the menu for the default EVT_RIGHT_DOWN event. Just create
1099 the menu how you want it and return it from this function,
1100 the base class takes care of the rest.
1103 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1104 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1105 menu
.AppendSeparator()
1106 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1107 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1111 def MakeIcon(self
, img
):
1113 The various platforms have different requirements for the
1116 if "wxMSW" in wx
.PlatformInfo
:
1117 img
= img
.Scale(16, 16)
1118 elif "wxGTK" in wx
.PlatformInfo
:
1119 img
= img
.Scale(22, 22)
1120 # wxMac can be any size upto 128x128, so leave the source img alone....
1121 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1125 def OnTaskBarActivate(self
, evt
):
1126 if self
.frame
.IsIconized():
1127 self
.frame
.Iconize(False)
1128 if not self
.frame
.IsShown():
1129 self
.frame
.Show(True)
1133 def OnTaskBarClose(self
, evt
):
1137 def OnTaskBarChange(self
, evt
):
1138 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1139 name
= names
[self
.imgidx
]
1141 getFunc
= getattr(images
, "get%sImage" % name
)
1143 if self
.imgidx
>= len(names
):
1146 icon
= self
.MakeIcon(getFunc())
1147 self
.SetIcon(icon
, "This is a new icon: " + name
)
1150 def OnTaskBarRemove(self
, evt
):
1154 #---------------------------------------------------------------------------
1155 class wxPythonDemo(wx
.Frame
):
1156 overviewText
= "wxPython Overview"
1158 def __init__(self
, parent
, title
):
1159 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1160 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1162 self
.SetMinSize((640,480))
1165 self
.cwd
= os
.getcwd()
1166 self
.curOverview
= ""
1167 self
.demoPage
= None
1168 self
.codePage
= None
1170 self
.firstTime
= True
1173 icon
= images
.getWXPdemoIcon()
1177 self
.tbicon
= DemoTaskBarIcon(self
)
1181 wx
.CallAfter(self
.ShowTip
)
1183 self
.otherWin
= None
1184 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1185 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1186 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1187 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1189 self
.Centre(wx
.BOTH
)
1190 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1192 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1193 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1195 def EmptyHandler(evt
): pass
1196 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1197 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1199 # Prevent TreeCtrl from displaying all items after destruction when True
1203 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1206 self
.mainmenu
= wx
.MenuBar()
1208 item
= menu
.Append(-1, '&Redirect Output',
1209 'Redirect print statements to a window',
1211 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1213 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1214 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1215 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1216 self
.mainmenu
.Append(menu
, '&File')
1220 for item
in _treeList
:
1222 for childItem
in item
[1]:
1223 mi
= submenu
.Append(-1, childItem
)
1224 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1225 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1226 self
.mainmenu
.Append(menu
, '&Demo')
1231 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1232 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1233 menu
.AppendSeparator()
1235 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1236 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1237 menu
.AppendSeparator()
1238 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1239 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1241 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1242 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1243 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1244 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1245 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1246 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1247 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1248 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1249 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1250 self
.mainmenu
.Append(menu
, '&Help')
1251 self
.SetMenuBar(self
.mainmenu
)
1253 self
.finddata
= wx
.FindReplaceData()
1254 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1257 # This is another way to set Accelerators, in addition to
1258 # using the '\t<key>' syntax in the menu items.
1259 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1260 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1261 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1262 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1264 self
.SetAcceleratorTable(aTable
)
1269 leftPanel
= wx
.Panel(splitter
)
1271 self
.filter = wx
.TextCtrl(leftPanel
)
1272 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1275 self
.tree
= wx
.TreeCtrl(leftPanel
, tID
, style
=
1276 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1279 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1281 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1282 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1283 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1284 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1286 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1287 # we put it in a panel first because there seems to be a
1288 # refresh bug of some sort (wxGTK) when it is directly in
1291 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1292 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1294 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1295 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1296 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1297 self
.nb
.AddPage(panel
, self
.overviewText
)
1299 def OnOvrSize(evt
, ovr
=self
.ovr
):
1300 ovr
.SetSize(evt
.GetSize())
1301 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1302 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1304 if "gtk2" in wx
.PlatformInfo
:
1305 self
.ovr
.SetStandardFonts()
1306 self
.SetOverview(self
.overviewText
, mainOverview
)
1309 # Set up a log window
1310 self
.log
= wx
.TextCtrl(splitter2
, -1,
1311 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1312 if wx
.Platform
== "__WXMAC__":
1313 self
.log
.MacCheckSpelling(False)
1315 # Set the wxWindows log target to be this textctrl
1316 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1318 # But instead of the above we want to show how to use our own wx.Log class
1319 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1321 # for serious debugging
1322 #wx.Log_SetActiveTarget(wx.LogStderr())
1323 #wx.Log_SetTraceMask(wx.TraceMessages)
1326 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1327 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1329 # add the windows to the splitter and split it.
1330 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1331 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1332 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1333 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1334 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1335 leftPanel
.SetSizer(leftBox
)
1336 splitter
.SplitVertically(leftPanel
, splitter2
, 220)
1338 splitter
.SetMinimumPaneSize(120)
1339 splitter2
.SetMinimumPaneSize(60)
1341 # Make the splitter on the right expand the top window when resized
1342 def SplitterOnSize(evt
):
1343 splitter
= evt
.GetEventObject()
1344 sz
= splitter
.GetSize()
1345 splitter
.SetSashPosition(sz
.height
- 160, False)
1348 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1350 # select initial items
1351 self
.nb
.SetSelection(0)
1352 self
.tree
.SelectItem(self
.root
)
1354 # Load 'Main' module
1355 self
.LoadDemo(self
.overviewText
)
1358 # select some other initial module?
1359 if len(sys
.argv
) > 1:
1361 if arg
.endswith('.py'):
1363 selectedDemo
= self
.treeMap
.get(arg
, None)
1365 self
.tree
.SelectItem(selectedDemo
)
1366 self
.tree
.EnsureVisible(selectedDemo
)
1369 #---------------------------------------------
1371 def RecreateTree(self
, evt
=None):
1372 self
.tree
.DeleteAllItems()
1373 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1375 filter = self
.filter.GetValue()
1376 for category
, items
in _treeList
:
1378 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1380 child
= self
.tree
.AppendItem(self
.root
, category
)
1381 if not firstChild
: firstChild
= child
1382 for childItem
in items
:
1383 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1384 self
.treeMap
[childItem
] = theDemo
1386 self
.tree
.Expand(self
.root
)
1388 self
.tree
.Expand(firstChild
)
1391 def WriteText(self
, text
):
1392 if text
[-1:] == '\n':
1396 def write(self
, txt
):
1399 #---------------------------------------------
1400 def OnItemExpanded(self
, event
):
1401 item
= event
.GetItem()
1402 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1405 #---------------------------------------------
1406 def OnItemCollapsed(self
, event
):
1407 item
= event
.GetItem()
1408 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1411 #---------------------------------------------
1412 def OnTreeLeftDown(self
, event
):
1413 # reset the overview text if the tree item is clicked on again
1414 pt
= event
.GetPosition();
1415 item
, flags
= self
.tree
.HitTest(pt
)
1416 if item
== self
.tree
.GetSelection():
1417 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1420 #---------------------------------------------
1421 def OnSelChanged(self
, event
):
1422 if self
.dying
or not self
.loaded
:
1425 item
= event
.GetItem()
1426 itemText
= self
.tree
.GetItemText(item
)
1427 self
.LoadDemo(itemText
)
1429 #---------------------------------------------
1430 def LoadDemo(self
, demoName
):
1432 wx
.BeginBusyCursor()
1435 self
.ShutdownDemoModule()
1437 if demoName
== self
.overviewText
:
1438 # User selected the "wxPython Overview" node
1440 # Changing the main window at runtime not yet supported...
1441 self
.demoModules
= DemoModules(__name__
)
1442 self
.SetOverview(self
.overviewText
, mainOverview
)
1443 self
.LoadDemoSource()
1444 self
.UpdateNotebook(0)
1446 if os
.path
.exists(GetOriginalFilename(demoName
)):
1447 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1448 self
.demoModules
= DemoModules(demoName
)
1449 self
.LoadDemoSource()
1452 self
.SetOverview("wxPython", mainOverview
)
1453 self
.codePage
= None
1454 self
.UpdateNotebook(0)
1458 #---------------------------------------------
1459 def LoadDemoSource(self
):
1460 self
.codePage
= None
1461 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1462 self
.codePage
.LoadDemo(self
.demoModules
)
1464 #---------------------------------------------
1465 def RunModule(self
):
1466 """Runs the active module"""
1468 module
= self
.demoModules
.GetActive()
1469 self
.ShutdownDemoModule()
1472 # o The RunTest() for all samples must now return a window that can
1473 # be palced in a tab in the main notebook.
1474 # o If an error occurs (or has occurred before) an error tab is created.
1476 if module
is not None:
1477 wx
.LogMessage("Running demo module...")
1478 if hasattr(module
, "overview"):
1479 overviewText
= module
.overview
1482 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1484 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1485 DemoError(sys
.exc_info()), self
)
1487 assert self
.demoPage
is not None, "runTest must return a window!"
1490 # There was a previous error in compiling or exec-ing
1491 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1492 self
.demoModules
.GetErrorInfo(), self
)
1494 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1497 # cahnge to the demo page the first time a module is run
1498 self
.UpdateNotebook(2)
1499 self
.firstTime
= False
1501 # otherwise just stay on the same tab in case the user has changed to another one
1502 self
.UpdateNotebook()
1504 #---------------------------------------------
1505 def ShutdownDemoModule(self
):
1507 # inform the window that it's time to quit if it cares
1508 if hasattr(self
.demoPage
, "ShutdownDemo"):
1509 self
.demoPage
.ShutdownDemo()
1510 wx
.YieldIfNeeded() # in case the page has pending events
1511 self
.demoPage
= None
1513 #---------------------------------------------
1514 def UpdateNotebook(self
, select
= -1):
1518 def UpdatePage(page
, pageText
):
1521 for i
in range(nb
.GetPageCount()):
1522 if nb
.GetPageText(i
) == pageText
:
1530 nb
.AddPage(page
, pageText
)
1531 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1533 if nb
.GetPage(pagePos
) != page
:
1534 # Reload an existing page
1536 nb
.DeletePage(pagePos
)
1537 nb
.InsertPage(pagePos
, page
, pageText
)
1539 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1541 # Excellent! No redraw/flicker
1542 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1545 nb
.DeletePage(pagePos
)
1546 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1548 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1551 select
= nb
.GetSelection()
1553 UpdatePage(self
.codePage
, "Demo Code")
1554 UpdatePage(self
.demoPage
, "Demo")
1556 if select
>= 0 and select
< nb
.GetPageCount():
1557 nb
.SetSelection(select
)
1559 #---------------------------------------------
1560 def SetOverview(self
, name
, text
):
1561 self
.curOverview
= text
1563 if lead
!= '<html>' and lead
!= '<HTML>':
1564 text
= '<br>'.join(text
.split('\n'))
1566 text
= text
.decode('iso8859_1')
1567 self
.ovr
.SetPage(text
)
1568 self
.nb
.SetPageText(0, name
)
1570 #---------------------------------------------
1572 def OnFileExit(self
, *event
):
1575 def OnToggleRedirect(self
, event
):
1579 print "Print statements and other standard output will now be directed to this window."
1582 print "Print statements and other standard output will now be sent to the usual location."
1584 def OnHelpAbout(self
, event
):
1585 from About
import MyAboutBox
1586 about
= MyAboutBox(self
)
1590 def OnHelpFind(self
, event
):
1591 if self
.finddlg
!= None:
1594 self
.nb
.SetSelection(1)
1595 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1596 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1597 self
.finddlg
.Show(True)
1600 def OnUpdateFindItems(self
, evt
):
1601 evt
.Enable(self
.finddlg
== None)
1604 def OnFind(self
, event
):
1605 editor
= self
.codePage
.editor
1606 self
.nb
.SetSelection(1)
1607 end
= editor
.GetLastPosition()
1608 textstring
= editor
.GetRange(0, end
).lower()
1609 findstring
= self
.finddata
.GetFindString().lower()
1610 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1612 start
= editor
.GetSelection()[0]
1613 loc
= textstring
.rfind(findstring
, 0, start
)
1615 start
= editor
.GetSelection()[1]
1616 loc
= textstring
.find(findstring
, start
)
1617 if loc
== -1 and start
!= 0:
1618 # string not found, start at beginning
1621 loc
= textstring
.rfind(findstring
, 0, start
)
1624 loc
= textstring
.find(findstring
, start
)
1626 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1627 'Find String Not Found in Demo File',
1628 wx
.OK | wx
.ICON_INFORMATION
)
1633 self
.finddlg
.SetFocus()
1636 self
.finddlg
.Destroy()
1638 editor
.ShowPosition(loc
)
1639 editor
.SetSelection(loc
, loc
+ len(findstring
))
1643 def OnFindNext(self
, event
):
1644 if self
.finddata
.GetFindString():
1647 self
.OnHelpFind(event
)
1649 def OnFindClose(self
, event
):
1650 event
.GetDialog().Destroy()
1654 def OnOpenShellWindow(self
, evt
):
1656 # if it already exists then just make sure it's visible
1662 # Make a PyShell window
1664 namespace
= { 'wx' : wx
,
1665 'app' : wx
.GetApp(),
1668 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1669 self
.shell
.SetSize((640,480))
1672 # Hook the close event of the main frame window so that we
1673 # close the shell at the same time if it still exists
1674 def CloseShell(evt
):
1678 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
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():
1779 import wx
.lib
.mixins
.inspect
1781 class MyApp(wx
.App
, wx
.lib
.mixins
.inspect
.InspectionMixin
):
1784 Create and show the splash screen. It will then create and show
1785 the main frame when it is time to do so.
1788 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1791 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1793 # Normally when using a SplashScreen you would create it, show
1794 # it and then continue on with the applicaiton's
1795 # initialization, finally creating and showing the main
1796 # application window(s). In this case we have nothing else to
1797 # do so we'll delay showing the main frame until later (see
1798 # ShowMain above) so the users can see the SplashScreen effect.
1799 splash
= MySplashScreen()
1802 # Setup the InspectionMixin
1809 #---------------------------------------------------------------------------
1813 demoPath
= os
.path
.dirname(__file__
)
1820 #---------------------------------------------------------------------------
1823 mainOverview
= """<html><body>
1826 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1827 language. It allows Python programmers to create programs with a
1828 robust, highly functional graphical user interface, simply and easily.
1829 It is implemented as a Python extension module (native code) that
1830 wraps the popular wxWindows cross platform GUI library, which is
1833 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1834 means that it is free for anyone to use and the source code is
1835 available for anyone to look at and modify. Or anyone can contribute
1836 fixes or enhancements to the project.
1838 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1839 same program will run on multiple platforms without modification.
1840 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1841 or unix-like systems, and Macintosh OS X. Since the language is
1842 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1845 <p> <b>This demo</b> is not only a collection of test cases for
1846 wxPython, but is also designed to help you learn about and how to use
1847 wxPython. Each sample is listed in the tree control on the left.
1848 When a sample is selected in the tree then a module is loaded and run
1849 (usually in a tab of this notebook,) and the source code of the module
1850 is loaded in another tab for you to browse and learn from.
1855 #----------------------------------------------------------------------------
1856 #----------------------------------------------------------------------------
1858 if __name__
== '__main__':
1862 #----------------------------------------------------------------------------