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 #----------------------------------------------------------------------------
14 import sys
, os
, time
, string
15 from wxPython
.wx
import *
16 from wxPython
.html
import wxHtmlWindow
20 #---------------------------------------------------------------------------
24 ## ('New since last release', ['wxGenericDirCtrl',
25 ## 'wxImageFromStream',
31 ## ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
32 ## 'wxGrid', 'wxSashWindow',
33 ## 'wxScrolledWindow', 'wxSplitterWindow',
34 ## 'wxStatusBar', 'wxNotebook',
36 ## 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
38 ## 'wxDynamicSashWindow',
41 ## ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
42 ## 'wxSingleChoiceDialog', 'wxTextEntryDialog',
43 ## 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
44 ## 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
47 ## ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
48 ## 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'VirtualListCtrl',
50 ## 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
51 ## 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
52 ## 'wxCalendarCtrl', 'wxToggleButton',
53 ## 'wxEditableListBox', 'wxLEDNumberCtrl',
56 ## ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource',
60 ## ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
62 ## 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
63 ## 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
64 ## 'PythonEvents', 'Threads',
65 ## 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
66 ## 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
67 ## 'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
68 ## 'ContextHelp', 'SplitTree', 'Unicode', 'wxFileHistory',
71 ## ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
72 ## 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
73 ## 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
74 ## 'FileBrowseButton', 'GenericButtons', 'wxEditor',
75 ## 'ColourSelect', 'ImageBrowser',
76 ## 'infoframe', 'ColourDB', 'PyCrust', 'PyCrustWithFilling',
81 ## ('Cool Contribs', ['pyTree', 'hangman',
91 ('New since last release', [
99 # managed windows == things with a caption you can close
100 ('Base Frames and Dialogs', [
112 'wxFindReplaceDialog',
118 'wxSingleChoiceDialog',
122 # dialogs form libraries
126 'wxMultipleChoiceDialog',
127 'wxScrolledMessageDialog',
131 ('Core Windows/Controls', [
162 # controls coming from other librairies
163 ('More Windows/Controls', [
170 'PyCrustWithFilling',
175 'wxDynamicSashWindow',
181 'wxMimeTypesManager',
183 'wxStyledTextCtrl_1',
184 'wxStyledTextCtrl_2',
188 # How to lay out the controls in a frame/dialog
194 'wxLayoutConstraints',
199 ('Process and Events', [
209 ('Clipboard and DnD', [
237 # need libs not coming with the demo
238 ('Objects using an external library', [
239 'ActiveXWrapper_Acrobat',
246 # pyTree, hangman, ... in the samples dir
247 ('Check out the samples dir too', [
254 #---------------------------------------------------------------------------
256 class MyLog(wxPyLog
):
257 def __init__(self
, textCtrl
, logTime
=0):
258 wxPyLog
.__init
__(self
)
260 self
.logTime
= logTime
262 def DoLogString(self
, message
, timeStamp
):
264 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
266 self
.tc
.AppendText(message
+ '\n')
269 #---------------------------------------------------------------------------
272 """Convert paths to the platform-specific separator"""
273 return apply(os
.path
.join
, tuple(string
.split(path
, '/')))
276 #---------------------------------------------------------------------------
278 class wxPythonDemo(wxFrame
):
279 overviewText
= "wxPython Overview"
281 def __init__(self
, parent
, id, title
):
282 wxFrame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
283 style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
)
285 self
.cwd
= os
.getcwd()
286 self
.curOverview
= ""
288 icon
= images
.getMondrianIcon()
291 if wxPlatform
== '__WXMSW__':
292 # setup a taskbar icon, and catch some events from it
293 self
.tbicon
= wxTaskBarIcon()
294 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
295 EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
296 EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
297 EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
298 EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
303 EVT_IDLE(self
, self
.OnIdle
)
304 EVT_CLOSE(self
, self
.OnCloseWindow
)
305 EVT_ICONIZE(self
, self
.OnIconfiy
)
306 EVT_MAXIMIZE(self
, self
.OnMaximize
)
309 self
.CreateStatusBar(1, wxST_SIZEGRIP
)
311 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
312 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
314 def EmptyHandler(evt
): pass
315 EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
)
316 EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
)
318 # Prevent TreeCtrl from displaying all items after destruction when true
322 self
.mainmenu
= wxMenuBar()
325 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
326 EVT_MENU(self
, exitID
, self
.OnFileExit
)
327 self
.mainmenu
.Append(menu
, '&File')
331 for item
in _treeList
:
333 for childItem
in item
[1]:
335 submenu
.Append(mID
, childItem
)
336 EVT_MENU(self
, mID
, self
.OnDemoMenu
)
337 menu
.AppendMenu(wxNewId(), item
[0], submenu
)
338 self
.mainmenu
.Append(menu
, '&Demo')
344 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
345 EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
346 self
.mainmenu
.Append(menu
, '&Help')
347 self
.SetMenuBar(self
.mainmenu
)
349 # set the menu accellerator table...
350 aTable
= wxAcceleratorTable([(wxACCEL_ALT
, ord('X'), exitID
),
351 (wxACCEL_CTRL
, ord('H'), helpID
)])
352 self
.SetAcceleratorTable(aTable
)
358 self
.tree
= wxTreeCtrl(splitter
, tID
,
359 style
=wxTR_HAS_BUTTONS |
361 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
363 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
364 root
= self
.tree
.AddRoot("wxPython Overview")
366 for item
in _treeList
:
367 child
= self
.tree
.AppendItem(root
, item
[0])
368 if not firstChild
: firstChild
= child
369 for childItem
in item
[1]:
370 theDemo
= self
.tree
.AppendItem(child
, childItem
)
371 self
.treeMap
[childItem
] = theDemo
373 self
.tree
.Expand(root
)
374 self
.tree
.Expand(firstChild
)
375 EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
376 EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
377 EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
378 EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
381 self
.nb
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
)
383 # Set up a wxHtmlWindow on the Overview Notebook page
384 # we put it in a panel first because there seems to be a
385 # refresh bug of some sort (wxGTK) when it is directly in
388 self
.ovr
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400))
389 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
391 else: # hopefully I can remove this hacky code soon, see bug #216861
392 panel
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
)
393 self
.ovr
= wxHtmlWindow(panel
, -1, size
=(400, 400))
394 self
.nb
.AddPage(panel
, self
.overviewText
)
396 def OnOvrSize(evt
, ovr
=self
.ovr
):
397 ovr
.SetSize(evt
.GetSize())
399 EVT_SIZE(panel
, OnOvrSize
)
400 EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
403 self
.SetOverview(self
.overviewText
, overview
)
406 # Set up a TextCtrl on the Demo Code Notebook page
407 self
.txt
= wxTextCtrl(self
.nb
, -1,
408 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
409 self
.nb
.AddPage(self
.txt
, "Demo Code")
412 # Set up a log on the View Log Notebook page
413 self
.log
= wxTextCtrl(splitter2
, -1,
414 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
416 # Set the wxWindows log target to be this textctrl
417 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
419 # But instead of the above we want to show how to use our own wxLog class
420 wxLog_SetActiveTarget(MyLog(self
.log
))
426 # add the windows to the splitter and split it.
427 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
428 splitter
.SplitVertically(self
.tree
, splitter2
)
430 splitter
.SetSashPosition(180, true
)
431 splitter
.SetMinimumPaneSize(20)
432 splitter2
.SetSashPosition(450, true
)
433 splitter2
.SetMinimumPaneSize(20)
437 # select initial items
438 self
.nb
.SetSelection(0)
439 self
.tree
.SelectItem(root
)
441 if len(sys
.argv
) == 2:
443 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
447 self
.tree
.SelectItem(selectedDemo
)
448 self
.tree
.EnsureVisible(selectedDemo
)
451 wxLogMessage('window handle: %s' % self
.GetHandle())
454 #---------------------------------------------
455 def WriteText(self
, text
):
456 if text
[-1:] == '\n':
461 def write(self
, txt
):
464 #---------------------------------------------
465 def OnItemExpanded(self
, event
):
466 item
= event
.GetItem()
467 wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
470 #---------------------------------------------
471 def OnItemCollapsed(self
, event
):
472 item
= event
.GetItem()
473 wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
476 #---------------------------------------------
477 def OnTreeLeftDown(self
, event
):
478 pt
= event
.GetPosition();
479 item
, flags
= self
.tree
.HitTest(pt
)
480 if item
== self
.tree
.GetSelection():
481 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
484 #---------------------------------------------
485 def OnSelChanged(self
, event
):
489 item
= event
.GetItem()
490 itemText
= self
.tree
.GetItemText(item
)
491 self
.RunDemo(itemText
)
494 #---------------------------------------------
495 def RunDemo(self
, itemText
):
497 if self
.nb
.GetPageCount() == 3:
498 if self
.nb
.GetSelection() == 2:
499 self
.nb
.SetSelection(0)
500 self
.nb
.DeletePage(2)
502 if itemText
== self
.overviewText
:
503 self
.GetDemoFile('Main.py')
504 self
.SetOverview(self
.overviewText
, overview
)
509 if os
.path
.exists(itemText
+ '.py'):
511 wxLogMessage("Running demo %s.py..." % itemText
)
513 self
.GetDemoFile(itemText
+ '.py')
514 module
= __import__(itemText
, globals())
515 self
.SetOverview(itemText
+ " Overview", module
.overview
)
519 # in case runTest is modal, make sure things look right...
523 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
525 self
.nb
.AddPage(self
.window
, 'Demo')
526 #wxYield() TODO: Is this still needed?
527 self
.nb
.SetSelection(2)
528 self
.nb
.Refresh() # without this wxMac has troubles showing the just added page
537 #---------------------------------------------
539 def GetDemoFile(self
, filename
):
542 self
.txt
.SetValue(open(filename
).read())
544 self
.txt
.WriteText("Cannot open %s file." % filename
)
546 self
.txt
.SetInsertionPoint(0)
547 self
.txt
.ShowPosition(0)
549 #---------------------------------------------
550 def SetOverview(self
, name
, text
):
551 self
.curOverview
= text
553 if lead
!= '<html>' and lead
!= '<HTML>':
554 text
= string
.join(string
.split(text
, '\n'), '<br>')
555 self
.ovr
.SetPage(text
)
556 self
.nb
.SetPageText(0, name
)
558 #---------------------------------------------
560 def OnFileExit(self
, *event
):
564 def OnHelpAbout(self
, event
):
565 from About
import MyAboutBox
566 about
= MyAboutBox(self
)
571 #---------------------------------------------
572 def OnCloseWindow(self
, event
):
576 if hasattr(self
, "tbicon"):
581 #---------------------------------------------
582 def OnIdle(self
, event
):
584 self
.otherWin
.Raise()
585 self
.window
= self
.otherWin
593 #---------------------------------------------
596 showTipText
= open(opj("data/showTips")).read()
597 showTip
, index
= eval(showTipText
)
599 showTip
, index
= (1, 0)
601 tp
= wxCreateFileTipProvider(opj("data/tips.txt"), index
)
602 showTip
= wxShowTip(self
, tp
)
603 index
= tp
.GetCurrentTip()
604 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
607 #---------------------------------------------
608 def OnDemoMenu(self
, event
):
610 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
614 self
.tree
.SelectItem(selectedDemo
)
615 self
.tree
.EnsureVisible(selectedDemo
)
618 #---------------------------------------------
619 def OnTaskBarActivate(self
, evt
):
620 if self
.IsIconized():
622 if not self
.IsShown():
626 #---------------------------------------------
628 TBMENU_RESTORE
= 1000
631 def OnTaskBarMenu(self
, evt
):
633 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
634 menu
.Append(self
.TBMENU_CLOSE
, "Close")
635 self
.tbicon
.PopupMenu(menu
)
638 #---------------------------------------------
639 def OnTaskBarClose(self
, evt
):
642 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
643 # prod the main idle handler a bit to get the window to actually close
644 wxGetApp().ProcessIdle()
647 #---------------------------------------------
648 def OnIconfiy(self
, evt
):
649 wxLogMessage("OnIconfiy")
652 #---------------------------------------------
653 def OnMaximize(self
, evt
):
654 wxLogMessage("OnMaximize")
660 #---------------------------------------------------------------------------
661 #---------------------------------------------------------------------------
663 class MySplashScreen(wxSplashScreen
):
665 bmp
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
666 wxSplashScreen
.__init
__(self
, bmp
,
667 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
,
669 EVT_CLOSE(self
, self
.OnClose
)
671 def OnClose(self
, evt
):
672 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
674 evt
.Skip() # Make sure the default handler runs too...
680 Create and show the splash screen. It will then create and show
681 the main frame when it is time to do so.
683 wxInitAllImageHandlers()
684 splash
= MySplashScreen()
690 #---------------------------------------------------------------------------
694 demoPath
= os
.path
.dirname(__file__
)
702 #---------------------------------------------------------------------------
706 overview
= """<html><body>
709 Python is an interpreted, interactive, object-oriented programming
710 language often compared to Tcl, Perl, Scheme, or Java.
712 <p> Python combines remarkable power with very clear syntax. It has
713 modules, classes, exceptions, very high level dynamic data types, and
714 dynamic typing. There are interfaces to many system calls and
715 libraries, and new built-in modules are easily written in C or
716 C++. Python is also usable as an extension language for applications
717 that need a programmable interface. <p>
721 wxWindows is a free C++ framework designed to make cross-platform
722 programming child's play. Well, almost. wxWindows 2 supports Windows
723 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
724 underway. Other ports are under consideration. <p>
726 wxWindows is a set of libraries that allows C++ applications to
727 compile and run on several different types of computers, with minimal
728 source code changes. There is one library per supported GUI (such as
729 Motif, or Windows). As well as providing a common API (Application
730 Programming Interface) for GUI functionality, it provides
731 functionality for accessing some commonly-used operating system
732 facilities, such as copying or deleting files. wxWindows is a
733 'framework' in the sense that it provides a lot of built-in
734 functionality, which the application can use or replace as required,
735 thus saving a great deal of coding effort. Basic data structures such
736 as strings, linked lists and hash tables are also supported.
741 wxPython is a Python extension module that encapsulates the wxWindows
742 GUI classes. Currently it is only available for the Win32 and GTK
743 ports of wxWindows, but as soon as the other ports are brought up to
744 the same level as Win32 and GTK, it should be fairly trivial to
745 enable wxPython to be used with the new GUI.
749 The wxPython extension module attempts to mirror the class heiarchy
750 of wxWindows as closely as possible. This means that there is a
751 wxFrame class in wxPython that looks, smells, tastes and acts almost
752 the same as the wxFrame class in the C++ version. Unfortunately,
753 because of differences in the languages, wxPython doesn't match
754 wxWindows exactly, but the differences should be easy to absorb
755 because they are natural to Python. For example, some methods that
756 return multiple values via argument pointers in C++ will return a
757 tuple of values in Python.
761 There is still much to be done for wxPython, many classes still need
762 to be mirrored. Also, wxWindows is still somewhat of a moving target
763 so it is a bit of an effort just keeping wxPython up to date. On the
764 other hand, there are enough of the core classes completed that
765 useful applications can be written.
769 wxPython is close enough to the C++ version that the majority of
770 the wxPython documentation is actually just notes attached to the C++
771 documents that describe the places where wxPython is different. There
772 is also a series of sample programs included, and a series of
773 documentation pages that assist the programmer in getting started
779 #----------------------------------------------------------------------------
780 #----------------------------------------------------------------------------
782 if __name__
== '__main__':
785 #----------------------------------------------------------------------------