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
18 ##from wxPython.stc import *
22 #---------------------------------------------------------------------------
27 ('New since last release', [
39 # managed windows == things with a caption you can close
40 ('Base Frames and Dialogs', [
52 'wxFindReplaceDialog',
58 'wxSingleChoiceDialog',
62 # dialogs form libraries
66 'wxMultipleChoiceDialog',
67 'wxScrolledMessageDialog',
71 ('Core Windows/Controls', [
103 # controls coming from other librairies
104 ('More Windows/Controls', [
111 'PyCrustWithFilling',
116 'wxDynamicSashWindow',
123 'wxMimeTypesManager',
126 'wxStyledTextCtrl_1',
127 'wxStyledTextCtrl_2',
130 # How to lay out the controls in a frame/dialog
137 'wxLayoutConstraints',
142 ('Process and Events', [
152 ('Clipboard and DnD', [
181 # need libs not coming with the demo
182 ('Objects using an external library', [
183 'ActiveXWrapper_Acrobat',
190 ('Check out the samples dir too', [
197 #---------------------------------------------------------------------------
199 class MyLog(wxPyLog
):
200 def __init__(self
, textCtrl
, logTime
=0):
201 wxPyLog
.__init
__(self
)
203 self
.logTime
= logTime
205 def DoLogString(self
, message
, timeStamp
):
207 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
209 self
.tc
.AppendText(message
+ '\n')
212 #---------------------------------------------------------------------------
215 """Convert paths to the platform-specific separator"""
216 return apply(os
.path
.join
, tuple(string
.split(path
, '/')))
219 #---------------------------------------------------------------------------
221 class wxPythonDemo(wxFrame
):
222 overviewText
= "wxPython Overview"
224 def __init__(self
, parent
, id, title
):
225 wxFrame
.__init
__(self
, parent
, -1, title
, size
= (800, 600),
226 style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
)
228 self
.cwd
= os
.getcwd()
229 self
.curOverview
= ""
231 icon
= images
.getMondrianIcon()
234 if wxPlatform
== '__WXMSW__':
235 # setup a taskbar icon, and catch some events from it
236 self
.tbicon
= wxTaskBarIcon()
237 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
238 EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
)
239 EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
)
240 EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
)
241 EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
)
246 EVT_IDLE(self
, self
.OnIdle
)
247 EVT_CLOSE(self
, self
.OnCloseWindow
)
248 EVT_ICONIZE(self
, self
.OnIconfiy
)
249 EVT_MAXIMIZE(self
, self
.OnMaximize
)
252 self
.CreateStatusBar(1, wxST_SIZEGRIP
)
254 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
255 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
257 def EmptyHandler(evt
): pass
258 EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
)
259 EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
)
261 # Prevent TreeCtrl from displaying all items after destruction when true
265 self
.mainmenu
= wxMenuBar()
268 menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!')
269 EVT_MENU(self
, exitID
, self
.OnFileExit
)
270 self
.mainmenu
.Append(menu
, '&File')
274 for item
in _treeList
:
276 for childItem
in item
[1]:
278 submenu
.Append(mID
, childItem
)
279 EVT_MENU(self
, mID
, self
.OnDemoMenu
)
280 menu
.AppendMenu(wxNewId(), item
[0], submenu
)
281 self
.mainmenu
.Append(menu
, '&Demo')
287 menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!')
288 EVT_MENU(self
, helpID
, self
.OnHelpAbout
)
289 self
.mainmenu
.Append(menu
, '&Help')
290 self
.SetMenuBar(self
.mainmenu
)
292 # set the menu accellerator table...
293 aTable
= wxAcceleratorTable([(wxACCEL_ALT
, ord('X'), exitID
),
294 (wxACCEL_CTRL
, ord('H'), helpID
)])
295 self
.SetAcceleratorTable(aTable
)
301 self
.tree
= wxTreeCtrl(splitter
, tID
,
302 style
=wxTR_HAS_BUTTONS |
304 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
306 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
307 root
= self
.tree
.AddRoot("wxPython Overview")
309 for item
in _treeList
:
310 child
= self
.tree
.AppendItem(root
, item
[0])
311 if not firstChild
: firstChild
= child
312 for childItem
in item
[1]:
313 theDemo
= self
.tree
.AppendItem(child
, childItem
)
314 self
.treeMap
[childItem
] = theDemo
316 self
.tree
.Expand(root
)
317 self
.tree
.Expand(firstChild
)
318 EVT_TREE_ITEM_EXPANDED (self
.tree
, tID
, self
.OnItemExpanded
)
319 EVT_TREE_ITEM_COLLAPSED (self
.tree
, tID
, self
.OnItemCollapsed
)
320 EVT_TREE_SEL_CHANGED (self
.tree
, tID
, self
.OnSelChanged
)
321 EVT_LEFT_DOWN (self
.tree
, self
.OnTreeLeftDown
)
324 self
.nb
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
)
326 # Set up a wxHtmlWindow on the Overview Notebook page
327 # we put it in a panel first because there seems to be a
328 # refresh bug of some sort (wxGTK) when it is directly in
331 self
.ovr
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400))
332 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
334 else: # hopefully I can remove this hacky code soon, see bug #216861
335 panel
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
)
336 self
.ovr
= wxHtmlWindow(panel
, -1, size
=(400, 400))
337 self
.nb
.AddPage(panel
, self
.overviewText
)
339 def OnOvrSize(evt
, ovr
=self
.ovr
):
340 ovr
.SetSize(evt
.GetSize())
342 EVT_SIZE(panel
, OnOvrSize
)
343 EVT_ERASE_BACKGROUND(panel
, EmptyHandler
)
346 self
.SetOverview(self
.overviewText
, overview
)
349 # Set up a TextCtrl on the Demo Code Notebook page
350 self
.txt
= wxTextCtrl(self
.nb
, -1,
351 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
352 self
.nb
.AddPage(self
.txt
, "Demo Code")
355 # Set up a log on the View Log Notebook page
356 self
.log
= wxTextCtrl(splitter2
, -1,
357 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
359 # Set the wxWindows log target to be this textctrl
360 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
362 # But instead of the above we want to show how to use our own wxLog class
363 wxLog_SetActiveTarget(MyLog(self
.log
))
365 # for serious debugging
366 #wxLog_SetActiveTarget(wxLogStderr())
367 #wxLog_SetTraceMask(wxTraceMessages)
372 # add the windows to the splitter and split it.
373 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
374 splitter
.SplitVertically(self
.tree
, splitter2
)
376 splitter
.SetSashPosition(180, true
)
377 splitter
.SetMinimumPaneSize(20)
378 splitter2
.SetSashPosition(450, true
)
379 splitter2
.SetMinimumPaneSize(20)
383 # select initial items
384 self
.nb
.SetSelection(0)
385 self
.tree
.SelectItem(root
)
387 if len(sys
.argv
) == 2:
389 selectedDemo
= self
.treeMap
[sys
.argv
[1]]
393 self
.tree
.SelectItem(selectedDemo
)
394 self
.tree
.EnsureVisible(selectedDemo
)
397 wxLogMessage('window handle: %s' % self
.GetHandle())
400 #---------------------------------------------
401 def WriteText(self
, text
):
402 if text
[-1:] == '\n':
407 def write(self
, txt
):
410 #---------------------------------------------
411 def OnItemExpanded(self
, event
):
412 item
= event
.GetItem()
413 wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
416 #---------------------------------------------
417 def OnItemCollapsed(self
, event
):
418 item
= event
.GetItem()
419 wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
422 #---------------------------------------------
423 def OnTreeLeftDown(self
, event
):
424 pt
= event
.GetPosition();
425 item
, flags
= self
.tree
.HitTest(pt
)
426 if item
== self
.tree
.GetSelection():
427 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
430 #---------------------------------------------
431 def OnSelChanged(self
, event
):
435 item
= event
.GetItem()
436 itemText
= self
.tree
.GetItemText(item
)
437 self
.RunDemo(itemText
)
440 #---------------------------------------------
441 def RunDemo(self
, itemText
):
443 if self
.nb
.GetPageCount() == 3:
444 if self
.nb
.GetSelection() == 2:
445 self
.nb
.SetSelection(0)
446 self
.nb
.DeletePage(2)
448 if itemText
== self
.overviewText
:
449 self
.GetDemoFile('Main.py')
450 self
.SetOverview(self
.overviewText
, overview
)
455 if os
.path
.exists(itemText
+ '.py'):
457 wxLogMessage("Running demo %s.py..." % itemText
)
459 self
.GetDemoFile(itemText
+ '.py')
460 module
= __import__(itemText
, globals())
461 self
.SetOverview(itemText
+ " Overview", module
.overview
)
466 # in case runTest is modal, make sure things look right...
470 self
.window
= module
.runTest(self
, self
.nb
, self
) ###
472 self
.nb
.AddPage(self
.window
, 'Demo')
473 self
.nb
.SetSelection(2)
474 self
.nb
.Refresh() # without this wxMac has troubles showing the just added page
483 #---------------------------------------------
485 def GetDemoFile(self
, filename
):
488 self
.txt
.SetValue(open(filename
).read())
490 self
.txt
.WriteText("Cannot open %s file." % filename
)
492 self
.txt
.SetInsertionPoint(0)
493 self
.txt
.ShowPosition(0)
495 #---------------------------------------------
496 def SetOverview(self
, name
, text
):
497 self
.curOverview
= text
499 if lead
!= '<html>' and lead
!= '<HTML>':
500 text
= string
.join(string
.split(text
, '\n'), '<br>')
501 self
.ovr
.SetPage(text
)
502 self
.nb
.SetPageText(0, name
)
504 #---------------------------------------------
506 def OnFileExit(self
, *event
):
510 def OnHelpAbout(self
, event
):
511 from About
import MyAboutBox
512 about
= MyAboutBox(self
)
517 #---------------------------------------------
518 def OnCloseWindow(self
, event
):
522 if hasattr(self
, "tbicon"):
527 #---------------------------------------------
528 def OnIdle(self
, event
):
530 self
.otherWin
.Raise()
531 self
.window
= self
.otherWin
539 #---------------------------------------------
542 showTipText
= open(opj("data/showTips")).read()
543 showTip
, index
= eval(showTipText
)
545 showTip
, index
= (1, 0)
547 tp
= wxCreateFileTipProvider(opj("data/tips.txt"), index
)
548 showTip
= wxShowTip(self
, tp
)
549 index
= tp
.GetCurrentTip()
550 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
553 #---------------------------------------------
554 def OnDemoMenu(self
, event
):
556 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
560 self
.tree
.SelectItem(selectedDemo
)
561 self
.tree
.EnsureVisible(selectedDemo
)
564 #---------------------------------------------
565 def OnTaskBarActivate(self
, evt
):
566 if self
.IsIconized():
568 if not self
.IsShown():
572 #---------------------------------------------
574 TBMENU_RESTORE
= 1000
577 def OnTaskBarMenu(self
, evt
):
579 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
580 menu
.Append(self
.TBMENU_CLOSE
, "Close")
581 self
.tbicon
.PopupMenu(menu
)
584 #---------------------------------------------
585 def OnTaskBarClose(self
, evt
):
588 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
589 # prod the main idle handler a bit to get the window to actually close
590 wxGetApp().ProcessIdle()
593 #---------------------------------------------
594 def OnIconfiy(self
, evt
):
595 wxLogMessage("OnIconfiy")
598 #---------------------------------------------
599 def OnMaximize(self
, evt
):
600 wxLogMessage("OnMaximize")
606 #---------------------------------------------------------------------------
607 #---------------------------------------------------------------------------
609 class MySplashScreen(wxSplashScreen
):
611 bmp
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
612 wxSplashScreen
.__init
__(self
, bmp
,
613 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
,
615 style
= wxSIMPLE_BORDER|wxFRAME_NO_TASKBAR|wxSTAY_ON_TOP
)
616 EVT_CLOSE(self
, self
.OnClose
)
618 def OnClose(self
, evt
):
619 frame
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
621 evt
.Skip() # Make sure the default handler runs too...
627 Create and show the splash screen. It will then create and show
628 the main frame when it is time to do so.
630 wxInitAllImageHandlers()
631 splash
= MySplashScreen()
637 #---------------------------------------------------------------------------
641 demoPath
= os
.path
.dirname(__file__
)
645 app
= MyApp(wxPlatform
== "__WXMAC__")
649 #---------------------------------------------------------------------------
653 overview
= """<html><body>
656 Python is an interpreted, interactive, object-oriented programming
657 language often compared to Tcl, Perl, Scheme, or Java.
659 <p> Python combines remarkable power with very clear syntax. It has
660 modules, classes, exceptions, very high level dynamic data types, and
661 dynamic typing. There are interfaces to many system calls and
662 libraries, and new built-in modules are easily written in C or
663 C++. Python is also usable as an extension language for applications
664 that need a programmable interface. <p>
668 wxWindows is a free C++ framework designed to make cross-platform
669 programming child's play. Well, almost. wxWindows 2 supports Windows
670 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
671 underway. Other ports are under consideration. <p>
673 wxWindows is a set of libraries that allows C++ applications to
674 compile and run on several different types of computers, with minimal
675 source code changes. There is one library per supported GUI (such as
676 Motif, or Windows). As well as providing a common API (Application
677 Programming Interface) for GUI functionality, it provides
678 functionality for accessing some commonly-used operating system
679 facilities, such as copying or deleting files. wxWindows is a
680 'framework' in the sense that it provides a lot of built-in
681 functionality, which the application can use or replace as required,
682 thus saving a great deal of coding effort. Basic data structures such
683 as strings, linked lists and hash tables are also supported.
688 wxPython is a Python extension module that encapsulates the wxWindows
689 GUI classes. Currently it is only available for the Win32 and GTK
690 ports of wxWindows, but as soon as the other ports are brought up to
691 the same level as Win32 and GTK, it should be fairly trivial to
692 enable wxPython to be used with the new GUI.
696 The wxPython extension module attempts to mirror the class heiarchy
697 of wxWindows as closely as possible. This means that there is a
698 wxFrame class in wxPython that looks, smells, tastes and acts almost
699 the same as the wxFrame class in the C++ version. Unfortunately,
700 because of differences in the languages, wxPython doesn't match
701 wxWindows exactly, but the differences should be easy to absorb
702 because they are natural to Python. For example, some methods that
703 return multiple values via argument pointers in C++ will return a
704 tuple of values in Python.
708 There is still much to be done for wxPython, many classes still need
709 to be mirrored. Also, wxWindows is still somewhat of a moving target
710 so it is a bit of an effort just keeping wxPython up to date. On the
711 other hand, there are enough of the core classes completed that
712 useful applications can be written.
716 wxPython is close enough to the C++ version that the majority of
717 the wxPython documentation is actually just notes attached to the C++
718 documents that describe the places where wxPython is different. There
719 is also a series of sample programs included, and a series of
720 documentation pages that assist the programmer in getting started
726 #----------------------------------------------------------------------------
727 #----------------------------------------------------------------------------
729 if __name__
== '__main__':
732 #----------------------------------------------------------------------------