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', [
163 # controls coming from other librairies
164 ('More Windows/Controls', [
171 'PyCrustWithFilling',
176 'wxDynamicSashWindow',
182 'wxMimeTypesManager',
184 'wxStyledTextCtrl_1',
185 'wxStyledTextCtrl_2',
189 # How to lay out the controls in a frame/dialog
195 'wxLayoutConstraints',
200 ('Process and Events', [
210 ('Clipboard and DnD', [
238 # need libs not coming with the demo
239 ('Objects using an external library', [
240 'ActiveXWrapper_Acrobat',
247 # pyTree, hangman, ... in the samples dir
248 ('Check out the samples dir too', [
255 #---------------------------------------------------------------------------
257 class MyLog(wxPyLog
):
258 def __init__(self
, textCtrl
, logTime
=0):
259 wxPyLog
.__init
__(self
)
261 self
.logTime
= logTime
263 def DoLogString(self
, message
, timeStamp
):
265 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
267 self
.tc
.AppendText(message
+ '\n')
270 #---------------------------------------------------------------------------
273 """Convert paths to the platform-specific separator"""
274 return apply(os
.path
.join
, tuple(string
.split(path
, '/')))
277 #---------------------------------------------------------------------------
279 class wxPythonDemo(wxFrame
):
280 overviewText
= "wxPython Overview"
282 def __init__(self
, parent
, id, title
):
283 wxFrame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
284 style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
)
286 self
.cwd
= os
.getcwd()
287 self
.curOverview
= ""
289 icon
= images
.getMondrianIcon()
292 if wxPlatform
== '__WXMSW__':
293 # setup a taskbar icon, and catch some events from it
294 self
.tbicon
= wxTaskBarIcon()
295 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
296 EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
297 EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
298 EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
299 EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
304 EVT_IDLE(self
, self
.OnIdle
)
305 EVT_CLOSE(self
, self
.OnCloseWindow
)
306 EVT_ICONIZE(self
, self
.OnIconfiy
)
307 EVT_MAXIMIZE(self
, self
.OnMaximize
)
310 self
.CreateStatusBar(1, wxST_SIZEGRIP
)
312 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
313 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
315 def EmptyHandler(evt
): pass
316 EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
)
317 EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
)
319 # Prevent TreeCtrl from displaying all items after destruction when true
323 self
.mainmenu
= wxMenuBar()
326 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
327 EVT_MENU(self
, exitID
, self
.OnFileExit
)
328 self
.mainmenu
.Append(menu
, '&File')
332 for item
in _treeList
:
334 for childItem
in item
[1]:
336 submenu
.Append(mID
, childItem
)
337 EVT_MENU(self
, mID
, self
.OnDemoMenu
)
338 menu
.AppendMenu(wxNewId(), item
[0], submenu
)
339 self
.mainmenu
.Append(menu
, '&Demo')
345 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
346 EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
347 self
.mainmenu
.Append(menu
, '&Help')
348 self
.SetMenuBar(self
.mainmenu
)
350 # set the menu accellerator table...
351 aTable
= wxAcceleratorTable([(wxACCEL_ALT
, ord('X'), exitID
),
352 (wxACCEL_CTRL
, ord('H'), helpID
)])
353 self
.SetAcceleratorTable(aTable
)
359 self
.tree
= wxTreeCtrl(splitter
, tID
,
360 style
=wxTR_HAS_BUTTONS |
362 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
364 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
365 root
= self
.tree
.AddRoot("wxPython Overview")
367 for item
in _treeList
:
368 child
= self
.tree
.AppendItem(root
, item
[0])
369 if not firstChild
: firstChild
= child
370 for childItem
in item
[1]:
371 theDemo
= self
.tree
.AppendItem(child
, childItem
)
372 self
.treeMap
[childItem
] = theDemo
374 self
.tree
.Expand(root
)
375 self
.tree
.Expand(firstChild
)
376 EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
377 EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
378 EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
379 EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
382 self
.nb
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
)
384 # Set up a wxHtmlWindow on the Overview Notebook page
385 # we put it in a panel first because there seems to be a
386 # refresh bug of some sort (wxGTK) when it is directly in
389 self
.ovr
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400))
390 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
392 else: # hopefully I can remove this hacky code soon, see bug #216861
393 panel
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
)
394 self
.ovr
= wxHtmlWindow(panel
, -1, size
=(400, 400))
395 self
.nb
.AddPage(panel
, self
.overviewText
)
397 def OnOvrSize(evt
, ovr
=self
.ovr
):
398 ovr
.SetSize(evt
.GetSize())
400 EVT_SIZE(panel
, OnOvrSize
)
401 EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
404 self
.SetOverview(self
.overviewText
, overview
)
407 # Set up a TextCtrl on the Demo Code Notebook page
408 self
.txt
= wxTextCtrl(self
.nb
, -1,
409 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
410 self
.nb
.AddPage(self
.txt
, "Demo Code")
413 # Set up a log on the View Log Notebook page
414 self
.log
= wxTextCtrl(splitter2
, -1,
415 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
417 # Set the wxWindows log target to be this textctrl
418 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
420 # But instead of the above we want to show how to use our own wxLog class
421 wxLog_SetActiveTarget(MyLog(self
.log
))
427 # add the windows to the splitter and split it.
428 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
429 splitter
.SplitVertically(self
.tree
, splitter2
)
431 splitter
.SetSashPosition(180, true
)
432 splitter
.SetMinimumPaneSize(20)
433 splitter2
.SetSashPosition(450, true
)
434 splitter2
.SetMinimumPaneSize(20)
438 # select initial items
439 self
.nb
.SetSelection(0)
440 self
.tree
.SelectItem(root
)
442 if len(sys
.argv
) == 2:
444 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
448 self
.tree
.SelectItem(selectedDemo
)
449 self
.tree
.EnsureVisible(selectedDemo
)
452 wxLogMessage('window handle: %s' % self
.GetHandle())
455 #---------------------------------------------
456 def WriteText(self
, text
):
457 if text
[-1:] == '\n':
462 def write(self
, txt
):
465 #---------------------------------------------
466 def OnItemExpanded(self
, event
):
467 item
= event
.GetItem()
468 wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
471 #---------------------------------------------
472 def OnItemCollapsed(self
, event
):
473 item
= event
.GetItem()
474 wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
477 #---------------------------------------------
478 def OnTreeLeftDown(self
, event
):
479 pt
= event
.GetPosition();
480 item
, flags
= self
.tree
.HitTest(pt
)
481 if item
== self
.tree
.GetSelection():
482 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
485 #---------------------------------------------
486 def OnSelChanged(self
, event
):
490 item
= event
.GetItem()
491 itemText
= self
.tree
.GetItemText(item
)
492 self
.RunDemo(itemText
)
495 #---------------------------------------------
496 def RunDemo(self
, itemText
):
498 if self
.nb
.GetPageCount() == 3:
499 if self
.nb
.GetSelection() == 2:
500 self
.nb
.SetSelection(0)
501 self
.nb
.DeletePage(2)
503 if itemText
== self
.overviewText
:
504 self
.GetDemoFile('Main.py')
505 self
.SetOverview(self
.overviewText
, overview
)
510 if os
.path
.exists(itemText
+ '.py'):
512 wxLogMessage("Running demo %s.py..." % itemText
)
514 self
.GetDemoFile(itemText
+ '.py')
515 module
= __import__(itemText
, globals())
516 self
.SetOverview(itemText
+ " Overview", module
.overview
)
520 # in case runTest is modal, make sure things look right...
524 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
526 self
.nb
.AddPage(self
.window
, 'Demo')
527 #wxYield() TODO: Is this still needed?
528 self
.nb
.SetSelection(2)
529 self
.nb
.Refresh() # without this wxMac has troubles showing the just added page
538 #---------------------------------------------
540 def GetDemoFile(self
, filename
):
543 self
.txt
.SetValue(open(filename
).read())
545 self
.txt
.WriteText("Cannot open %s file." % filename
)
547 self
.txt
.SetInsertionPoint(0)
548 self
.txt
.ShowPosition(0)
550 #---------------------------------------------
551 def SetOverview(self
, name
, text
):
552 self
.curOverview
= text
554 if lead
!= '<html>' and lead
!= '<HTML>':
555 text
= string
.join(string
.split(text
, '\n'), '<br>')
556 self
.ovr
.SetPage(text
)
557 self
.nb
.SetPageText(0, name
)
559 #---------------------------------------------
561 def OnFileExit(self
, *event
):
565 def OnHelpAbout(self
, event
):
566 from About
import MyAboutBox
567 about
= MyAboutBox(self
)
572 #---------------------------------------------
573 def OnCloseWindow(self
, event
):
577 if hasattr(self
, "tbicon"):
582 #---------------------------------------------
583 def OnIdle(self
, event
):
585 self
.otherWin
.Raise()
586 self
.window
= self
.otherWin
594 #---------------------------------------------
597 showTipText
= open(opj("data/showTips")).read()
598 showTip
, index
= eval(showTipText
)
600 showTip
, index
= (1, 0)
602 tp
= wxCreateFileTipProvider(opj("data/tips.txt"), index
)
603 showTip
= wxShowTip(self
, tp
)
604 index
= tp
.GetCurrentTip()
605 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
608 #---------------------------------------------
609 def OnDemoMenu(self
, event
):
611 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
615 self
.tree
.SelectItem(selectedDemo
)
616 self
.tree
.EnsureVisible(selectedDemo
)
619 #---------------------------------------------
620 def OnTaskBarActivate(self
, evt
):
621 if self
.IsIconized():
623 if not self
.IsShown():
627 #---------------------------------------------
629 TBMENU_RESTORE
= 1000
632 def OnTaskBarMenu(self
, evt
):
634 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
635 menu
.Append(self
.TBMENU_CLOSE
, "Close")
636 self
.tbicon
.PopupMenu(menu
)
639 #---------------------------------------------
640 def OnTaskBarClose(self
, evt
):
643 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
644 # prod the main idle handler a bit to get the window to actually close
645 wxGetApp().ProcessIdle()
648 #---------------------------------------------
649 def OnIconfiy(self
, evt
):
650 wxLogMessage("OnIconfiy")
653 #---------------------------------------------
654 def OnMaximize(self
, evt
):
655 wxLogMessage("OnMaximize")
661 #---------------------------------------------------------------------------
662 #---------------------------------------------------------------------------
664 class MySplashScreen(wxSplashScreen
):
666 bmp
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
667 wxSplashScreen
.__init
__(self
, bmp
,
668 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
,
670 EVT_CLOSE(self
, self
.OnClose
)
672 def OnClose(self
, evt
):
673 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
675 evt
.Skip() # Make sure the default handler runs too...
681 Create and show the splash screen. It will then create and show
682 the main frame when it is time to do so.
684 wxInitAllImageHandlers()
685 splash
= MySplashScreen()
691 #---------------------------------------------------------------------------
695 demoPath
= os
.path
.dirname(__file__
)
703 #---------------------------------------------------------------------------
707 overview
= """<html><body>
710 Python is an interpreted, interactive, object-oriented programming
711 language often compared to Tcl, Perl, Scheme, or Java.
713 <p> Python combines remarkable power with very clear syntax. It has
714 modules, classes, exceptions, very high level dynamic data types, and
715 dynamic typing. There are interfaces to many system calls and
716 libraries, and new built-in modules are easily written in C or
717 C++. Python is also usable as an extension language for applications
718 that need a programmable interface. <p>
722 wxWindows is a free C++ framework designed to make cross-platform
723 programming child's play. Well, almost. wxWindows 2 supports Windows
724 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
725 underway. Other ports are under consideration. <p>
727 wxWindows is a set of libraries that allows C++ applications to
728 compile and run on several different types of computers, with minimal
729 source code changes. There is one library per supported GUI (such as
730 Motif, or Windows). As well as providing a common API (Application
731 Programming Interface) for GUI functionality, it provides
732 functionality for accessing some commonly-used operating system
733 facilities, such as copying or deleting files. wxWindows is a
734 'framework' in the sense that it provides a lot of built-in
735 functionality, which the application can use or replace as required,
736 thus saving a great deal of coding effort. Basic data structures such
737 as strings, linked lists and hash tables are also supported.
742 wxPython is a Python extension module that encapsulates the wxWindows
743 GUI classes. Currently it is only available for the Win32 and GTK
744 ports of wxWindows, but as soon as the other ports are brought up to
745 the same level as Win32 and GTK, it should be fairly trivial to
746 enable wxPython to be used with the new GUI.
750 The wxPython extension module attempts to mirror the class heiarchy
751 of wxWindows as closely as possible. This means that there is a
752 wxFrame class in wxPython that looks, smells, tastes and acts almost
753 the same as the wxFrame class in the C++ version. Unfortunately,
754 because of differences in the languages, wxPython doesn't match
755 wxWindows exactly, but the differences should be easy to absorb
756 because they are natural to Python. For example, some methods that
757 return multiple values via argument pointers in C++ will return a
758 tuple of values in Python.
762 There is still much to be done for wxPython, many classes still need
763 to be mirrored. Also, wxWindows is still somewhat of a moving target
764 so it is a bit of an effort just keeping wxPython up to date. On the
765 other hand, there are enough of the core classes completed that
766 useful applications can be written.
770 wxPython is close enough to the C++ version that the majority of
771 the wxPython documentation is actually just notes attached to the C++
772 documents that describe the places where wxPython is different. There
773 is also a series of sample programs included, and a series of
774 documentation pages that assist the programmer in getting started
780 #----------------------------------------------------------------------------
781 #----------------------------------------------------------------------------
783 if __name__
== '__main__':
786 #----------------------------------------------------------------------------