Copy the wxPython demo from Classic

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@74164 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2013-06-11 18:24:09 +00:00
parent a83c11396f
commit f96e25db1f
670 changed files with 113835 additions and 0 deletions

1150
demo/AUI_DockingWindowMgr.py Normal file

File diff suppressed because it is too large Load Diff

111
demo/AUI_MDI.py Normal file
View File

@@ -0,0 +1,111 @@
import wx
import wx.aui
#----------------------------------------------------------------------
class ParentFrame(wx.aui.AuiMDIParentFrame):
def __init__(self, parent):
wx.aui.AuiMDIParentFrame.__init__(self, parent, -1,
title="AuiMDIParentFrame",
size=(640,480),
style=wx.DEFAULT_FRAME_STYLE)
self.count = 0
mb = self.MakeMenuBar()
self.SetMenuBar(mb)
self.CreateStatusBar()
self.Bind(wx.EVT_CLOSE, self.OnDoClose)
def MakeMenuBar(self):
mb = wx.MenuBar()
menu = wx.Menu()
item = menu.Append(-1, "New child window\tCtrl-N")
self.Bind(wx.EVT_MENU, self.OnNewChild, item)
item = menu.Append(-1, "Close parent")
self.Bind(wx.EVT_MENU, self.OnDoClose, item)
mb.Append(menu, "&File")
return mb
def OnNewChild(self, evt):
self.count += 1
child = ChildFrame(self, self.count)
child.Activate()
def OnDoClose(self, evt):
# Close all ChildFrames first else Python crashes
for m in self.GetChildren():
if isinstance(m, wx.aui.AuiMDIClientWindow):
for k in m.GetChildren():
if isinstance(k, ChildFrame):
k.Close()
evt.Skip()
#----------------------------------------------------------------------
class ChildFrame(wx.aui.AuiMDIChildFrame):
def __init__(self, parent, count):
wx.aui.AuiMDIChildFrame.__init__(self, parent, -1,
title="Child: %d" % count)
mb = parent.MakeMenuBar()
menu = wx.Menu()
item = menu.Append(-1, "This is child %d's menu" % count)
mb.Append(menu, "&Child")
self.SetMenuBar(mb)
p = wx.Panel(self)
wx.StaticText(p, -1, "This is child %d" % count, (10,10))
p.SetBackgroundColour('light blue')
sizer = wx.BoxSizer()
sizer.Add(p, 1, wx.EXPAND)
self.SetSizer(sizer)
wx.CallAfter(self.Layout)
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Show a AuiMDIParentFrame", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
pf = ParentFrame(self)
pf.Show()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.aui.AuiMDI</center></h2>
The wx.aui.AuiMDIParentFrame and wx.aui.AuiMDIChildFrame classes
implement the same API as wx.MDIParentFrame and wx.MDIChildFrame, but
implement the multiple document interface with a wx.aui.AuiNotebook.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

57
demo/AUI_Notebook.py Normal file
View File

@@ -0,0 +1,57 @@
import wx
import wx.aui
text = """\
Hello!
Welcome to this little demo of draggable tabs using the wx.aui module.
To try it out, drag a tab from the top of the window all the way to the bottom. After releasing the mouse, the tab will dock at the hinted position. Then try it again with the remaining tabs in various other positions. Finally, try dragging a tab to an existing tab ctrl. You'll soon see that very complex tab layouts may be achieved.
"""
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.nb = wx.aui.AuiNotebook(self)
page = wx.TextCtrl(self.nb, -1, text, style=wx.TE_MULTILINE)
self.nb.AddPage(page, "Welcome")
for num in range(1, 5):
page = wx.TextCtrl(self.nb, -1, "This is page %d" % num ,
style=wx.TE_MULTILINE)
self.nb.AddPage(page, "Tab Number %d" % num)
sizer = wx.BoxSizer()
sizer.Add(self.nb, 1, wx.EXPAND)
self.SetSizer(sizer)
wx.CallAfter(self.nb.SendSizeEvent)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>Say something nice here</center></h2>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

74
demo/About.py Normal file
View File

@@ -0,0 +1,74 @@
import sys
import wx # This module uses the new wx namespace
import wx.html
import wx.lib.wxpTag
#---------------------------------------------------------------------------
class MyAboutBox(wx.Dialog):
text = '''
<html>
<body bgcolor="#AC76DE">
<center><table bgcolor="#458154" width="100%%" cellspacing="0"
cellpadding="0" border="1">
<tr>
<td align="center">
<h1>wxPython %s</h1>
(%s)<br>
Running on Python %s<br>
</td>
</tr>
</table>
<p><b>wxPython</b> is a Python extension module that
encapsulates the wxWindows GUI classes.</p>
<p>This demo shows off some of the capabilities
of <b>wxPython</b>. Select items from the menu or tree control,
sit back and enjoy. Be sure to take a peek at the source code for each
demo item so you can learn how to use the classes yourself.</p>
<p><b>wxPython</b> is brought to you by <b>Robin Dunn</b> and<br>
<b>Total Control Software,</b> Copyright (c) 1997-2011.</p>
<p>
<font size="-1">Please see <i>license.txt</i> for licensing information.</font>
</p>
<p><wxp module="wx" class="Button">
<param name="label" value="Okay">
<param name="id" value="ID_OK">
</wxp></p>
</center>
</body>
</html>
'''
def __init__(self, parent):
wx.Dialog.__init__(self, parent, -1, 'About the wxPython demo',)
html = wx.html.HtmlWindow(self, -1, size=(420, -1))
if "gtk2" in wx.PlatformInfo:
html.SetStandardFonts()
py_version = sys.version.split()[0]
txt = self.text % (wx.VERSION_STRING,
", ".join(wx.PlatformInfo[1:]),
py_version
)
html.SetPage(txt)
btn = html.FindWindowById(wx.ID_OK)
ir = html.GetInternalRepresentation()
html.SetSize( (ir.GetWidth()+25, ir.GetHeight()+25) )
self.SetClientSize(html.GetSize())
self.CentreOnParent(wx.BOTH)
#---------------------------------------------------------------------------
if __name__ == '__main__':
app = wx.PySimpleApp()
dlg = MyAboutBox(None)
dlg.ShowModal()
dlg.Destroy()
app.MainLoop()

73
demo/AboutBox.py Normal file
View File

@@ -0,0 +1,73 @@
import wx
from wx.lib.wordwrap import wordwrap
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Show a wx.AboutBox", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
# First we create and fill the info object
info = wx.AboutDialogInfo()
info.Name = "Hello World"
info.Version = "1.2.3"
info.Copyright = "(C) 2006 Programmers and Coders Everywhere"
info.Description = wordwrap(
"A \"hello world\" program is a software program that prints out "
"\"Hello world!\" on a display device. It is used in many introductory "
"tutorials for teaching a programming language."
"\n\nSuch a program is typically one of the simplest programs possible "
"in a computer language. A \"hello world\" program can be a useful "
"sanity test to make sure that a language's compiler, development "
"environment, and run-time environment are correctly installed.",
350, wx.ClientDC(self))
info.WebSite = ("http://en.wikipedia.org/wiki/Hello_world", "Hello World home page")
info.Developers = [ "Joe Programmer",
"Jane Coder",
"Vippy the Mascot" ]
info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
# Then we call wx.AboutBox giving it that info object
wx.AboutBox(info)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.AboutBox</center></h2>
This function shows the native standard about dialog containing the
information specified in info. If the current platform has a native
about dialog which is capable of showing all the fields in info, the
native dialog is used, otherwise the function falls back to the
generic wxWidgets version of the dialog.
</body></html>
"""
licenseText = "blah " * 250 + "\n\n" +"yadda " * 100
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

View File

@@ -0,0 +1,130 @@
"""
<html><body>
This demo shows how to embed an ActiveX control in a wxPython application, (Win32 only.)
<p>
The MakeActiveXClass function dynamically builds a new Class on the fly, that has the
same signature and semantics as wxWindow. This means that when you call the function
you get back a new class that you can use just like wxWindow, (set the size and position,
use in a sizer, etc.) except its contents will be the COM control.
<p>
This demo embeds the Adobe Acrobat Reader, and gives you some buttons for opening a PDF
file, changing pages, etc. that show how to call methods on the COM object. If you don't
have Acrobat Reader 4.0 installed it won't work.
</body></html>
"""
import wx
if wx.Platform == '__WXMSW__':
from wx.lib.activexwrapper import MakeActiveXClass
import win32com.client.gencache
try:
#acrobat = win32com.client.gencache.EnsureModule('{CA8A9783-280D-11CF-A24D-444553540000}', 0x0, 1, 3)
acrobat = win32com.client.gencache.EnsureModule('{05BFD3F1-6319-4F30-B752-C7A22889BCC4}', 0x0, 1, 0)
except:
raise ImportError("Can't load PDF.OCX, install Acrobat 4.0")
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.pdf = None
sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
# this function creates a new class that can be used as
# a wxWindow, but contains the given ActiveX control.
ActiveXWrapper = MakeActiveXClass(acrobat.AcroPDF)
# create an instance of the new class
self.pdf = ActiveXWrapper( self, -1, style=wx.SUNKEN_BORDER)
sizer.Add(self.pdf, 1, wx.EXPAND)
btn = wx.Button(self, wx.NewId(), "Open PDF File")
wx.EVT_BUTTON(self, btn.GetId(), self.OnOpenButton)
btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5)
btn = wx.Button(self, wx.NewId(), "<-- Previous Page")
wx.EVT_BUTTON(self, btn.GetId(), self.OnPrevPageButton)
btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5)
btn = wx.Button(self, wx.NewId(), "Next Page -->")
wx.EVT_BUTTON(self, btn.GetId(), self.OnNextPageButton)
btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5)
btnSizer.Add((50, -1), 2, wx.EXPAND)
sizer.Add(btnSizer, 0, wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)
wx.EVT_WINDOW_DESTROY(self, self.OnDestroy)
def OnDestroy(self, evt):
if self.pdf:
self.pdf.Cleanup()
self.pdf = None
def OnOpenButton(self, event):
dlg = wx.FileDialog(self, wildcard="*.pdf")
if dlg.ShowModal() == wx.ID_OK:
wx.BeginBusyCursor()
self.pdf.LoadFile(dlg.GetPath())
wx.EndBusyCursor()
dlg.Destroy()
def OnPrevPageButton(self, event):
self.pdf.gotoPreviousPage()
def OnNextPageButton(self, event):
self.pdf.gotoNextPage()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
if wxPlatform == '__WXMSW__':
win = TestPanel(nb, log)
return win
else:
dlg = wx.MessageDialog(frame, 'This demo only works on MSW.',
'Sorry', wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
overview = __doc__
#----------------------------------------------------------------------
if __name__ == '__main__':
import sys
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "ActiveX test -- Acrobat", size=(640, 480),
style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
self.tp = TestPanel(self, sys.stdout)
app = wx.PySimpleApp()
frame = TestFrame()
frame.Show(True)
app.MainLoop()

186
demo/ActiveXWrapper_IE.py Normal file
View File

@@ -0,0 +1,186 @@
import wx
from wx.lib.activexwrapper import MakeActiveXClass
import win32com.client.gencache
browserModule = win32com.client.gencache.EnsureModule(
"{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
#----------------------------------------------------------------------
class TestPanel(wx.Window):
def __init__(self, parent, frame=None):
wx.Window.__init__(self, parent)
self.ie = None
self.current = "http://wxPython.org/"
self.frame = frame
if frame:
self.titleBase = frame.GetTitle()
sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
# Make a new class that derives from the WebBrowser class in the
# COM module imported above. This class also derives from wxWindow and
# implements the machinery needed to integrate the two worlds.
theClass = MakeActiveXClass(browserModule.WebBrowser, eventObj=self)
# Create an instance of that class
self.ie = theClass(self, -1)
btn = wx.Button(self, wx.NewId(), "Open", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "Home", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnHomeButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "<--", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "-->", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "Stop", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "Search", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSearchPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, wx.NewId(), "Refresh", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
txt = wx.StaticText(self, -1, "Location:")
btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2)
self.location = wx.ComboBox(self, wx.NewId(), "", style=wx.CB_DROPDOWN)
self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location)
self.location.Bind(wx.EVT_KEY_UP, self.OnLocationKey)
self.location.Bind(wx.EVT_CHAR, self.IgnoreReturn)
btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2)
sizer.Add(btnSizer, 0, wx.EXPAND)
sizer.Add(self.ie, 1, wx.EXPAND)
self.ie.Navigate2(self.current)
self.location.Append(self.current)
self.SetSizer(sizer)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
def OnDestroy(self, evt):
if self.ie:
self.ie.Cleanup()
self.ie = None
self.frame = None
def OnSize(self, evt):
self.Layout()
def OnLocationSelect(self, evt):
url = self.location.GetStringSelection()
self.ie.Navigate2(url)
def OnLocationKey(self, evt):
if evt.KeyCode() == wx.WXK_RETURN:
URL = self.location.GetValue()
self.location.Append(URL)
self.ie.Navigate2(URL)
else:
evt.Skip()
def IgnoreReturn(self, evt):
if evt.KeyCode() != wx.WXK_RETURN:
evt.Skip()
def OnOpenButton(self, event):
dlg = wx.TextEntryDialog(self, "Open Location",
"Enter a full URL or local path",
self.current, wx.OK|wx.CANCEL)
dlg.CentreOnParent()
if dlg.ShowModal() == wx.ID_OK:
self.current = dlg.GetValue()
self.ie.Navigate2(self.current)
dlg.Destroy()
def OnHomeButton(self, event):
self.ie.GoHome()
def OnPrevPageButton(self, event):
self.ie.GoBack()
def OnNextPageButton(self, event):
self.ie.GoForward()
def OnStopButton(self, evt):
self.ie.Stop()
def OnSearchPageButton(self, evt):
self.ie.GoSearch()
def OnRefreshPageButton(self, evt):
self.ie.Refresh2(3)
# The following event handlers are called by the web browser COM
# control since we passed self to MakeActiveXClass. It will look
# here for matching attributes and call them if they exist. See the
# module generated by makepy for details of method names, etc.
def OnNavigateComplete2(self, pDisp, URL):
self.current = URL
self.location.SetValue(URL)
def OnTitleChange(self, text):
if self.frame:
self.frame.SetTitle(self.titleBase + ' -- ' + text)
def OnStatusTextChange(self, text):
if self.frame:
self.frame.SetStatusText(text)
#----------------------------------------------------------------------
if __name__ == '__main__':
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "ActiveX test -- Internet Explorer",
size=(640, 480))
self.CreateStatusBar()
self.tp = TestPanel(self, frame=self)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseWindow(self, evt):
self.tp.Destroy()
self.Destroy()
app = wx.PySimpleApp()
frame = TestFrame()
frame.Show(True)
import wx.py
shell = wx.py.shell.ShellFrame(frame, size=(640,480),
locals=dict(wx=wx, frame=frame, ie=frame.tp.ie))
shell.Show()
frame.Raise()
app.MainLoop()

105
demo/ActiveX_FlashWindow.py Normal file
View File

@@ -0,0 +1,105 @@
import os
import wx
if wx.Platform == '__WXMSW__':
from wx.lib.flashwin import FlashWindow
from Main import opj
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, style=0)
self.pdf = None
sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
self.flash = FlashWindow(self, style=wx.SUNKEN_BORDER)
self.flash.LoadMovie(0, 'file://' + os.path.abspath('data/Asteroid_blaster.swf'))
sizer.Add(self.flash, proportion=1, flag=wx.EXPAND)
btn = wx.Button(self, wx.NewId(), "Open Flash File")
self.Bind(wx.EVT_BUTTON, self.OnOpenFileButton, btn)
btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
btn = wx.Button(self, wx.NewId(), "Open Flash URL")
self.Bind(wx.EVT_BUTTON, self.OnOpenURLButton, btn)
btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)
btnSizer.Add((50,-1), proportion=2, flag=wx.EXPAND)
sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)
def OnOpenFileButton(self, event):
dlg = wx.FileDialog(self, wildcard="*.swf")
if dlg.ShowModal() == wx.ID_OK:
wx.BeginBusyCursor()
self.flash.LoadMovie(0, 'file://' + dlg.GetPath())
wx.EndBusyCursor()
dlg.Destroy()
def OnOpenURLButton(self, event):
dlg = wx.TextEntryDialog(self, "Enter a URL of a .swf file", "Enter URL")
if dlg.ShowModal() == wx.ID_OK:
wx.BeginBusyCursor()
# setting the movie property works too
self.flash.movie = dlg.GetValue()
wx.EndBusyCursor()
dlg.Destroy()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
if wx.Platform == '__WXMSW__':
win = TestPanel(nb, log)
return win
else:
from wx.lib.msgpanel import MessagePanel
win = MessagePanel(nb, 'This demo only works on Microsoft Windows.',
'Sorry', wx.ICON_WARNING)
return win
overview = """\
<html><body>
<h2>wx.lib.flashwin.FlashWindow</h2>
The wx.lib.pdfwin.FlashWindow class is yet another example of using
ActiveX controls from wxPython using the new wx.activex module. This
allows you to use an ActiveX control as if it is a wx.Window, you can
call its methods, set/get properties, and receive events from the
ActiveX control in a very intuitive way.
<p> Using this class is simpler than ActiveXWrapper, doesn't rely on
the win32all extensions, and is more "wx\'ish", meaning that it uses
events and etc. as would be expected from any other wx window.
<p> This demo embeds the Shockwave Flash control, and lets you play a game.
</body></html>
"""
#----------------------------------------------------------------------
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

View File

@@ -0,0 +1,240 @@
# 11/18/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Updated for wx namespace
#
import wx
if wx.Platform == '__WXMSW__':
import wx.lib.iewin as iewin
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log, frame=None):
wx.Panel.__init__(
self, parent, -1,
style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN|wx.NO_FULL_REPAINT_ON_RESIZE
)
self.log = log
self.current = "http://wxPython.org/"
self.frame = frame
if frame:
self.titleBase = frame.GetTitle()
sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
self.ie = iewin.IEHtmlWindow(self)
btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "Home", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnHomeButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn)
btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn)
btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "Search", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSearchPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
txt = wx.StaticText(self, -1, "Location:")
btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2)
self.location = wx.ComboBox(
self, -1, "", style=wx.CB_DROPDOWN|wx.PROCESS_ENTER
)
self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location)
self.location.Bind(wx.EVT_KEY_UP, self.OnLocationKey)
self.location.Bind(wx.EVT_CHAR, self.IgnoreReturn)
btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2)
sizer.Add(btnSizer, 0, wx.EXPAND)
sizer.Add(self.ie, 1, wx.EXPAND)
self.ie.LoadUrl(self.current)
self.location.Append(self.current)
self.SetSizer(sizer)
# Since this is a wx.Window we have to call Layout ourselves
self.Bind(wx.EVT_SIZE, self.OnSize)
## Hook up the event handlers for the IE window. Using
## AddEventSink is how we tell the COM system to look in this
## object for method names matching the COM Event names. They
## are automatically looked for in the ActiveXCtrl class, (so
## deriving a new class from IEHtmlWindow would also have been
## a good appraoch) and now they will be looked for here too.
self.ie.AddEventSink(self)
def ShutdownDemo(self):
# put the frame title back
if self.frame:
self.frame.SetTitle(self.titleBase)
def OnSize(self, evt):
self.Layout()
def OnLocationSelect(self, evt):
url = self.location.GetStringSelection()
self.log.write('OnLocationSelect: %s\n' % url)
self.ie.Navigate(url)
def OnLocationKey(self, evt):
if evt.GetKeyCode() == wx.WXK_RETURN:
URL = self.location.GetValue()
self.location.Append(URL)
self.ie.Navigate(URL)
else:
evt.Skip()
def IgnoreReturn(self, evt):
if evt.GetKeyCode() != wx.WXK_RETURN:
evt.Skip()
def OnOpenButton(self, event):
dlg = wx.TextEntryDialog(self, "Open Location",
"Enter a full URL or local path",
self.current, wx.OK|wx.CANCEL)
dlg.CentreOnParent()
if dlg.ShowModal() == wx.ID_OK:
self.current = dlg.GetValue()
self.ie.Navigate(self.current)
dlg.Destroy()
def OnHomeButton(self, event):
self.ie.GoHome() ## ET Phone Home!
def OnPrevPageButton(self, event):
self.ie.GoBack()
def OnNextPageButton(self, event):
self.ie.GoForward()
def OnCheckCanGoBack(self, event):
event.Enable(self.ie.CanGoBack())
def OnCheckCanGoForward(self, event):
event.Enable(self.ie.CanGoForward())
def OnStopButton(self, evt):
self.ie.Stop()
def OnSearchPageButton(self, evt):
self.ie.GoSearch()
def OnRefreshPageButton(self, evt):
self.ie.Refresh(iewin.REFRESH_COMPLETELY)
# Here are some of the event methods for the IE COM events. See
# the MSDN docs for DWebBrowserEvents2 for details on what events
# are available, and what the parameters are.
def BeforeNavigate2(self, this, pDisp, URL, Flags, TargetFrameName,
PostData, Headers, Cancel):
self.log.write('BeforeNavigate2: %s\n' % URL[0])
if URL[0] == 'http://www.microsoft.com/':
if wx.MessageBox("Are you sure you want to visit Microsoft?",
style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO:
# This is how you can cancel loading a page. The
# Cancel parameter is defined as an [in,out] type and
# so setting the value means it will be returned and
# checked in the COM control.
Cancel[0] = True
def NewWindow3(self, this, pDisp, Cancel, Flags, urlContext, URL):
self.log.write('NewWindow3: %s\n' % URL)
Cancel[0] = True # Veto the creation of a new window.
#def ProgressChange(self, this, progress, progressMax):
# self.log.write('ProgressChange: %d of %d\n' % (progress, progressMax))
def DocumentComplete(self, this, pDisp, URL):
self.current = URL[0]
self.location.SetValue(self.current)
def TitleChange(self, this, Text):
if self.frame:
self.frame.SetTitle(self.titleBase + ' -- ' + Text)
def StatusTextChange(self, this, Text):
if self.frame:
self.frame.SetStatusText(Text)
#----------------------------------------------------------------------
# for the demo framework...
def runTest(frame, nb, log):
if wx.Platform == '__WXMSW__':
win = TestPanel(nb, log, frame)
return win
else:
from wx.lib.msgpanel import MessagePanel
win = MessagePanel(nb, 'This demo only works on Microsoft Windows.',
'Sorry', wx.ICON_WARNING)
return win
overview = """\
<html><body>
<h2>wx.lib.iewin.IEHtmlWindow</h2>
The wx.lib.iewin.IEHtmlWindow class is one example of using ActiveX
controls from wxPython using the new wx.activex module. This allows
you to use an ActiveX control as if it is a wx.Window, you can call
its methods, set/get properties, and receive events from the ActiveX
control in a very intuitive way.
<p> Using this class is simpler than ActiveXWrapper, doesn't rely on
the win32all extensions, and is more "wx\'ish", meaning that it uses
events and etc. as would be expected from any other wx window.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
#----------------------------------------------------------------------

202
demo/ActiveX_PDFWindow.py Normal file
View File

@@ -0,0 +1,202 @@
import sys
import wx
if wx.Platform == '__WXMSW__':
from wx.lib.pdfwin import PDFWindow
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
mainsizer = wx.BoxSizer(wx.HORIZONTAL)
leftsizer = wx.BoxSizer(wx.VERTICAL)
self.pdf = PDFWindow(self, style=wx.SUNKEN_BORDER)
leftsizer.Add(self.pdf, proportion=1, flag=wx.EXPAND)
box = wx.StaticBox(self, wx.NewId(), "" )
buttonsizer = wx.StaticBoxSizer(box, wx.HORIZONTAL )
b1 = wx.Button(self, wx.NewId(), "First")
buttonsizer.Add(b1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnFirstPageButton, b1)
b2 = wx.Button(self, wx.NewId(), "Previous")
buttonsizer.Add(b2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnPreviousPageButton, b2)
tx1 = wx.StaticText(self, wx.NewId(), " Go to page" )
buttonsizer.Add(tx1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
tc1 = wx.TextCtrl(self, wx.NewId(), "0", size=[30,-1])
buttonsizer.Add( tc1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_TEXT, self.OnGotoPage, tc1)
b3 = wx.Button(self, wx.NewId(), "Next")
buttonsizer.Add(b3, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, b3)
b4 = wx.Button(self, wx.NewId(), "Last")
buttonsizer.Add(b4, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnLastPageButton, b4)
tx2 = wx.StaticText(self, wx.NewId(), " Zoom")
buttonsizer.Add(tx2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
ch1 = wx.Choice(self, wx.NewId(),
choices=["Default", "Fit", "FitH", "FitV",
"25%", "50%", "75%", "100%", "125%", "200%", "400%"])
ch1.SetSelection(0)
buttonsizer.Add(ch1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
self.Bind(wx.EVT_CHOICE, self.OnZoom, ch1)
leftsizer.Add(buttonsizer, proportion=0)
mainsizer.Add(leftsizer, proportion=1, flag=wx.GROW|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5)
box = wx.StaticBox(self, wx.NewId(), "" )
rightsizer = wx.StaticBoxSizer(box, wx.VERTICAL)
b5 = wx.Button(self, wx.NewId(), "Load PDF")
rightsizer.Add(b5, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnLoadButton, b5)
b6 = wx.Button(self, wx.NewId(), "Print")
rightsizer.Add(b6, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_BUTTON, self.OnPrintButton, b6)
tx3 = wx.StaticText(self, wx.NewId(), "Page mode:")
rightsizer.Add(tx3, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
ch2 = wx.Choice(self, wx.NewId(),size=[100,-1],
choices=["None", "Bookmarks", "Thumbs"])
ch2.SetSelection(0)
rightsizer.Add(ch2, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_CHOICE, self.OnPageMode, ch2)
tx4 = wx.StaticText(self, wx.NewId(), "Layout mode:")
rightsizer.Add(tx4, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
ch3 = wx.Choice(self, wx.NewId(),size=[100,-1],
choices=["DontCare", "SinglePage",
"OneColumn", "TwoColumnLeft", "TwoColumnRight" ])
ch3.SetSelection(0)
rightsizer.Add(ch3, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_CHOICE, self.OnLayoutMode, ch3)
cx1 = wx.CheckBox(self, wx.NewId(), "Toolbar")
cx1.SetValue( True )
rightsizer.Add( cx1,proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_CHECKBOX, self.OnToolbar, cx1)
cx2 = wx.CheckBox(self, wx.NewId(), "Scrollbars")
cx2.SetValue( True )
rightsizer.Add( cx2,proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
self.Bind(wx.EVT_CHECKBOX, self.OnScrollbars, cx2)
mainsizer.Add( rightsizer, proportion=0, flag=wx.ALL, border=15)
self.SetSizer(mainsizer)
self.SetAutoLayout(True)
def OnFirstPageButton(self, event):
self.pdf.gotoFirstPage()
def OnPreviousPageButton(self, event):
self.pdf.gotoPreviousPage()
def OnNextPageButton(self, event):
self.pdf.gotoNextPage()
def OnLastPageButton(self, event):
self.pdf.gotoLastPage()
def OnGotoPage(self, event):
npage = event.GetEventObject().GetValue()
try:
self.pdf.setCurrentPage(int(npage))
except ValueError:
pass
def OnZoom(self, event):
astring = event.GetEventObject().GetStringSelection()
if astring.startswith('Fit'):
self.pdf.setView(astring)
else:
try:
percent = float(astring.replace('%',''))
self.pdf.setZoom(percent)
except ValueError:
pass
def OnLoadButton(self, event):
dlg = wx.FileDialog(self, wildcard="*.pdf")
if dlg.ShowModal() == wx.ID_OK:
wx.BeginBusyCursor()
self.pdf.LoadFile(dlg.GetPath())
wx.EndBusyCursor()
dlg.Destroy()
def OnPrintButton(self, event):
self.pdf.Print()
def OnPageMode(self, event):
astring = event.GetEventObject().GetStringSelection()
self.pdf.setPageMode(astring.lower())
def OnLayoutMode(self, event):
astring = event.GetEventObject().GetStringSelection()
self.pdf.setLayoutMode(astring)
def OnToolbar(self, event):
on = event.GetEventObject().GetValue()
self.pdf.setShowToolbar(on)
def OnScrollbars(self, event):
on = event.GetEventObject().GetValue()
self.pdf.setShowScrollbars(on)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
if wx.Platform == '__WXMSW__':
win = TestPanel(nb, log)
return win
else:
from wx.lib.msgpanel import MessagePanel
win = MessagePanel(nb, 'This demo only works on Microsoft Windows.',
'Sorry', wx.ICON_WARNING)
return win
overview = """\
<html><body>
<h2>wx.lib.pdfwin.PDFWindow</h2>
The wx.lib.pdfwin.PDFWindow class is another example of using ActiveX
controls from wxPython using the new wx.activex module. This allows
you to use an ActiveX control as if it is a wx.Window, you can call
its methods, set/get properties, and receive events from the ActiveX
control in a very intuitive way.
<p> Using this class is simpler than ActiveXWrapper, doesn't rely on
the win32all extensions, and is more "wx\'ish", meaning that it uses
events and etc. as would be expected from any other wx window.
<p> This demo embeds the Adobe Acrobat Reader, and gives you some
buttons for opening a PDF file, changing pages, etc. that show how to
call methods on the COM object. If you don't have Acrobat Reader 4.0
(or greater) installed it won't work.
</body></html>
"""
#----------------------------------------------------------------------
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

178
demo/AdjustChannels.py Normal file
View File

@@ -0,0 +1,178 @@
import wx
from Main import opj
#----------------------------------------------------------------------
# AdjustChannels demo. The interesting part is ImageWindow.OnPaint
class TestAdjustChannels(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
topsizer= wx.BoxSizer(wx.HORIZONTAL) # left controls, right image output
# slider controls controls
ctrlsizer= wx.BoxSizer(wx.VERTICAL)
label= wx.StaticText(self, -1, "Factor red in %")
label.SetForegroundColour("RED")
ctrlsizer.Add(label, 0, wx.ALL, 5)
sliderred= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
sliderred.SetForegroundColour("RED")
sliderred.SetTickFreq(50, 5)
ctrlsizer.Add(sliderred)
ctrlsizer.AddSpacer(15)
label= wx.StaticText(self, -1, "Factor green in %")
label.SetForegroundColour("GREEN")
ctrlsizer.Add(label, 0, wx.ALL, 5)
slidergreen= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
slidergreen.SetForegroundColour("GREEN")
slidergreen.SetTickFreq(50, 5)
ctrlsizer.Add(slidergreen)
ctrlsizer.AddSpacer(15)
label= wx.StaticText(self, -1, "Factor blue in %")
label.SetForegroundColour("BLUE")
ctrlsizer.Add(label, 0, wx.ALL, 5)
sliderblue= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
sliderblue.SetForegroundColour("BLUE")
sliderblue.SetTickFreq(50, 5)
ctrlsizer.Add(sliderblue)
ctrlsizer.AddSpacer(20)
label= wx.StaticText(self, -1, "Factor alpha in %")
ctrlsizer.Add(label, 0, wx.ALL, 5)
slideralpha= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
slideralpha.SetTickFreq(50, 1)
ctrlsizer.Add(slideralpha)
topsizer.Add(ctrlsizer, 0, wx.ALL, 10)
# image window
self.images= ImageWindow(self)
topsizer.Add(self.images, 1, wx.EXPAND)
self.SetSizer(topsizer)
topsizer.Layout()
# forward the slider change events to the image window
sliderred.Bind(wx.EVT_SCROLL, self.images.OnScrollRed)
slidergreen.Bind(wx.EVT_SCROLL, self.images.OnScrollGreen)
sliderblue.Bind(wx.EVT_SCROLL, self.images.OnScrollBlue)
slideralpha.Bind(wx.EVT_SCROLL, self.images.OnScrollAlpha)
class ImageWindow(wx.Window):
def __init__(self, parent):
wx.Window.__init__(self, parent)
self.image1= wx.Image(opj('bitmaps/image.bmp'), wx.BITMAP_TYPE_BMP)
self.image2= wx.Image(opj('bitmaps/toucan.png'), wx.BITMAP_TYPE_PNG)
# the factors -- 1.0 does not not modify the image
self.factorred= 1.0
self.factorgreen= 1.0
self.factorblue= 1.0
self.factoralpha= 1.0
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnScrollRed(self, event):
# position is a int value -- calculate the factor
self.factorred = event.GetPosition() / 100.0
self.Refresh()
def OnScrollGreen(self, event):
# position is a int value -- calculate the factor
self.factorgreen = event.GetPosition() / 100.0
self.Refresh()
def OnScrollBlue(self, event):
# position is a int value -- calculate the factor
self.factorblue = event.GetPosition() / 100.0
self.Refresh()
def OnScrollAlpha(self, event):
# position is a int value -- calculate the factor
self.factoralpha = event.GetPosition() / 100.0
self.Refresh()
def OnPaint(self, event):
dc= wx.PaintDC(self)
dc= wx.BufferedDC(dc)
# paint a background to show the alpha manipulation
dc.SetBackground(wx.Brush("WHITE"))
dc.Clear()
dc.SetBrush(wx.Brush("GREY", wx.CROSSDIAG_HATCH))
windowsize= self.GetSizeTuple()
dc.DrawRectangle(0, 0, windowsize[0], windowsize[1])
# apply correction to the image channels via wx.Image.AdjustChannels
image= self.image1.AdjustChannels(self.factorred, self.factorgreen, self.factorblue, self.factoralpha)
bitmap= wx.BitmapFromImage(image)
dc.DrawBitmap(bitmap, 10, 10, True)
image= self.image2.AdjustChannels(self.factorred, self.factorgreen, self.factorblue, self.factoralpha)
bitmap= wx.BitmapFromImage(image)
dc.DrawBitmap(bitmap, 10, 110, True)
def OnSize(self, event):
self.Refresh()
def OnEraseBackground(self, event):
pass
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestAdjustChannels(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>Adjust Channels</h2>
<p>
The <code>wx.Image</code> member function '<code>AdjustChannels</code>' is a fast way to manipulate the four
channels (red, green, blue, alpha) of a <code>wx.Image</code>. It can be used for <b>colour</b> or
<b>gamma correction</b> of a image. It is also possible to <b>add</b> or <b>enhance</b> the <b>transparency</b>
of a image via this function (eg. for fade-in/fade-out effects).
</p>
<p>
The function expects four float values (one for each channel) and multiplies every
byte in the channel with the given factor (written in C++). That means a 1.0 will not alter the channel
and eg. 1.2 will 'enhance' the channel by 20%.
</p>
<pre>
Examples:
# make a image 10% brighter - first three parameters are the factors for red, green and blue
image= image.AdjustChannels(1.1, 1.1, 1.1, 1.0)
# add 20% transparency to a image - the last parameter is the factor for the alpha channel
image= image.AdjustChannels(1.0, 1.0, 1.0, 0.8)
</pre>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

76
demo/AlphaDrawing.py Normal file
View File

@@ -0,0 +1,76 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
txt = """\
If this build of wxPython includes the new wx.GCDC class (which
provides the wx.DC API on top of the new wx.GraphicsContext class)
then these squares should be transparent.
"""
wx.StaticText(self, -1, txt, (20, 20))
def OnPaint(self, evt):
pdc = wx.PaintDC(self)
try:
dc = wx.GCDC(pdc)
except:
dc = pdc
rect = wx.Rect(0,0, 100, 100)
for RGB, pos in [((178, 34, 34), ( 50, 90)),
(( 35, 142, 35), (110, 150)),
(( 0, 0, 139), (170, 90))
]:
r, g, b = RGB
penclr = wx.Colour(r, g, b, wx.ALPHA_OPAQUE)
brushclr = wx.Colour(r, g, b, 128) # half transparent
dc.SetPen(wx.Pen(penclr))
dc.SetBrush(wx.Brush(brushclr))
rect.SetPosition(pos)
dc.DrawRoundedRectangleRect(rect, 8)
# some additional testing stuff
#dc.SetPen(wx.Pen(wx.Colour(0,0,255, 196)))
#dc.SetBrush(wx.Brush(wx.Colour(0,0,255, 64)))
#dc.DrawCircle(50, 275, 25)
#dc.DrawEllipse(100, 275, 75, 50)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>Alpha Drawing</center></h2>
The wx.GCDC class is a class that implemented the wx.DC API using the
new wx.GraphicsContext class, and so it supports anti-aliased drawing
using pens and brushes, that can optionally also be drawn using an
alpha transparency. (On the Mac all the DC classes are using this new
implementation.) This is accomplished by enabling the wx.Colour class
to have a fourth component for the alpha value, where 0 is fully
transparent, and 255 is fully opaque.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

142
demo/AnalogClock.py Normal file
View File

@@ -0,0 +1,142 @@
# AnalogClock demo
# E. A. Tacao <e.a.tacao |at| estadao.com.br>
# http://j.domaindlx.com/elements28/wxpython/
# 12 Fev 2006, 22:00 GMT-03:00
# Distributed under the wxWidgets license.
import wx
import wx.lib.analogclock as ac
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent)
# A mostly default clock
c1 = ac.AnalogClock(self, size=(200,200))
if True: # for a simpler test case just set this to False and
# only the one clock will be created
# A plain clock, with square hour and round minute marks, no
# shadow, static border
c2 = ac.AnalogClock(self, style=wx.STATIC_BORDER,
hoursStyle=ac.TICKS_SQUARE,
minutesStyle=ac.TICKS_CIRCLE,
clockStyle=ac.SHOW_HOURS_TICKS| \
ac.SHOW_MINUTES_TICKS|
ac.SHOW_HOURS_HAND| \
ac.SHOW_MINUTES_HAND| \
ac.SHOW_SECONDS_HAND)
c2.SetTickSize(12, target=ac.HOUR)
# No minute tick marks
c3 = ac.AnalogClock(self, hoursStyle=ac.TICKS_CIRCLE,
clockStyle=ac.SHOW_HOURS_TICKS| \
ac.SHOW_HOURS_HAND| \
ac.SHOW_MINUTES_HAND| \
ac.SHOW_SECONDS_HAND| \
ac.SHOW_SHADOWS)
c3.SetTickSize(12)
# A clock with hex numbers no seconds hand and different colours.
c4 = ac.AnalogClock(self, hoursStyle=ac.TICKS_HEX,
clockStyle=ac.SHOW_HOURS_TICKS| \
ac.SHOW_HOURS_HAND| \
ac.SHOW_MINUTES_HAND| \
ac.SHOW_SHADOWS)
colour = wx.Colour(0, 255, 255)
c4.SetForegroundColour(colour)
colour = wx.Colour(0, 132, 132)
c4.SetShadowColour(colour)
c4.SetTickFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.BOLD))
c4.SetBackgroundColour(wx.BLACK)
c4.SetFaceBorderColour(wx.BLACK)
c4.SetFaceFillColour(wx.BLACK)
# A clock with binary numbers shown only at the quarter tick marks,
# no minutes ticks and different colours.
c5 = ac.AnalogClock(self, style = wx.RAISED_BORDER,
hoursStyle=ac.TICKS_BINARY,
clockStyle=ac.SHOW_QUARTERS_TICKS| \
ac.SHOW_HOURS_HAND| \
ac.SHOW_MINUTES_HAND| \
ac.SHOW_SECONDS_HAND| \
ac.SHOW_SHADOWS)
colour = wx.Colour(0, 128, 0)
c5.SetHandFillColour(colour, target=ac.SECOND)
c5.SetHandBorderColour(colour, target=ac.SECOND)
c5.SetBackgroundColour(colour)
colour = wx.Colour(128, 0, 64)
c5.SetTickFillColour(colour)
c5.SetFaceBorderColour(colour)
c5.SetFaceBorderWidth(1)
colour = wx.Colour(0, 198, 0)
c5.SetFaceFillColour(colour)
c5.SetShadowColour(wx.WHITE)
# A clock with a sunken border, roman numerals shown only at the
# quarter tick marks with a roman font, circular minutes ticks,
# no seconds hand, no shadows, tick overlapping and different colours.
c6 = ac.AnalogClock(self, style = wx.SUNKEN_BORDER,
hoursStyle=ac.TICKS_ROMAN,
minutesStyle=ac.TICKS_CIRCLE,
clockStyle=ac.SHOW_QUARTERS_TICKS| \
ac.SHOW_MINUTES_TICKS| \
ac.SHOW_HOURS_HAND| \
ac.SHOW_MINUTES_HAND| \
ac.OVERLAP_TICKS)
colour = wx.Colour(128, 0, 0)
c6.SetHandFillColour(colour)
colour = wx.Colour(179, 0, 89)
c6.SetHandBorderColour(colour)
c6.SetTickFillColour(colour)
c6.SetTickBorderColour(colour)
colour = wx.Colour(225, 255, 255)
c6.SetFaceBorderColour(colour)
c6.SetBackgroundColour(colour)
colour = wx.Colour(249, 255, 255)
c6.SetFaceFillColour(colour)
colour = wx.Colour(255, 213, 213)
c6.SetShadowColour(colour)
c6.SetTickFont(wx.Font(10, wx.FONTFAMILY_ROMAN, wx.NORMAL, wx.BOLD))
# layout the clocks in a grid
gs = wx.GridSizer(2, 3, 4, 4)
gs.Add(c1, 0, wx.EXPAND)
gs.Add(c2, 0, wx.EXPAND)
gs.Add(c3, 0, wx.EXPAND)
gs.Add(c4, 0, wx.EXPAND)
gs.Add(c5, 0, wx.EXPAND)
gs.Add(c6, 0, wx.EXPAND)
# put it in another sizer for a border
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(gs, 1, wx.EXPAND|wx.ALL, 10)
self.SetSizerAndFit(sizer)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html>
<PRE><FONT SIZE=-1>
""" + ac.__doc__.replace("<", "").replace(">", "") + """
</FONT></PRE>"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

60
demo/AnimateCtrl.py Normal file
View File

@@ -0,0 +1,60 @@
import wx
import wx.animate
from Main import opj
GIFNames = [
'bitmaps/AG00178_.gif',
'bitmaps/BD13656_.gif',
'bitmaps/AG00185_.gif',
'bitmaps/AG00039_.gif',
'bitmaps/AG00183_.gif',
'bitmaps/AG00028_.gif',
]
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
for name in GIFNames:
ani = wx.animate.Animation(opj(name))
ctrl = wx.animate.AnimationCtrl(self, -1, ani)
ctrl.SetUseWindowBackgroundColour()
ctrl.Play()
sizer.AddF(ctrl, wx.SizerFlags().Border(wx.ALL, 10))
border = wx.BoxSizer()
border.AddF(sizer, wx.SizerFlags(1).Expand().Border(wx.ALL, 20))
self.SetSizer(border)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.animate.AnimationCtrl</center></h2>
wx.animate.AnimationCtrl is like a wx.StaticBitmap but is able to
display an animation by extracing frames from a multi-image GIF file.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

884
demo/ArtProvider.py Normal file
View File

@@ -0,0 +1,884 @@
import cStringIO
import wx
#----------------------------------------------------------------------
ArtClients = [ "wx.ART_TOOLBAR",
"wx.ART_MENU",
"wx.ART_FRAME_ICON",
"wx.ART_CMN_DIALOG",
"wx.ART_HELP_BROWSER",
"wx.ART_MESSAGE_BOX",
"wx.ART_OTHER",
]
ArtIDs = [ "wx.ART_ADD_BOOKMARK",
"wx.ART_DEL_BOOKMARK",
"wx.ART_HELP_SIDE_PANEL",
"wx.ART_HELP_SETTINGS",
"wx.ART_HELP_BOOK",
"wx.ART_HELP_FOLDER",
"wx.ART_HELP_PAGE",
"wx.ART_GO_BACK",
"wx.ART_GO_FORWARD",
"wx.ART_GO_UP",
"wx.ART_GO_DOWN",
"wx.ART_GO_TO_PARENT",
"wx.ART_GO_HOME",
"wx.ART_FILE_OPEN",
"wx.ART_FILE_SAVE",
"wx.ART_FILE_SAVE_AS",
"wx.ART_PRINT",
"wx.ART_HELP",
"wx.ART_TIP",
"wx.ART_REPORT_VIEW",
"wx.ART_LIST_VIEW",
"wx.ART_NEW_DIR",
"wx.ART_HARDDISK",
"wx.ART_FLOPPY",
"wx.ART_CDROM",
"wx.ART_REMOVABLE",
"wx.ART_FOLDER",
"wx.ART_FOLDER_OPEN",
"wx.ART_GO_DIR_UP",
"wx.ART_EXECUTABLE_FILE",
"wx.ART_NORMAL_FILE",
"wx.ART_TICK_MARK",
"wx.ART_CROSS_MARK",
"wx.ART_ERROR",
"wx.ART_QUESTION",
"wx.ART_WARNING",
"wx.ART_INFORMATION",
"wx.ART_MISSING_IMAGE",
"wx.ART_COPY",
"wx.ART_CUT",
"wx.ART_PASTE",
"wx.ART_DELETE",
"wx.ART_NEW",
"wx.ART_UNDO",
"wx.ART_REDO",
"wx.ART_CLOSE",
"wx.ART_QUIT",
"wx.ART_FIND",
"wx.ART_FIND_AND_REPLACE",
]
#----------------------------------------------------------------------
class MyArtProvider(wx.ArtProvider):
def __init__(self, log):
wx.ArtProvider.__init__(self)
self.log = log
def CreateBitmap(self, artid, client, size):
# You can do anything here you want, such as using the same
# image for any size, any client, etc., or using specific
# images for specific sizes, whatever...
# See end of file for the image data
bmp = wx.NullBitmap
# use this one for all 48x48 images
if size.width == 48:
bmp = makeBitmap(smile48_png)
# but be more specific for these
elif size.width == 16 and artid == wx.ART_ADD_BOOKMARK:
bmp = makeBitmap(smile16_png)
elif size.width == 32 and artid == wx.ART_ADD_BOOKMARK:
bmp = makeBitmap(smile32_png)
# and just ignore the size for these
elif artid == wx.ART_GO_BACK:
bmp = makeBitmap(left_png)
elif artid == wx.ART_GO_FORWARD:
bmp = makeBitmap(right_png)
elif artid == wx.ART_GO_UP:
bmp = makeBitmap(up_png)
elif artid == wx.ART_GO_DOWN:
bmp = makeBitmap(down_png)
elif artid == wx.ART_GO_TO_PARENT:
bmp = makeBitmap(back_png)
elif artid == wx.ART_CROSS_MARK:
bmp = makeBitmap(cross_png)
elif artid == wx.ART_TICK_MARK:
bmp = makeBitmap(tick_png)
if bmp.Ok():
self.log.write("MyArtProvider: providing %s:%s at %s\n" %(artid, client, size))
return bmp
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
sizer = wx.BoxSizer(wx.VERTICAL)
title = wx.StaticText(self, -1, "ArtProvider")
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
fgs = wx.FlexGridSizer(cols=3, hgap=10, vgap=10)
combo = wx.ComboBox(self, -1, "", choices = ArtClients,
style = wx.CB_DROPDOWN|wx.CB_READONLY)
fgs.Add(combo, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
self.Bind(wx.EVT_COMBOBOX, self.OnSelectClient, combo)
combo.Select(0)
combo = wx.ComboBox(self, -1, "", choices = ArtIDs,
style = wx.CB_DROPDOWN|wx.CB_READONLY)
fgs.Add(combo, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
self.Bind(wx.EVT_COMBOBOX, self.OnSelectID, combo)
combo.Select(0)
cb = wx.CheckBox(self, -1, "Use custom provider")
fgs.Add(cb, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
self.Bind(wx.EVT_CHECKBOX, self.OnUseCustom, cb)
fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
box = wx.BoxSizer(wx.VERTICAL)
bmp = wx.EmptyBitmap(16,16)
self.bmp16 = wx.StaticBitmap(self, -1, bmp)
box.Add(self.bmp16, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
text = wx.StaticText(self, -1, "16x16")
box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
box = wx.BoxSizer(wx.VERTICAL)
bmp = wx.EmptyBitmap(32,32)
self.bmp32 = wx.StaticBitmap(self, -1, bmp)
box.Add(self.bmp32, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
text = wx.StaticText(self, -1, "32x32")
box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
box = wx.BoxSizer(wx.VERTICAL)
bmp = wx.EmptyBitmap(48,48)
self.bmp48 = wx.StaticBitmap(self, -1, bmp)
box.Add(self.bmp48, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
text = wx.StaticText(self, -1, "48x48")
box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.Add(fgs, 0, wx.ALL, 5)
self.SetSizer(sizer)
self.client = eval(ArtClients[0])
self.artid = eval(ArtIDs[0])
self.getArt()
def OnSelectClient(self, evt):
self.log.write("OnSelectClient\n")
self.client = eval(evt.GetString())
self.getArt()
def OnSelectID(self, evt):
self.log.write("OnSelectID\n")
self.artid = eval(evt.GetString())
self.getArt()
def OnUseCustom(self, evt):
if evt.IsChecked():
self.log.write("Images will now be provided by MyArtProvider\n")
wx.ArtProvider.Push( MyArtProvider(self.log) )
else:
self.log.write("MyArtProvider deactivated\n")
wx.ArtProvider.Pop()
self.getArt()
def getArt(self):
self.log.write("Getting art for %s:%s\n" % (self.client, self.artid))
bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (16,16))
if not bmp.Ok():
bmp = wx.EmptyBitmap(16,16)
self.clearBmp(bmp)
self.bmp16.SetBitmap(bmp)
bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (32,32))
if not bmp.Ok():
bmp = wx.EmptyBitmap(32,32)
self.clearBmp(bmp)
self.bmp32.SetBitmap(bmp)
bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (48,48))
if not bmp.Ok():
bmp = wx.EmptyBitmap(48,48)
self.clearBmp(bmp)
self.bmp48.SetBitmap(bmp)
def clearBmp(self, bmp):
dc = wx.MemoryDC()
dc.SelectObject(bmp)
dc.SetBackground(wx.Brush("white"))
dc.Clear()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.ArtProvider</center></h2>
wx.ArtProvider class can be used to customize the look of wxWindows
applications. When wxWindows internal classes need to display an icon
or a bitmap (e.g. in the standard file dialog), it does not use a
hard-coded resource but asks wx.ArtProvider for it instead. This way
the users can plug in their own wx.ArtProvider class and easily replace
standard art with his/her own version. It is easy thing to do: all
that is needed is to derive a class from wx.ArtProvider, override it's
CreateBitmap method and register the provider with
wx.ArtProvider.PushProvider.
<p>
This class can also be used to get the platform native icons as
provided by wx.ArtProvider.GetBitmap or wx.ArtProvider.GetIcon methods.
</body></html>
"""
#----------------------------------------------------------------------
# Image data
def makeBitmap(data):
stream = cStringIO.StringIO(data)
return wx.BitmapFromImage(wx.ImageFromStream(stream))
back_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x07YID\
ATx\x9c\xa5\x97Ml\x9dG\x15\x86\x9fsf\xbe\xef^\xfb:\xaeS\xd7\xa9\x1d;!IK)\xfd\
A\x05\x95BQ\xc5\xdf\x02\xb1(\x12\x0b\x10\x8b\x8a\x05]Vl\xd8\xb2`\xcb\x92\xee\
Q\x85\xd8U\xaa\xba\x03\tD+@j\x91J\x11\x8aT\xd14\xfd\xa7\xf9q\x9a\xc6\x8e\xe3\
\xd8\xb1\xefwg\xcea1s\xaf\x13;\xaa*1\xd2h4su\xe7=\xe7\xcc{\xdes>\x99\x9b\x9b\
\x03\xe0\xf9\x17\xff\xe2[\xb6B;u\'\x86`\x19\x9299Ar\xc8\x19\xb29\xd9 \xe5\
\xb2O\x069\x97\xb3\x03{\x1b\xff\xa7\x9c\xa5zf\xe6,\x1e\xda\xe0\xe1\xe5U\xe6g\
\xb6\x91\xb9\xb99~\xf7\xc2i\x1f\xcc-3\xdd\x8f\xe5r\x83Q\x86\x94\xa0K\x05p\
\xbc\x1f\xe5\xba\xff?\xcf{\xb1\xe3;_x\x17\xf9\xd3\xcb\xaf\xbb\xce>\xc2\xcctd\
\x94*x\xca\\\xdb\xd8\xe2Fg\x98\x0b\x96\x95l\xc2\xc8 \xbb\xe0Y\xc8&\xd5+!eadB\
JBv\xa9`R\xef\x12FYH\x19\xcc\x84.\xcb\xc4\xb0\xa5\xd9k\xc4-[f\xb1_\xc0\xdda\
\xed\xca*k\xabg\xd9\xda\xfc\x84\xeb;\x01\x97\x1eh\x03\x12A"N\x03D\\"\xe6\x81\
LK\xf6H\xb6H\xf6@\xb6@\xf2H\xb2\xc0(+\xd9#\xbb]$y\x00\x14\xd5\x00\x08\x00\
\x17\xaf\xcd\x12\t\x83b\x9d\xc3\xd6\xf5\xab|\xf4\xf6+|ti\xc8\xb9+\rW\xae\xb7\
\x88*\x1a\x14\x15E\x82"Z\xa7(\xaa\rh\x00\tH]\x11\x05Q\\\x14<\xe0\x12HV"\xe8\
\x08\xfd6\xd3k\x03\xee\xc2(\t\xd1\xc6\x841\xf8\xf8\xc2;\\^\x1f\xf2\xda\xd9\
\x86\xc1\xf4!V\x16gh{-\xe6J\x08\x11\t\rA\x03\x1a"\xaa\r\x12\x02\xaa\x81 \x11\
\x82\xa2\xd5\x10\x11-\x06\x11\xe8\xb7\xca(\x0b\xef\xad\n\xeb\x9b\x86Y\xa6UgD\
\x03@4wF\x19,\x8f\xb8\xb1u\x85w/6\xf4z\x03N\x1e\x9bc\xa7\x13.\xad\x8d\xd8\
\xed\x04QG\xd5\x11\x8d\x88\n\xa8 \x02\xaa\x02\x9a\x01\x07\x11\x10\xc1\xa5\
\x84\xd8\x81\xa9>\x9cZR\xbev\xbf\xf3\xea\x1b\xc6ng\xb4\xd1\xd8\xee"\xee\x82\
\x9a\x15V\xa6,\x98\x05\xae\xef\xf69<7 [\xe0\xfc\xe5!\xdb\xbb`D\x9c\x80\x110\
\x1a2\x01\xf32\x93+)+\xc9\xea\xbb[ \xe5\xc8(\x17\x0e\\\xdbV\xfe\xf3a\xa6\x1b\
\x19\xcb\x0bNTc\xaa5\xc6#\x9a\x97Ts\x03B\x8b\xc6\xcc\xf4T\x8f\xcd\x1b\x86y@\
\xb4A5V\xcf[\xd0\x88H\x99\xd40#\x91\xe1\xf6\xc7|\xf0\xfa\xb3\xe44\xac$\x13\
\x16\x1f|\x9a\xc3+\x8fc9s\xe1\n\xdc5\x0b\x17.\x1bM(\x112\x87\x98\xcdk\x8a\
\x00\x94\xb7\r!\xe2#\x10\x95\xcf\x04\x8e\x04\xba\xe1&\xabg\x9e\'w[\x13\xef\
\xe6V\x9e@W\x1eC\xc4p\x87\x18 \x06\xa3\x89\x8a{\xc9\xbahUt0\n\x80\xc6B\xb2\
\x00\xaa\xf6\x99\xc0]\xea\xbe\xa6\xd7x\x08\x86\x88\xa1bD\x15\x82B\x10\xa7\t\
\x19K\x1d9Iy\x82\x94\xc0\x11\xa0\xe4\xbajD\x15D\xed3\x82G\x1ce\xff\x10\xbc\
\x82\x1bA\xa5\xcc`4\x01R\xee0\x13\xa2Y\xc9\x02\x1c\x8c0y\x82\x9a\xce\x07\xc0\
\xddAt?x\xb8\xbd\x01\xe2\x15\xdcPQT\xa0Q\xa7\t`y\x88\xe5q\x16T\xfd\xf7q\x04B\
\x84\xe6\x00x\xeevx\xff\xb5\xdf\xb0~\xfe\xd5\x03\xe0\xb73@e\x0c\xee\x04\xf5\
\xca\x01\xa7\t\x86\xa5\x0e\xcf\x1dj\xe6E\xbbS5@cU\xb8\x83\xe0\xef\xfc\xe3\
\xd7|\xf8\xfa\xb3\x9cy\xf9\x17\\=\xf7\xea-\xe0\x8a\xdd\xc6\x00\xaf\xe0F\x08N\
T\'(\xc4h\xb8\x8d\xb0\xdc\xa1\xe6%\x02E\x8e\x03\xa2-\x12""\xe1\x00\xf8\x857~\
\x8f{fg\xe3\x03\xce\xbc\xf4s\xd6\xcf\xfd\xbd\x80\x8b\xa1d\x04?`@P+\xde\xab\
\x13\x024\xc1\xe97\x8e\xe7\x0e\xcfCt\\zG&\xe4ZdT\x02\xaa\xb7\x07\x1f\x8f\x9d\
\x8d\xf79\xfb\xd23\\;\xf7r\x01\x17\xdf\x1f\x00d\x1c\xfa\xeayPh\x1b\xa7\x89\
\x0e\xdea\xd6\xa1\xee^\x940A\xf6H\x13c\xcd\xfd\xc2\xf6\x94\x86\xdc\xb1\xf4(s\
\xcb\x8f\xdfry;}\x84\x95G\x9eA0`\x84\xe5m\xdco}\x86\x10t\xe2y\xac\xde7\x01z\
\x11\xdc\n\x07&: \x02x\xa0m\xa4V;@\x84\xde\xccQ\x16\x1fx\x8a\xd4\xedp\xf5\
\xfc+\x93\xcb\xd3p\x83\xde\xf4<\xf3\x9f\xfb&*\xc6\xf6\xe5\xd3\xe4\xd1\x8d\
\xc9\xef\xb1\x99f\xee\xae{\n\xb8:M\xa8\x86D\xa1\x89`\xb9\xc3\xb2U\x1d\xc8\
\xa0\x02f\x01Cji\x15\x10&l\xef\xcd\x9e@4\xe2\x96\x80r\xc1\xbb\xaf\xfc\x8a\
\xb4\xb3J\x7fz\x9e\xff\x9e\xfe\xed-\xde7\xfdY\x06\xb3\x0b\x05<\x8e\xa3P\xc0\
\xdb\x08X5 \xd7,P\x11\xdcJ\x9dV\t\x88\x08.LR\xed\xd0\xdd_e\xfa\xf0}l\xaf\xbd\
9\x01\xd9\xdd\xfc\x88\xb7\xfe\xfaKD\xc3\xc4\xb0\xf1\xb8\xfb\xc47\x98=\xbcD\
\x13\xbd\x86_*\t\xa1\x89\xe0\x96\xf0\x9c\xf6t\xa04\x94\x01#\x82j\x997\xe5y38\
\xca\xd1\x87~\xc6~\xb9\x05?\x00\xde\xf4\x0e\xf1\xc5\xc7~J\xaf\r\x05<\xde\x04\
\xde\x08m\x03\xee\t\xcb\xc3\x92\x86\xa3\xda4\x8er S\xbb\x9b}"\xa3b,\xdd\xffc\
\x16N}\x1f\r\xed\x01\xc6\xef\xbd\xfd\x14\xf7=\xfa\x14\xcb\xa7\x1e\x9d\x80\
\xc7\xeau\x08B\x1b\xa1\x8d\x8a\xdb\x10\xb7\xaeHqJ\x85\x03\x9e\x15s\x10\n\x07\
\xbc\xa8\xf9$\xcf{3\x0b|\xe9\xc9\xe7X\xff\xf0\xcf\x9c;\xfd\x1c\x1b\x97N\x93j\
\xf5\x8b\xcd\x14\xf3+_\xe1\x81\xaf?\xcd=\x0f}\x8f\xb6mn\x01\x8f*5\xfcJ\xbf\
\xe7\x95\x037e\x81\nXR\x92\x95~\xaf\xdf+\x06LD\xa6V\xb5\xb6?\xe0\xd8\x03?d\
\xf9\xde\xef\xb2}\xf5,\xdb\xebo\xa3df\xef<\xce\x91\x95\x87\x99\x1e\xcc\x1c\
\xf0\xbc\t\xc2\xa1\x81\x12\x832\xd5S\xdahX\x1e\xe1y\xb8\x97\x05"\xd0\x8d"\
\xd9\x84\x8dm\xe1\xd4Q\xe5\xd2zfk;\xdfTR\xf7\xb4\xbd\x99\x1a0=\xf82K\xc7\x1f\
\xd9K\xb51\xe1\xf6\x81\xdfqH9\xbe\xd8pi-\xd36B\xd3\x08\xe27G \x15ju)\x90\x0c\
.\xac\t\'\x16\x9d\'\x1e\x84s\x9f@7\xa2\xd6sAE\t\xea\x84 {\xda^E&\xdc\xcc\xf6\
\x1a\xf6~O8~w\x83 \xacof\x8e-\x08MTR\xea\xb0<\xac\x1c\xc8P\xaaw\xc0\xdd\x19v\
\xc6kof\x8e\x1c\x866Z\x05\xda\xabj\xb7\x14\x96O\x01\x8f\r\x88\x08\xabW2[\xbb\
#\xa6{pbQ\xf9\xdb?/\xb2\xb9\xb9\x8d[":\xb5\x1f\x00\xdc\x85A\xdf\x18\xa5\x8c\
\xbb\xb1\xb6Q:\xd8\x18\xac\x94Q-k[C\x1d\xa3\xd3\x8b\x8eEh\xa3 ^"iU\xc4\xd4\
\x95&8m\x14\x16\xef\x14\x96\xe6\x95l\xc6\x0b\x7f\xf8\x17f\x1d\xb8\x11\x8f\
\xcd]\xe5\xcc\xea\x11\xccJ#\xa9!0\x88\xd0\x84L\x1b\x85\x18tR\xc3\x83\x16\x1e\
\xc4\x89!U\xdf\xe3\xb8\xd7s\x9a e\x8dB\xaf1\x1a\x15\xa2\n\xbbC\xe1\xf4[[\xbc\
\xf8\xc7\x7f\xf3\xde\x07\xab\xb8\x97\xce(\x9e\xbck\x8d\x85\x99M\xce_\xbdc\
\x12\x85\x11\xb1\xf6\xed%2f`\xa9#\xe5\x8e\x9c\x129\x15\x02y\x1eb\xb5\xa8\x94\
\x0e\xa7+\nge?>/kWz\x00\xebp7<\x0f9yr\x19\xfd\xc9\x8f\x9e\x94o}\xfe=\xee]\
\xf8\x04%\x17A\x1aW\xc7}_\xb5\xd9J+\xfd\xa9\xc3\r\xb7\\V\xb7\xc9\xea\x9e\x8b\
b\xba!\x18G\x97\xe6\xf9\xc1\xb7\x97\xf9\x1f\x92tznH\x8fy\x14\x00\x00\x00\x00\
IEND\xaeB`\x82'
down_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x042ID\
ATx\x9c\xa5\xd5Ko\x1bU\x14\xc0\xf1\xff\x8c\xe7\xe1g\xe2\xa6\x84\xa8\xa8\x82\
\xd0\x88E\xabJ\x08\t\x8a*\xb1@\x02v\xec@l`\x87\xf8\x1e\x91\xf8\x06 \x90\xd8\
\xb3\xe2S\xb0aS\x1ej\x8bhIe\xd2\xa8i\xa8\x13\xc7\x8f\xda\xe3\x99\xb93\xf7\
\xcee1\x1e\xc7\xae\xed\xc4c\x16Wc\xddk\xfbw\xce\xf1\xf1\xb9\xc6\x0fw\xb5\xfe\
h\x1b\x02\t\x91\x02\xa1 N&^+\x88\x12\x08%\x08\x99\xeeE\xa3\xf3l\t\x05~\x9c>\
\xc3\xd1^(\'>7:\x7fqOH0\x13\r\x00\xa6\x91\xae\x82\x01F\xba5~\xca\x04\x94\x86\
db\xa9\xd1\x92I\x1a|\x16t<\x91\x84\x18%\x15\xc4g\x81\x87Y\xa2\x12\x94R\x98J\
\x8f\x0e\'\xb2\x11\nNzC\xfex\xb0\x8f\x17\xeb\xf4|"\xfb\xec\xfdB\x82\x17\x9fe\
\xfcb\x05\xc6\x99gU\x12\n!\x13\xc2\x11\x8e\x14X*\x99\xc5#\x05a\x9c\xf0\xfdw\
\xdf\xb0qe\x9bO>\xfb\x9c\xcb\x9b\x9b+\xe3\xa1L\xe8{\x01a\xa40\xdc**Iq\xad",\
\xa5g\xf1HA\xb1R\xe3\xda\xcdw\xf8\xe5\xa7o9\xd8\xfb\x93\xdb\x1f\x7f\xc1\xdb\
\xb7\xde\xc5)\x96s\xe1\xfda\xc0\xc0\x1b\x12)0\xdd\x1aI\xa2\xc78\xb1O\xe1\xc3\
\xafvw\xafT\xa7q\x7f\xf4%\xf5\x8d-\xee\xfcz\x87\xb0w\xc2\xc1\xdf\xf7y\xf8\
\xcf!Vu\x13wm\x8381\xce\xc5\xbd0\xe6\xb4\xd3a0\xf0\x90X\x18v\x19,w\nG\n\n\
\x1f|\xb9\xbb\xbbU\x99\xc5#\tv\xa9\xc2\xa3\xc3\x16\x9d\xe6\x13\xb0\\\x82a\
\x9f\xc7\xfb\rN\xfa!v\xf5\x12\x96[\x99\xc1\x07\xa1\xa4\xd5\xeepzz\x8a\x88\
\x15\xda.\xa5\xb8S\xc2\x88\xa7\xf1\xb4\x07\xf4|\\(\x90\xda\xe0\xad\xdb\xef\
\xf3\xf8\xaf\xdfP\x1a\x0c\xb7\x86L4O\x1e\xfc\xceq\xf3\x19Wo\xdc\xe2\xea\xceu\
\x12\xd3!\x94\x9aV\xe79\'\xad\x14\xc6.\x81S\x1e\xe1e\x1cb\x84\x12S\xb8\x96\
\x11\x96L\xe6\xe3Y\xc3m_\xbb\xc6\xfa\xab7\xe86\x0f\xc1.aXEp\xca\x88(f\xff\
\xc1]\x8e\xdb]6^\xd9\xc1\xf3C\xfaC\x1f]pa\x84fx\xc5\xd2\x84A8\x83#E:\x07\x16\
\xe1\x91\x02\xa3\xe0\xb2\xf3\xe6{`\x97\xc78N\x05\xc3)\x83]b\xe8y<=h\xd0\xeb\
\x0f\xe6\xe2U\x1b,bT0\x98\xc1Q\x023N\x16\xe3Y\xb7o\xbfq\x9d\xf2KW_\xc0\'\xa0\
\xe2\xfa\xec\xde\x08\xaf8\x90\x88!z\x0e\x8e\x8c\xd2At\xd1\x90q+kl\xbe~s>^\
\xaa/\xc4\xab\x0eTL\x89\xef\xf5\xe7\xe2Z\nL\x99\x9c\x8fg\xdd\xfd\xca\xceu\n\
\xe5z.|\xa3\x08\x81?D\x8a`.N\xec\xa7\x01,3\xe1\xca\xeb\x97\xa9\xbd\xfcZ.\xbc\
h&\xf4\x9f\xf7\x16\xe2H1}\x17\x9c7\xe1\xe2\xc4\xe4\xd2\x95m\x0c\xa7\xb2\x14^\
s@\x84>\xde\xa0\xbf\x10GE\x98?~z\xc9Xv\xb6;k\x9b\xd8\xeb[K\xe1eKs\xda\xe9\
\xa2\xe3p!\xae\xa5\xc0\x84\xe5/\x16Up(\xd6\xb7.\xc4\xab\x0eh\x15\xd1>m\x9f\
\x8b\x93\x05\x90\xe7J-\x94\xd60\xdc\xea\xb9x\xd5\x86V\xbbG\x14z\xe7\xe2\xc8\
\x08\x0b\x96\xc7C\t\xca\xb01\x9c\n\xdar\x17\xe2\x16\x8a\xa3\xe6\xf1\x858jT\
\x81e\xf1\xecL\x17\xec\x85x\xcd\x81^\xdf\xa3\xd7\xe9\\\x88\x9f\xf5@\x0e\\)\
\x85\x11\x0b\\S\xcd\xc5\x8b\x05\xcd\xc1\xd3&*\n.\xc4\x89\xfcQ\x05r\xe0HA\xa2\
\x04:\xf2g\xf0\x8a\rB\x08\x0e\x8f\x8e\x96\xc2\xc7M\x98\x07\xcf\xee\xf3\xa1\
\xd7\xc7BN\xe15\x07\xf6\x8fZ\x04\x83\xeeR\xf88\x80\xbc8R\x10\x0e\x07xC\x7f\n\
\'\x914\xf6\x1f/\x8dO\xf5@\x1e<\xbbX\x9a\xc7-\xdc\x82\x1e\xff\x14\xadn\x9f\
\xe3\xe6\xbfK\xe3\xe3\n\xac\x82#\x05\xedv\x0b\xdf\x0f\xa8:\xb0\xeeh\xee\xed\
\x1d\xa0\xa2pi\xfc\xeco\xb8\x02\x8e\x12D\x81O\xe3\xe91\x1bEx>\x0c\xd9k4r\xe1\
\xe3\n\xac\x82gCf\xefQ\x83@D\xdcm<c\xd0\xeb\xe6\xc2\xb5\x14\xe9$\\\x15\'\xf6\
\xe9u\x04?\xdf;\xe0\xfe\xc3G\xb9q"\x1f\xa3^\xafc}\xdd\xd5\xab\xe0Y\xb7\x1bIL\
\x12\x05\xb9q&+\xb0*\xae\xc7@~|\xfc7\xfc?\xf8*e\x9f<\xfb\x0fT{\xea\xc3\x87j\
\xf9\x90\x00\x00\x00\x00IEND\xaeB`\x82'
left_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\
\x03IDATx\x9c\xc5\xd7Mo\x1bE\x18\xc0\xf1\xff\xbe\xc4^\x9b\x86V\x81\x86\xf2\
\x8e\x8aJ+\x90(jE\x85\x84\xd4\x03\x12G$\xee\\\xb8\xf2-\xfa9\x10_\x82\x0b\x07\
N\xbd \xd4"\xd1&MQ\xd44iZ7N\xea$vl\xafwwv\x9e\x99\xe1\xe0\xf7\xc4i\xeb\xf4%\
\x07k\xf6\x19\xef\xccoV\xf3\xb2\xcfz\xbf.8w\xba\x04\xb9\x05cA[0\x0e\xc4\x808\
\x90^\xbd\xb2\xa0\xcd\xf0\x1eq\xddX\xdb\xee=\xa9t\xe3\xbc\xf7\xbf2\xbd\xd8t\
\xafS\xe9\x96\xfd87\x90\t\x84\xa7Kpq~X\xd9\xbfa4N\xfa\x8d\xfb\xa5\x1d\xe9L \
\xd6P\x0c\xc0\xb9\xee\xe05\xe0\x01\xb6\x17\xe7\xbd\x81j;\x8e\x1bc\xf0G;;*\
\xde\xefP\x19\xc8\xccx\x9c\xe8n\x9d\xea\xd5\x8d\xe2\x88\xc27\xf6\xf8pgr|m\
\x8f\x0fG\'\xf8\xc6\xbd>\x1ck\x08l>\xc0\x11\x85/\xaf\x18\xef?\\\x148\xe6J\
\x80\xd5\x03\x1cQ\x84\xe2^\r\xde\xc9-\x99\xf1\xf1\x80\x13\x0581\xe3\xd1\x8cs\
$\x8b\x07\xb8\x93\x9cP\xec\xcb\xc3\x13mi\xa5B\xa2\x1d\xda+R\x0c!\nav\x06D\
\x84\xb8\xbd7\x86#\x8a\xd0\xd8\x17\xc33q4:9{\x1dE\xac,\xe2\x15\xa0P&\x1a\xc1\
g|\xcbn\xb3\x89\xcd\xb31\x1c\xa3\x08\x95=\x1a\xdeN\x85\x9dV\x87\x9d\xbd\x0e\
\x89v\x98\xa0\x887S>\x80\x97Bh\xc5)\x9d\xb8u\x00GrB=\x05\x9ej\xc7n3\xa6\xba]\
\xa7\xdeN\xc9\xc4\x83\x99\x12\x14\xca\x87\xe2\x9e3\xec\xd6\xeb\x13q\xd7\x9f\
\x82g\xe1\xad4\xa7\xb2\xb5Mu\xb3F\xb3\xddA\xc22^\xa1\xfcL\xbc\x18:6\xb7\x9b\
\xe4ig"\x8eN\x08\xb5\x9d\x8cg\xda\xb2\xb1\xbd\xc7ze\x83\xcd\xcd-\xd2\\\xe3\
\x82\x08J\xa7zx\xf9\xa9x\x14\x82R\x8a\xc6\xee\xee\xa1\xf8`\x1b\x8e\xe2\xb5V\
\xc6\xea\xc3\xc7\xdc_{@\xa3^G[o\x08M\x81\x87\x9ee\xfd\xc9\x0eZ\xa5\x87\xe2\
\x98\xde\x1aP\xe2X\xab\xd4X\\^\xe1\xd1\xfa\x1aI\x92\xe0\xc2h\x1c\x9a\x02\x8f\
B\xd8\xad\xb7i\xee5\x9e\x8a;Q\xdd)\x88Sa\xe9\xde*k+\xcbd*?\x08M\x89G\x01\xa4\
i\x82\xd3\xd9SqD\xe1\xfd\xf2\xa7s\xa1\xdf\x9d\x82\xda^\xcc\xfd\x07\x15\xaa\
\x9b\x9b$\xa9\xc2\x06\xc5\xa9\xf1\xfeu\x1c\'\xdc\xb8u\xa7\xb7\x00\'\xe3H\x8e\
\xf7\xf3\x1f\xce\x15\x83\xf1}\xde\xc9\x84Z\xa3E\xad\xd1\xa6\x9d\n\xe2\xcdL\
\x85\x97B(\x06\x8e\xbb+\x15\x16\x96\xee\x1e\x8acTw\r87~\xc8\x18/\xe4\xc4\xc9\
9\xfc\xf2\x1ce%\xb4SM\xa2=L\x10=\x17\x1e\x050[\xf4\xb8|\xee\x0c\x1b\x955v\
\xb6\x1a\x13q\'j\x98\x11\x1d\xf6bq^HX(Q\x8c"B\x1f\x02\x1c\xe5\xc0=\x03\xef\
\x96\xef\xbcY\xe0\xeb/>\xc5w2\x11\'O\xba\t\xc9\xf3\xbc\xcf\x95\x80\x88\xa1\
\x93\xa4\xec4c\x1a\xed6\xceh\xa2\xc0M\xc4\xfb\x83\xfa\xe6\xfc{\x9c\xfd\xf8\
\xfd\x898\xa2\xf0\xd5s\xe0\xfb3\x19\x95\xb4\xa9\xd5vX^}\xc4\xbd\xf5*\x8df\
\x8c\xef\xcc\x01\xbc\x14\xc2\\9\xe0\x87\xab\x97(\x15\xc2\x038\xa2\xf0\xf5\
\x11\xd2\xa8~c\x95v\xa8V\xab\xdc\xbc\xb5\xc0\xf5\x9b\x8b,\xadV\x89\x93\x8cb\
\x0f\xef\xff\xbe\xfa\xe8\x14W.}y\x00w\xa2\x08s\xd3M\x9d\xa7\xc5G\x8fW+9\xdbO\
Zl?^c\xb1\\\xe4\xc2\xd9\x0f\xb9\xf2\xf9\'\\xw\x96R\xe83[\xf0\xf8\xe9\xfb\xcb\
\xfc\xf7\xef\rj\x1b\x8d\x01\x8e(\x823?^\xbb\x96\xc9\xd1\xf1\xfd\x87\x8cJ\xda\
<\xae<\xe4\xf6\xe2\x1dV*5\\P`\xfed\x99s\xf3\x11\xfe\x1boq\xf3\xef\xbfp\x92\r\
\xf3\x81T\x86\x1f\x0c/\x8a\x8fn\xb5\\r\x96\x97n\xb3\xbc\xf0\x0f\xbf\xcf\x9d\
\xe4\xbb\xab\xdfr\xf1\xb3\x0f\x98?\xfd6[\x8f\xee\xf7\xda+\xbc\xf3\xbf9\xa7\
\xed\xcb\xc5\'\xadvDQ\x08}\xf2N\x0b\'\xe9\xf8\x1a\xd8\xff\xb9\xf4*p\'\n\x95\
\xa9\xc1\x93\x0f\xce\x81\xd7\x85\x0f\xdb\xef;\x07\x8e\x13w\xa2\xf0\x8f\x13G\
\x14\xff\x03\xe8\x84\x1b+\xdf\xf26\x9e\x00\x00\x00\x00IEND\xaeB`\x82'
right_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\nI\
DATx\x9c\xc5\x96Ko\x1bU\x14\xc7\x7f\xf3\xb4=&\xd4mQ_H\xd0"\xdaD,\xda\x8aR\nB\
\xa8\xb0a\x83\xc4\x82\r{>\x01_\x00\xa9;>\x04\x0b\xb6,\xd9\xb0fQ@\x08\x81BU\
\x92\xaa\xa1\xa5\x0f\xbbQ\x12\'c{\xecy\xdf\x07\x8b\xf1\xb86u\x9c\xa4I\x95\
\xd5\x9ds\xe6\xce\xfd\x9d9\xf7\x9c\xff\xbdF\xa3\xd1\xe0\xbb\xdf;:S \x15\xe4\
\n\xa4\x06!Ah\x10C\x7f\xaa \x97O\xe7\x08]\xd8\xb9*\xe6\xc4\xa2\xb0\xb3\xe1\
\xfbT\x0emY<\xc7\xa2\x18K;\x93\x90\x08\xb0\xbf\xf9\xa9\xa3/\x9dx\xea,\'\x8c\
\xdbQ\xf9q9\xaa\xb1\xc5\x04\x0cr\xa8X\xa0u\x11|\x0e\x18\x80\x1a\xda\xd90\xd0\
\\M\xc2\xa5\x94\x98R\xef\x1f^.\x98JH\xe4\xa4\x1d\xe5\x85/\x1d\xfa\xc6\xe1\
\x88\x14S\xaa\xc3\x83k\x99\x15\x198,8y\x84]nA\xb9\xf8\x1fK\xf7\xb1\xaa\x1e\
\xa7N\x9dBH\xe3\x85\xc2\x11)\xb6T\x93\x7f\xde\\\xf7\xf9\xfe\xdb\xaf9s\xe1\n\
\xd7\xae\x7f\xc2\xf9\xf9\x0b\x98N\xe5\x85\xc0\x8b\x00\xf4d\xda\xaf]\xbd\xc2\
\xcd\x9bW\xb9\xfb\xf3\x0f\xdc\xbf\xf5\x0b\x8d\xb3\x17Yx\xf7#\xe6\xdf\xbaHm\
\xee(\x992\x0e\x0c\xaeE\x86-\xd4\xe4\x9eKm\xf2\xe9\xe7_\xd0\xbc\x7f\x87\xb8\
\xd7\xc6o\xad\xf0\xebz\x8b\xc5\xdf\xcer\xf2\xcdK\xbc\xbep\x89\xa3\'N#\rg\xdf\
pD\x8au\xfd\xcb\x1b7\x8eT\'\x0b\xce{i\x8e\x9e\xac\xd0\xfa\xf7.\xd8\x15\x8c\
\xca\x1cBi\x02\xbfM\xeb\xf1CV76I\xa5\tN\ri:\xcf\rG\xa6\xd8#q\xf8_\xb5\xbf\
\xf7\xc1\x87\xdc\xb9\xfd\x17\xdd\xf6*85\x0c\xbb\n\xae\x872\x1d\xfa]\x9f\xfe\
\xd2"n\xb3\x85\xf7\xca\xab\xd4\x8e\x9d\xc1\xacx\xa4\xd2\xdc\x13\x1cQ\xb6\xe1\
\x94V\xb3\xdd\x1a\x97?\xfe\x0c\xcbk\x8c\xe0\xb8u\x0c\xd7\x03\xc7\x03\xd7#\
\x97\x9a^0`cm\x95\xcd\xf6&a\x94\x90\xe4z\xd7p-RL\xa1\xb6\xef\xf3\xb3o\x9c\
\xe7\xe4\xfc;S\xe1\x86\xe3A\xad\x81\xe1zh\xabJ\xaeM2\xa1\x90\x18\xb8\xa6\xc6\
6\x14\x86\x88g\xc2\xc9\xa3a\x11n\xd3\xe7\xb9\xb6\x98\xbf\xfc>\xbe\xdf%\x13b*\
|\xc2\xe7z\xd4\x1d\xf0\x1c\x9b\x97\x9d:H\x9b\xa0\xd7\xa3\xd7MI\x92g\xe1\xa36\
\x9c%2\xf5\xc6q\xce,\xbc\xcd\xa3\x95%\xb4S\xdb\x05\x1c\x1a\x15\xf0\x1c\x83\
\xbaS\xe5\xdc\xf1*\xc8c\xf8\xdd.\xcd\'kl\xb5\xd7\xc8\xcbm\x91\x19F\xa3\xd1\
\xe0\xab\x1f;z\x96\xc8\xf4\xa3\x8c\xbfo\xfdI\x14\xc5\xbb\x84S\xd8v1\x96\xef\
\x1cC1\x08\x07,\xdfk\xb2\xf2\xcf\n\x9d\xcd\rl\xd8Y\xe1\x94\xe5b\xd7\x8f\x82\
\xae<7\xbc\xee@\xa3b\xf2\xda\x919N\xcf\x9dC\xc4\x01\x8b\x1bO\x8a\x00v\x92\
\xd7\xad\xde\x800\xcd\xf7\x05\xaf\x9a\x92\x87\xeb\x01\xb7\xef>`iy\x99\xb0\
\xe7\x83\xc8\x8a\x00f\xc1\xc3L\xb1\xde\xdeD\x19\xce\x9e\xe1U[\x93$\x19\x0f\
\x1e\xb5Y^\xb9\xc7\xdaj\x93<)\xdb2+\x84\x08f\x1f,[\x9d\x80$\xc9\xf6\x04wME\'\
\x08\xb9\xf7\xf0\t\xad\xc7\x8f\x18\xf4\xb6@\x0e\xab\x7f\x0c\xae\xc50\x80\xed\
\xe0Q&\xe9\x06\x01z(D;\xc1\x919\xcd\xad\xb1j\x8f\x82Q\xb5O\x83\x93E\xc3\x0cl\
s\xaa\xf9\xdd\x1e\xb9d&\xbcf)\x928\xa1\xb5\xb9E\xbb\xbdA\x18\xf4&\xfa|\x16\
\x9c2\x03\xd3\xe0\x838%\x8c\x92m\xe16\x92\xb0\x1f\xf2\xd8\xef\x10t}\xf2$|Fdv\
\x82\x8f\x02\x98v\xa4\x06\x83\x08e\xb9\x13\xf0\x9a\r\x15r\xfc\xce\x80A\xafK\
\x1c\xf6\xa7\xca\xebn\xe1\x1350\x0e\xefG)Y\xaeFp\xcf\xd2X*\'\xee\x87\xf8a\
\x80L\xe3m\xb5}/\xf0Q\x06\xc6\xe1q\xae\x88\xe2\x14\x9c\x1a\xb85\x1c\x9d\x93&\
\tQ\xdc\x1f}tP\xf0\xa7m8v\x99H2\x89\xb6*`9\x18YB&\xd3\x1d\x8f\xd4\xe7\x85\
\x8f20~\x93\xc9q\xd0\xa6\x84<A\xed\xe2<\xdf\x0f\\\x8b\x14\xb3,\xc2\xbd\xded\
\x0e\x02N\x16\x15\x01\x1c\x16\x9c\xf1\x0c\x1c\x06|\xb4\x05\x87\x05G\xa4\xfc\
\x07\x8a\xed\x03}\xa8\xdcA9\x00\x00\x00\x00IEND\xaeB`\x82'
smile16_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x02\xa3IDATx\x9ce\x93\xdfkSg\x18\xc7?\xe7WL\x1b\xa2\x07!U\xa9\x89\xe9j\
\x90H\x87\x0cA\x86"\xb2\xf6B\xa1\xe0\x8d\xca\x19.\x88XJ\xa0\xb7R\xbc\x14\xbc\
\xb2\xfb\x03z\x93u\x17\xbb\xdb\x8dcHA\x85\xe4\xa6\xec\x80\x11d\xa3\x9548WMW\
\x10\xd9\xc4\xa2\x89\xc99=\xfdz\xd1D\x83\xbe\xf0\xde\xbc\xcf\xfb\xe1\xf9\xf2\
\xfd>\x0f\xae\xeb\xd2\x7f\xcb\xe5\xb2\n\x85\xcb\xcaf\x0f\xc8\xb6\r9\x8e\xa9\
\\.\xadbqZ\xbe\xef\xeb\xf3\xff&}\xc7\xf3.\xe9\xea\xd5\xf3\x8c\x8d\xfd\xc3\
\xdd\xbb\'i\xb5~\xa0\xd9\xfc\x9e;w\x8e12r\x1f\xcf;\x85\xe7]T?c\xb8\xae\x0b\
\xc0\x89\x13\xdf(\x93\xf9\x9f\xf9\xf9\xf38N\x004\x81w@\x04t\x80g\x84a\x8d\
\x99\x99\x80F\xe3$\xd5\xea\xb2\x01\xec(\xf0\xbcK\xcad\xa0T\xba\x8d\xe3\xe4\
\x81D\x17\xec5k\x03-\x1c\xc7\xa0T\xdaE&\xb3\x84\xe7]\xd8)\xfa\xbe\xaftz\xaf\
\x82\xa0&\xe9\xb9\xa4\x07\x9a\x9d\x9d\x15 \xa9 \xa9 @\xa9TJ\xd2\xa0\xa4\x01\
\x05\x01J\x1fD\xbe\xef\xcb(\x16\xa752\xb2\xc5\x8d\x1b7\x01\x0bx\x82a\x9c\x03\
@*\x00\x9b\xe4\xf3OY]]E\x1a\x04E\xb0e0\xf7c\xc4Z\xa3\x80Y\xa9\xdccrr\x18\xd8\
\x00\x9e\x01\x7f\xf6Y\xd4\x016X__\xef{\xdb\x86\xce \x93\x13I*\x95E\x0c\xc71\
\xd5l^\xc7q\x92@\x9b\xa9\xa9\x97,,\x04\x1f\x8d\x83\xf5\xae\xa1]8\x8a`s\x88\
\xb0m\x918\xd4\xe8\xc5\x18t\x1d\x7f\xcb\xc2B\x08l\x02\xcb@\xbd\x0f\x16h\x8b\
\xaf\x0e\xc6!\x1c\x800\x0e\x80\x99\xcd\x0eS\xaf\xff\x0b\xbc\x02\xea\xe4\xf3\
\x8f\x80\x87\xdd\xce\xfa\x04\x13Bd\xb2\xf6\xf2-\xb4\x92\xd4W\r\xb2\x87R\xd8\
\xe3\xe3gY\\\xfc\x85\xb1\xb1\x18 j5H$D\xb3\xd7\x98m`\x0b"\x83\xe3G\x93\xe8\
\xf90\xb4v\xb3\xf8\xe05\xe3g&z1\x1a\n\x82\x81nL;Q)\x1eW,\x16\x93m[J\xc4m\x1d\
\x1b\xdd+m\x1c\x91j\xa7\x15<\xfeN\xe9\xfd1\xf9Ke\x19\xae\xeb\xe2y\x17\x14E?S\
*\xd9}\x92\x05\xe66\xc4,&\x8e\x0eQ\xfe-\x05\xed$\x84\xbb\x98\xbeY\xc3J~\xcb\
\xaf\xbfW\x8c\xbeQ\xfeZ\x99\xcc\x12\xf3\xf3\xe08=\xf5&\xbc\xdf\x03o\xf6C;I\
\xd8\x8c1s\xebo\x1a\xff\x1d\xa0\xfa\xd7\xda\xa7Q\x06\xa8V\x97\r\xcb\x9abt\
\x14\xe6\xe6`e\x05\xc2\x8eE\xd81Yy\xfa\x8e\xb9\x9f^0z\xee!\xd6\xee\xd3\x1fa\
\x00>_O\xdf\xf7U,^S.\xb7O\x8e\x8d\x1c\x1b\xe5\x0e\x0f\xa98}E\xfe\x1fK_\xac\
\xf3\x07\xc0b=\xfa\xc1x\xb5\x84\x00\x00\x00\x00IEND\xaeB`\x82'
smile32_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\t\xc0I\
DATx\x9c\xc5\x97il\\\xd5\x15\xc7\x7fo\xde\xbc7\xfbx6\xdb\x93L\xe2\x988\x9b\
\x81\x10H\xd8\n\xa8-\x90PJ\xcb\xee\x90\xb0\x94B(\x08\xa9\xad\xa0\x85\x82J\
\xa5\xaa\x1f\xa0\xa2\xa8,\x95\xba( \x81\x08!\x0b!\x86\x8a\xadI\x03\x05Z\xc2\
\x1ah\x16\x12c\xc7`;\x1e\xc7\x9e}<3\xef\xbd\x99\xb7\xdc~\xb0\xb3\xe1\x80\xaa\
~\xe9\x95\xae\xf4\xf4t\xef\xfd\xff\xee\xb9\xe7\x9c{\x8f\x14\x89D\xf8\x7f6\
\xf7\x7f3h\xcd3\xcf\x8at:\x8d\xaeiH\x92D\xa1P\xa4\xd1h\xa0\xe9\x1a\xd9l\x16\
\xaf\xd7\xcb\t\xed\xed\xa8\xaa\x8am\xdb\x04C!R\xa9\x14\x91H\x84\xe5]WI_\xb7\
\xb6\xf4U\x16X\xfb\xecz\xd1\xdf\xdf\x8fe\x9aD\xa2Q\x12\x89\x04\xa6i\xd2\xbf\
\x7f?\xbb\xf7\xec\xc1\xeb\xf5\x92lM\xb2{\xcfn>\xf9\xf8\x13\x96]\xb4\x8c\x13;\
;\t75!\xcb2\xd9L\x86\\.\x8f\xdb\xedf\xee\xbc\xb9\xfc\xfcgw\x1c\x17\xe4\xb8\
\x16x\xe4\xd1?\x88\xbe\xbe>\x96,^B"\x11G\xd3t,\xcb\xc2\xa8\x1b\xf8|>T\x8f\
\x87P(Dkk+\xc1`\x00\x80\x83\x07\x0f2o\xee\\|>\x1f#\xe94\xd3S)\xe6\xcd\x9fO\
\xb5Z\xe5\xa3\x0f?\xe2\xea\xaek\xc4\xb9\xe7\x9e;\x05\xe4\x18\x80u\xeb7\x8a\
\xdd\xbbv\x91\xcdd\x08\x04\x83\x94\xc7\xcb(\x8aB\xbe\x90\'\x16\x8d100@*\x95\
\xe2\x9co\x9c\x83n\xe8\x94\xcbe>\xeb\xed\xc50\x0c\x06\x07\x06Yz\xe1\x85L\x9b\
6\r\xdb\xb6\xd9\xdf\xd7G\xad\xa6\xe18\x0e\xc5R\x91\xe1\xe1a\x06\x07\x07\xb9\
\xf2\xaa.\xb1r\xe5JV\\\xd3%M\x01x\xe5\x95W\xe8\xee\xeef\xe1\xc2\x85\x94\x8aE\
\xa2\xb1\x18~\xbf\x9f\xcf\xfb\xfbY\xb6\xec"\x92\xc9V*\x95\n\xd1h\x94x<\xcec\
\x8f=FOO\x0f\x99L\x06\xaf\xd7\xcb\xce]\xbb\xb0,\x8bH4J\xa5R\xa5\xbb\xbb\x9bb\
\xa9\xc8\x9c\x8e\x0e2\x99,\x8a\xa2\xa0\xeb:{\xf7\xee="\x1a\x89D\x88D"<\xb7i\
\xb3ho\xef\x10\x1e\xaf_\xdcu\xd7="\xdc\x14\x15\xe7_\xb0T\x84\x9b\xa2Br\xb9\
\xc5\x82\x05\'\x89\xef_z\xb9\x98={\xae\x981c\x96\xb8\xeb\xae{\x84?\x10\x12H\
\xb2@\x92\x85\xe4r\x8b\xef\\|\x89X\xb8p\x91hk;A\x9cz\xeab\x91hn\x15H\xb2\xf0\
\x07B\xe2\xf4\xd3\xcf\x14\x92\xcb-\xce8\xe3,\xd1\xb5|\x85\xd8\xb2u\x9b\x88D"\
G,\xd0\xb3o\x1f\x8dF\x03\xbf\xd7\xcb\xa7\xef\xbeC\x9bdS\xfdl\x1fm\x8a\x0b\
\x11\x8f\xe2\xd3*\x94v\xef\xc4_\xab\xe1\xb7\x1d\xde{\xa1\x9b\xd9.\x17x}\xe4M\
\x93\x8am3\xf0\xe9^\x86GF0\x1c\x1b\xa1\xebx\x05\xc4\x90@\xd3\xe9\xed\xed\xc5\
+\xcb\xe4\xb29Z\x93I\xca\xe5\xf2\xb1Q\xb0a\xe3&\xa1e\xb2\x046>\xcdl*\x04B!\
\xacX+\xdbX\xcc\xe6\xfa)\xb42\xca\xaa\xe6/\x98\xa3\xd4\x10\xba\x81(\x14A\xd3\
\x11\xe9\x0c\xf9L\x8e\xf2h\x81}\xca,^\x9b~6\xfd\xb2\x97\xcer?g\xa5\xdf!\\/\
\x93G\xd0\x87M\xc4\xad0\xe7\xd2K\x98y\xf3\r\\\xff\x83\xeb\x8f\xf5\x81\x95+\
\x96K\xef\xdd\xb4JL\xa3\x8a\x14\x0c E\xa3lu/&y\xe3O\xd9\xf9\x84\x865>H\xcf\
\x80\xc2\xf3\xe7\x17\x898uDS\x18gx\x04a\xda\x04\x1a&=\xbe\x0e\x12\x8f\xaea\
\xc7F0k\xa3\x8cU\x0e0\x16Hr\xe7\xee\xa7\t\xe3\x90@\xa2b9\x94_\xfb;\xd3N>\xe9\
\xb0\x0b\xb8\x0e}ly\xe0A\x91\xd8\xb9\x1d\xc9\xed\xc6\x15\x0c!\xb9=\xbc\xeb\
\xcc\xe2\xb6\'4\x1cK\x03 m\xa8\xechx\x91\x12\t\xa4D\x1c)\x1eC\xf2{q\xc5#t\'\
\xcf\xe7\xce\x8d`\x9b\x06\x00\x02\x89\xde\xd0tz\x02\xcd\xc7\x84\xb8i\x18\x1c\
\xe8\xfe+\x9b7l\x12\x87\x01^x\xbe[$\xb6nAih`9\x08K\x80\xc7K\x8b\xab\x80=>\
\x88\xa3eq\xf4,\xaa\x18\'\x10\x0bL\x00\xf8\xfdH>/\xf8}\x00\xa4j\x038\x954N\
\xa3\x84c\x14q\xac\x1a\xe1\xea\x18Q\xbd0%\xcf\x8c\xf5\xeeg\xfc\xdd\x0f\x8e\
\xe4\x01W\xb1D =\x88p\t$\x1b\xb0\x04X\x82\xe5\x89Q\xfeU\xf8\x80>#\x82\xaah\\\
\xb8\xc8\xcbi\x0b\xe7A~t\xca\xa2]\xe3\x1f\xb0o\x8f\xc5\xfb\xb1ET]n|\xc5^\xbe\
}\xe0\rf:\x16\xd5/\x8dm8.\xd2\xdb\xdef\xf3\xe6\x17\x85\x1b@\x1d\x1cB\xaeV\
\xc0\xe7A\x98\x0e\x92)\x106\xb4\xc8&\xeb\x97\n\x86|\x02Ob&\xb1\x96\x18~\xe1\
\xe0L\x91\x87\x80S\xe7\xb7\xe9\x978\xb0\xe7y\n.\x19\xc7\xd6\xf186\xe3\xc7\
\x19\x8b\xec\xe1`\xdf\x10\x1d\xe9\xf4\x84\x05\x94\\\x0e\xc9\xb4@U\xc0\x14\
\xe0\x00\x15\x1d\x112p\xe9\x1a\xed\x01?\x92\xab\x01\xb9Q\x1c@\xe4r\x08MC\xe8\
\x06h\xfa1k\'\xed\x06A[PEP9\x9e\xf8$\x80a\xb9idr\x93\x00c#XB \x8f\x1b\xa0\
\xd6\xb1\xc7J\xb8$\x15\xf2\x05\x84\xcf;1I\xd3\x0e\xcf\x17\x9a\x86\xc8\xe5\
\x11\xf9\x02B3p\xf2%\x84^\x07\xbd\x8e\x85\xc0\x02\xcc\xc9n\x1fG\x1c\xd9\x83-\
\xfb1\xb2\xa5\xc90\xac\x94\xb1\xea6\xaai\xc1\xd88R\x8bLv\xd8M\x8bW\xc7\x19\
\x1eA\xd2\x8d\t\x87;\x04\xa0\x1b\x88|a"\x0f\xe4K\xa0\x19\x88B\x05\xa17\xb0\
\x01\x0b\x81\x89\x00\xc0\xc1M\x81\x16`\x18\x1b0\xd50\xb6\xac`\xca^*\xe9\xe2\
\x04\x80\xddp\xb0\x1c\x81\xd1\xb0\xf1Z\x06\xaf\x0e\\\xc0j\xee\xe4\xba\xec\
\x0b\\\xb7\xe8\x8d\t\xa1Io\x9f\xb0\x86\x8e\xd0\x0cD\xbe4\xd1\x0b\x15\xd0\xeb\
\x18\x08L\xc0\x9a\xdc\xb9\x8e`\xb5\xfbe\xf4x\x8a\xc5c\xf7\x92P\xdf\xc4\x94=\
\xd8j\x18I\xf6#$e\x02\xa0\xde\x9c\xc4\xb0l\x84-\x90\xab\x06#R3\x9a\x12d}\xe1\
\n\x96|\xf6!\xf3\xdb\xb2\x90/\x1dcI\xe7\xe8\x9d\x17\xc61\xf5\x06\x06\x1c\x86\
0\x81\xb7\xb8\x9d\x9c\xa7\x13\xbf\xa8RqM\'"{\xb0\xd5\xd0\xc41\xa8\x01\x02\
\xd3&\xef\x02+\x1cA\xb7\x04.\xcb\xa1n;\x84\x19\xc3\xed3\xc9\x97\x9a\xb9\xd3z\
\x88K3/qk\xcbjd\xe9\xc8\x89\n\xbd~x\xe7\xa6\xde\xa0>y\xf6:0F\x0bkx\x88\x81\
\xe07\xa9\xd5\x82$[FH\x16\xdf\xc5RC\xd8\xb2\x8a\xa34!\x84\x89\xaf9<\t0k\x06\
\x86\xac ;:\x02X\xc0[\xb8\x95\xbb\xf1x\x0cf\xcd\xfa\x82\x97\xd3\x97\xb0\xe5\
\xe02f\xd4\x078\xd1\xda\xc5\x12e;\x91\xc6(\xed\xf5\x0cu\x04=\x9c\xc4\x10\x1d\
\xec\xe1lz\xbdgR\xf2\xa4@\x92\x08\xfbJ4\x85\x8b\xa8\x8a\x8e\xdb\x93\xc7\x90C\
8J\x13\xa6\xec!\xe0\xb1\xf1\xb7\xa7&\x00\xc4\xcc\x14F \x84S\xaa\xd1\x00b|N\
\xdc\x9f\xa5\xaa\x86\x98?g\x1fw\xff\xf8\x01^\xddv9;\xfe}&\xaf\x16\xaf\xe2U\
\xae\xc6\x96\xdc\xb8\x03\r\x00l[\xc1%\xdbH.\x87d\xf3(\xdf=g\r\x0b;w\xf2\xc4\
\x9a\x9f`\xd4\xbd\xa4\xa4\xedXj\x88\x86\x1a\xc2V\xc3\x085\xc4\xf4y\x01V\xdc\
\xbaJr\x03\\u\xcbM\xd2\xa6s\x96\nkh\x04\x81\x04\xd8,\x93\x9ed\x9dq\x1f\xdb\
\xdf?\x0f\x10\xdc\xf6\xc3?r\xfb\xcd\x8fQ,\xc6)\x14\x13\x0c\x0e\xb7c\x9a\n\
\x00\x01\x7f\x8d\xb6\x19\x03\x84\x82\xe3$\xe2YF3\xd3x\xf8O\xf71^\t\xa2*\x16\
\xb1\xe2\x0645\x8c\xa3\x84\xb1d\x0f\x8a\xc7\xcf\x8c\xf3N\x86\xb7\x8f\xba\r]\
\x97]\x8c\xf1\xe1\'\x98\xb9<&p\xca\x81\xa7\xd9\x92\\\x05\xaa\xcc\xaeOO\xe3W\
\xf7?\xcc\xcd\xd7=\xce\x89\x0bv3}Z\x9a\x93O\xdc9%\xbf\xd4\xb4\x00o\xfc\xf3"\
\x9e\xd9\xb8\x8aHS\x89\xf1j\x84\x94\xb4\x85\xba\x00\xc7\xe5\xc1T\xc38j\x88T\
\xab\x9b\xd8\xe29\xc0\x97^\xc5\xeb/\xbdF\xe8\xeb\x9eCq@\x06*t\xf0Lj-\x86\xe3\
\'\x16)ppl:\x1d\xed\xfb\xb9\xec\xe2\xcd\xcc\x99\xddK"\x9e\x01 \x93M\xb2c\xd7\
\x19\xbc\xfe\xe6\xc5\x0c\xa5\xdb\xe9h\xefc\xff\xc0\\Z\x03\xbd\xcc5~\x8d\xa3z\
h\xa8a\x1a\xbe\x042\x06\xe7\xafZ\xc2-\xf7\xffr\xea\x9bP]~9\xc6\xde\x1e\xf4\
\x8fw\xe2\x06\xfc\xf4\xb3"\xdd\xc5\xdf\xda\xffL\xdf\xd0\xa9\x9c\xbap\x07~\
\x9f\xc6\xd3\x1b~D\xb9\xdaD"\x9a\x03\xa0<\x1e\xa1)\\\xa2m\xc6\x00\xa6\xa5\
\xb0\xff\x8by\xcc\x0e\xbd\xcet\xfd\xf1\xc3\xe2\x96\x1aB\x92\x15\xe6w*DN\xeb<\
\xac9\xa5.x\xeew\x8f\x88\xdco\x1e\xc4\x1c\x1dC\x99$4\xf1\xf1R`5\xe3\xb1N*\
\xb5&Z\x9b\xc7hI\x1c\xa4m\xe6 \x00C\x07N\xe0\xf3\xc1\xd9\xd4\xf4 !_\x89P\xf1\
\x1ft\xf8\xd7b*\xe1\xc3\xe2\x96\x1a\xa0-^\xe7\xac{\xaf\xa4\xeb\xdak\xa4\xaf\
\x04\x00Xw\xc7/\xc4\xe8\xea\xa7h\x8ceP\x8e\xfa\xdf \xc0`\xe2Z\x06\x03\xdfc\
\xac:\x1b\x07\x19\x00\xb7\xabA\xab\xaf\x87&\xed-\xe2\xce\xdb4\xd4 \x8e\xeb\
\xc8\xce-\x97\xcc\xccf\x87\xd3\xef\xb8\x8c\x95\xb7\xdcpL]\xf0\x95\x95\xd1\
\xc6\x07\x7f/F\xff\xf2$\xa5O\xf7"\xec)W\n0\x91n\x1bj\x08K\xf6`\xa9!L\xd9CC\
\x9d\x8cu5\x8c\xa5\x06q\x99e\xe6\xceS\xe9\xbc\xe5\nV\xac\xbaqJu\xf4\x95\x00\
\x00\xcf\xaf]\'\xc6_\xdb\xc6\xe8+[)\x1d8\x80\xe3\x1c\x05"Ox\xb59\x99^\x0fe8[\
\x9d\x085YQ\x88\x055\xe6_0\x9f\x96\xa5\xe7q\xf5\xf2\xab\x8f[\x9a}-\xc0\xa1\
\xb6\xe9\xa95\xa2\xb4\xf5\r2\xdb\xdf\xa7:\x96\xa3VkP\xb7\x04\xb6\xdb\x87\xad\
\x04AV\x10J\x08\xb7\xea\xc2\xe7s\x13\x9b\x91$\xf5\xadE\xc4\x96,8\xe6\xbc\xff\
g\x80Cm\xf3\xe6\x17\x85S.S\x1f\x1a\xa6\xba\xef3L}"\x13:\xc2A\x89F\x89\x9e~\n\
J<N\xd7\xf5+\xbfV\xf4\xe8\xf6\x1f\xef}\x9b\xb7\xd0cu}\x00\x00\x00\x00IEND\
\xaeB`\x82'
smile48_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x000\x00\x00\x000\x08\x06\x00\
\x00\x00W\x02\xf9\x87\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x0c4IDATx\x9c\xed\x99{\x8c]\xc5}\xc7?3\xe7}\xef=\xf7\xe1\xbb\xde\x97\xd7\
\xbb`{\xc1\x0b\xb10\xc6(\x01\xb2n\xa9 Ai"\x82[\x05E$\xfc\x83\x10Hi\xa5(j\xd4\
H\x95\x9a\xaa\xad\x10i\xffI\x9b\xaaJj(\x15(~cC\xc2#H\x01c\x8ay8\xc5\xbb\xe0\
\xf7zm\xaf\xd7\xbb\xeb}\xde\xdd\xfb\xbe\xf7\xbc\xa6\x7f\xec\x82\x85H\xbb\xbb\
\xbe+\xa1J\x1di\xa4\xa393\xe7\xf7\xfd\x9e\xdfc~3?\x91N\xa7\xf9\xbf\xdc\xe4\
\xe7\r\xa0\xd1\xf6\xff\x04>\xef\xa6\xaf\xf4\x07\xf7\xefyF\xd5\xf2g\xa9\x15\
\x06\x11\xc1,Am\x14+\xd1\x81\xe1\xac\xc1L\xde\x88\x11\xdf\xc07\xb7\x7fK\xac\
\x94<\xb1RN|\xe0\xf9\xdd*w\xf9u.\x9d\xd8CX\x1b\'a{\xd8\x16d\xdc\x85\tJ \x8d\
\x18V\xeafd\xf6~\xcc\xf4\xed+BdE\x08\x1cx~\xb7:q\xf8o\x99\xbc\xfc;\x1c\xd3\'\
\xe3\xce\x03O\xbb\xe0X`\x9bW\xe7\xd6<\xa8\xf96\xa1\xfb\x87\xc4\xaf\xffA\xc3$\
V\xc4\x84.\x1d\x7f\x8eK\x83G\x89Y\xc1\'\xe0\xdb\x9a\xe6\x81g\xdc\xcf\x12\x98\
-\xd6\xa8\xd5\xdf\xc0\x9f\xd9\xd4\xb0\xec\x86\x9dx\xc7?\x7f_\xf5\xbd\xf7\x02\
\x9a\x9c\x07o[\xf3\x7f\xde6\xa1-\x0b\xd9\x14\xc4\x9d\xab=\x9b\x9a\x1f\xb7\r\
\x0fr\x078\xb0\xe7\x17\xeas%p\xee\xc3\x17\xf1je,\xe3\xea\x1fw\x16l?\xee\xfc\
\xfe5qg\xfe\xbd\xee_ *\x1emH~C\x04\xf6\xef}VM\x8c_\xfe\xcc\xb8m~\xdal~_\xb3M\
p,EX9\xd7\x08\x84\xc6\x08\xa8(\xc4\xf3\xfc\x86\x00(\x7f\xb6\xa1\xf5\r\x11\
\x98\x9d:G>_n\x08@!7\xc4\xf3\xfb~y\xcd~\xd0P\x14:=0N\xad\x1ea\xe8P\xaeA\xbe\
\x0cRB\xa9\n\xd3ypcW\xe7\xda\xb6\x8dm\xdb\xe8\x9aF\x10\x86\x9c\x1f\xf18>Pa\
\xf0\xca4_i\x99\xbcf\x0c\xd7L\xe0\xc5\xfd\xff\xa1\x9e\xfe\xc5\xbfp\xe0p\x04\
\x80e\x82\xa1\xfd\xcf\xf3{z\xae\xa7\xb7\xb7\x97m\x7f\xb0\x8d\xb7\xdey\x8bCo\
\xbeM\xdf\x87\xa7\xd0\xb4:\xb7\xf6\x9e\xe4\xd7/\xeeR\xdf\xb8\xff\xdb\xcb\xde\
\x13\xae\xc9\x84\x9e\xfd\xa7\xef\xaa\x96\xdaO\xd9\xbc\xee\x12=\xeb\xe2$b:\
\x86\xa1\x834P\x18\x94\xaa|\xa6W\xea\x92\xd1\xf1<o\x1cz\x97\x89\xa9<\x9af\
\x90LX|q\xf3\x1a6\xb6\x0e\xb3V\x7f\x81}O\xff\xd9\xb2Mi\xd9\x1ax\xf6\xa9\x7fW\
\xa3\xa7\xf7\xf0\x9fo\x0c\xd2\xda$x\xf8\x8f\x93\x94k\x82\xe6&\x87d\xc2! \xc6\
\xe8T\x80mY\x98\x96\x85\x94&R\xea(i\x92J%X\xdf\xa1\x90!\xe4\xf3-\xcc\xe4\x12\
\xe8\x94\x19\x1e\xec\xe7\xc3~\x8d\xd6u\xbd\xcb\x85\xb3<\x02;\x9f{Ni~\xc8\x8d\
\x9b\xbfKP\xedd\xf0\xa3~\x08s\xe8\xa2\xce\xc8\xa8B7\x02\x1cw\x06KJt\xbd\x82\
\xd0\x04RJ4MC\x97\x82`f\x88\x81s\x1a\xb99\x9b \x84z\x18Q*8\xf85\x87P\x18l\
\xb8\xe5\x0e`\xef\xb2\x08,9\x17\xda\xb7w\xaf\xcaOL\xb2*\xbd\x8a\xd3\xc7\x8eq\
\xea\xdd\xf7@\x85\x84\xf5*A\xad\x8a\n|\xd2\xe9$J)\x04\x1aa\xf4\xf1J\tRC\n\
\x81\xd4@\x13\x12t\x89\x10\x82H\x80PP+\x97)\xe5\x8b(\xdbf\xfb\x0f\xbe\xcfw\
\x1eyd\xc9\xbe\xb0d\x1f\x98\x19\x1f\'\x1eO0|\xfe"}\xef\xbcK\x14}\x82\x10!%\
\xba\xae\xa3\xe9:\x86i"u\x1d\xa9ih\x0bc\x9a\xbe\xf0\xaci\xc8\x85\xae-\xbc\
\x97\x9aF\xdcu1-\x93\xcaL\x8eC{\xf7\xf1\xc2\xc1\x83K\xf6\x85%\x99\xd0\xb3\
\xcf<\xa3T\xbdN\xa5T\xe2\x9d\xd7\x0fQ\xcc\x17\x88[&R(\xa4RX\x96\x85!%BjD(4MC\
H1\xaf\r\xa1\x81\x94H!\xf1B\x0fG\xd7@\x93H!@\n\x84\x04\xa1\x14\xa9t\x860TL\
\x9f\xbf\xc8\xc0\xf1\xe3K\xc5\xbf4\r\x94f\xa6\x11\x08~\xfb\xf2\xcb\\\x1c8\
\x87R\n?\x0c\x18\x99\x9be \x97\xe3\\\xbe@\xce0xu`\x90\xdf\x9c9G$%\x8e\xe3\
\x10O$\xb0c\x0e\x96ms\xa5T\xe0W\'\x8eslr\x82\t\xcf\xa3\x7ft\x94\xf7/\\`\xa2P\
\x00)\x89\xbb\t\xda\xdbZ\x11Jq\xe4W\xbf^\xb2\x16\x16\xd5\xc0\xfe={Tqr\x82\
\xc2\xec\x0cC\xa7\xcf"\x80\x9a\xefs|r\x8c\xf3\xa3#x\x9e\x07\x80a\x18\xf8\xbe\
\xcf\x9d\xb7\xdf\x8eeZ\x08)A\xcc;q\xa4 \xb5*\xcb\xf8\x7f\x1d\xe5\xfc\xc8\x08\
\xba\xae\xe3\xfb>B\x08R\xae\xcb\xd6\xeen\xfeh\xe3M\x18\x9a\x8ea\x1a\xe4\xa6\
\xa68\xf2\xe6\x9bK\xc1\xbf\xb8\x06\xfcj\x05\x15\xf8L\x8e]\x01\xa50M\x93+\x95\
"g\x86.\x12\x04\x01\xb1X\x82\xf6\xf6N\x92\xc9\x0cn\xc2\xa5;\xe5\x12\x85\xc1<\
\xf8\x05[\x97R\x92\xd2u\xba;:\xb0m\x87\xa6l\x0bm\xad\x1d\x98\xa6\xc5\\\xa1\
\xc0\x91\x93\'\x99\xacV\x90RbY\x16A\xdd\xe7\xec\xb1\xbe%\x11XT\x03~\xa5\x8c\
\nCf\'\'H\xc4\xe3\x08\xa5\xd1\x1c\xe9\xdc\xb5\xf5\x0e\xe2\xc9\x0c1\xc3\xc4\
\xb4l\x94\n)\xcd\xcd\xe2\x196\xc5P\x91\xf9\xf8\x03B\x12\x112^\xf1\xf8\xd2\
\xedw\xd3{\xa7A(utM\x92\x9b\x9dfrf\n+\xac\xd1\x92J#\x95"\x16\x8b\xa3P\xcc\
\x8e\x8f\xb3c\xc7\x0e\xf5\xe8\xa3\x8f\xfe\xaf\x11iQ\x02\x91\xef\xa3K\x81\xa5\
i\xb8\x89\x04U?\xc2p\xb2\xac5tz\xd6v\xa1\x87ut)\x90*\xc2\xbc\xa1\x9b\x81\x91\
\x11N\x8f\\fu\xa9\xc2\xe0\xe8%R\xf1\x04\xa9\xd5\x1d\xac\xbd~#=\x9d\x9d8""\
\xf0\xabH)\t\xda\xb3\xcc\xd5\xd630:\xc6D\xbdF\x97\xa3\x93t\x13h\xa6I\x04\x0c\
\r\r-\xaa\x81\xc5\x9d8\x08\x88\x82\x00\xbfRf$_`Z\t\x0c)\xd9\xb4~#\xa1W\xa5^)\
P\xc9O\x13\xd6\xab\xe0\xd7\xd9r\xd3\x17\xb8\xed\xe6[\x98\xae\xd7\x19\x99\x99\
f\xacP\xa0s\xfdM\xdcy\xcbVb\xa6N\xe8W\x89\xc2:^%O\xe0UH\xdb\x06[\xbao`\xba\
\x1epdd\x9c\xa9j\x15\xcb4\x91J\xe1\xd5j\x8d\x13\x88\xc2\x90Z\xb5\xc2\xdc\\\
\x8e\xa0^\xe5\xe2\xa5A6\xae\xef\x99\x0f\x83JQ\xafU\xf1}\x8fz\xbdB\x18\x05DQ\
\x84\x1bO20t\x91G\xbe\xfe\x15\xdc\x98\xc5\xf1\x93\x1f0W\xcc\xcf\xef\x13\x86\
\x85&@j\x12\x15\x85h\x9a$\x93L\xd2\xde\xdcFan\x1a\xd7q\xf0\xc3\x10/\x08>\xb5\
\xd7\\3\x01?\x8c\xa8\xd7j8v\x8c\x94&\x88\xbc:\x02\x85\x14\xf3\xf1[\xd7-\x14\
\x02\xa5\xe9\xd4\xbd\x80\xc1\x8b\x83\xec\xd8\xf5o\xacJX|\xe7\xeb\xf7\xf2\xbd\
\x07\xefg\xf8\xf2\x00O\xef\xfcW\xaa\xb5\n\x9a\xa1a;1\x0c\xcb\xc4t\x1c\x84\
\x9cwt\x85\xa2\xbb\xbd\x8d\x98m3[.\x11\x08\xd0\xf4\xc5\xb7\xa9E\th\x96E\xe0\
\x05\xd8\x8eC\xd6qp\r\x8d\xbe\x8f\x8eb[6\xae\x9b\xc6\x89\'HfZ\x88\xb9\xab\
\x98\xadz\xec\xf9\xcd\x8b\xdc\xb7\xf9F^z\xf2\xafX\xd7\xd5\xc9\xb7\xff\xf4\
\x9b\x1c\xfc\xc7\xbf!\xa6G\xbcz\xe8%\x94n\x10\xe9\x06\xba\xe3b\xdb\t\x9c\xb8\
K\xc9\xf3\xe8;\xfe\x01m-\xcdxB\xa1t\r\xa5\xeb\xf3\xa1\xb8Q\x02F,\x06J\xcd\
\xc7v"\xbe\xd0\xd2\xcc\x85\x0b\x03|p\xb2\x0faX\xa4\xb2m\xb8\xd9V\x8cx\x86\
\xd7\xdf=DO{\x13\x7f\xff\xf0\x9f\xd0\x94r!\xf0Q\x85<\xdd\xed-\xfc\xc3c\x0fs\
\xf4\xc3~^{\xfb0N2K<\xb5\x9ax\xa6\x99\xc8\xb0x\xff\xa3>\xdaR\x0em-\xcd\xcc\
\x14\x0bxa\x880\x8cE\xc1\xc3\x12\xa2\x90\x93L\xe2y>RH\x0c\xc3 )%[\xdb[8}\xf2\
\x18\xfd\'\xfbi\xce\xaefMK\x1b\xa3\x93cL\xccL\xd2\xeev\xa0+\x05\xb5\n\x9f\
\xdaJ\xbd\x1aQ\x14\xf1\xde\x07\xefs\xfdu\x1b0\x0c\x83\xf1\x99\x19fg\'ivmn\
\xdd\xba\x05\x84`fnv>\x1d\x89\xc7\xd0\x97`B\x8b\xce0l\x07a\x9aD*$\x1eOP*\x14\
I\xd86w\\\xd7E\xd1\xf7\x89\x00Y\xce\xb1&n3\x9eH\xf0\xf6\xd9\x0b\xfc\xc5S\xbb\
\xf8\xde7\xeee\xdd\x9aV\xaa\x9eO\xdf\xf9K\xfc\xdd\xae\x17\x11(\xb6\xf6t#j\
\xd3\x10\xeat\xad\xb2\xb9\xa3g\x0b\x9a\xd4(\x97\xcb\xcc\xe4r\x8cNN\xa2[6\xd2\
\xb2\xe9\xec\xecl\x9c\xc0\x03\xdb\xb7\x8b\xa7~\xf635~\xfe<\x86\x13C+/\x1c\
\xe2\x85 \x1d\x8b\xa1\x1b\x06\xbaa\xa0\xe9:\xa5 `*_\xe0\x95c\'x\xa5\xef\x14m\
\x99$\xd5\xba\xc7\x95\xb9"\xa6\xaeQ\x0b\x15]\x9d\x9dt\xb4\xb6b\xda\x16\xb6ec\
\xd9\x16\xbe\x1f\xe0\xf9>G\xfb\xfa(U\xabd\xd7\xac\xa5\xb3\xb3\x93\xc7\x1e{l\
\xd1\xb4zI\xd9hv\xcd\x1a\xccl\x96\xd9\xa9I\x84n@\x14"\xa4\xbc\xda\x17r\x9e\
\xee\xd6V&K\xdd\xbc\x7f\xe2\x04\xba\x80\\\xa9\x8c@\xa0P(-\xc6\x83\xf7\xdd\
\xcb\xf5m\xad(\x14\x9eWG\xd3t,a#\xa4\xe0\xf4\xc0Y\x06\x87/\xe3\xc4\xe3\x98n\
\x82\xeb\xae\xbbn)\xd0\x96~\xa0yf\xc7\x0eux\xdf^\xaaS\xd3\x18BbY\xe6\xfcIkA\
\x03\x1fk\xc1\x0fC\x86\xa6\xa6\x98,\x95\x98+\x97I\xc4b\xb465\xd1\xd5\xdcD{\
\xf3jL\xd3@\x01a\x14\xe28q\xdc\x94\xcb\xc8\xe5\xcb\xec\x7f\xe9U\xca\xf5:M\
\x1dkY\xb7\xb1\x87\x9d;w.\xe9P\xb3\xac\xdb\xe9\x9f\xfe\xe4\'\xea\xd0\x9e\xdd\
\xa8r\x95t2\x89m\x99\xf3\xe0u\x1d\xdd41\x0c\x830\x8a\x08\x95B\xd3u,\xcb\xc24\
M\x0c\xcbBHP(L\xcb$\x8a"\xbc\xc0\xc7\xb2\x1dj\xb5*\x87\xdf?\xca\xe5+\xe3\xa4\
V\xb7`\xa53<\xf4\xd0C<\xfe\xf8\xe3K"\xb0\xac3q\xd7\r7p\xeb=\xf7p\xec\xb7\xaf\
3\x91\x9b!f\x98\xb8\xaeK<\x11Gj\x1a\xb50D3\x0c\xcc\x05\x8d\x08!\x88\x94\xc2\
\xab\xd7\x91\xba$\x0c|\x84\x8a0-\x13\x82\x90\xbe\xbe~>\x1c8\x8b\x1fF\xacji\
\xc5H\xa7\xe9\xed\xed]2x\xb8\x86\xfa\xc0\xc1\x03\x07\xd4\xe0\xa9S\xbc\xf9\
\xc2\x0b\x14FGqL\x93\xe6\xa6&\xd2\xe9\x0cB\x93W\xcdI\xd3\xd0\x16HH)\x91R\x00\
\x11(\xc5L.G\xff\x993\x8c\xcf\xcd\xa1\x9b&\xa9\xd66\x0c7\xc9]w}\x99\'\x9f|rY\
wC\xd7\\\xe0\xd8\xf1\xf3\x9f\xab\xc3\x07\x0f2|\xea\x14\xa6\xd4\x16\xec? \x99\
L\x92M\xa7q\x1c\x07\xc30PBP\xad\xd5\xa8T\xca\xe4\xf3s\\\xc9\xcdP*\x14\t4\r7\
\x9d\xc6iiEZ6\xbd\xbd\xbd<\xf1\xc4\x13\xcb\xbe\xd8j\xa8B\xf3\xfc\xfe\xfdjx\
\xe0\x1c\xaf\xec\xdc\x89\x0c|.\x0c\x0e2\xedy\xb4$\x93$]\x17MJ\xbc \xa0\xe6yx\
\xbe\x87\xeb8\x9c\x19\x1d\xe3\xb6u\xeb\x18\x1e\x1e&\xb3i\x137\xddr\x0b\xdb\
\xb6m[\x96\xd9\xac\x18\x81\x8f\xdb=\xb7\xdd\xa6:\xae\\\xe1G\x99\x0c\x87-\x8b\
]\xc5"\xd3\xc3\xc3T,\x8b \x08\xd04\x8dD\xb9\xcc\xb6\xaf}\x8d\xf5o\xbd\xc5\
\xed\xad\xad<44\xc4\xcdw\xdd\xc5\xab\x87\x0e5TbZ\x912\xab\x93JQT\x8a\xec\xd0\
\x10\xdf\x12\x82\xbfv]\xc6\xcbe\xb4L\x06\'\x95\xc27M\x92\x1b6\xf0h\xb1\xc8\
\xc3--\xac\x8a\xc7\t\x95b\xd3\x96-\r\xcb^\x91\x1a\xd9\x8d\x9b61\xecy\xd4\x86\
\x86\x90A@\xe2\xd2%\xc2Z\r16\xc6\xadMM\xbc^(\x90\xae\xd7\xf1\x84\xa0R.3U\xab\
\x91jo\xa7\xad\xa3\xa3a\xd9+\xa2\x81\xb6\xceN\xc6fg\x99\xeb\xea"\xd6\xd6F{S\
\x13\xc9\xd5\xab\x19*\x958\x92\xcb\xa1\x0c\x83T"\xc1\x86X\x8cX{;\x17\x85\xa0\
\\,\x92\xcdf\x1b\x96\xbdb\x85\xee\xcbccT\xebu\x82J\x85\x1f\x9d?\xcfd\x18\xf2\
\xe7?\xfc!\xed]]\xfc\xee\x8d78\xd6\xd7\xc7\x91\xe1a\xbe\xb4y3^\xb1H87\xb7\
\xa4ls\xb1\xb6"\x04b\xb1\x181\xc7\xe1e\xc3`(\x97\xe3\xadL\x86\x07\xbf\xfaU\
\xbe|\xf7\xdd<\xf0\xc0\x03b\xf7\xee\xdd\xaaX(\xf0\xf0\xe1\xc3<25\xc5P\x14\
\xd1\x12\x8baYV\xc3\xb2W$\n\x1d<xP\xbd\xf7\xdak\x9c9s\x06]\x08\xbex\xcf=l\
\xe8\xe9a\xfb\xf6\xed\x9fD\x98}\xfb\xf6\xa9\x93\xfd\xfd\xbc\xf9\xca+\xd8\xb6\
\xcd\xdd\xf7\xdd\xc7_\xfe\xf8\xc7\rW\xea\xff\x1b\xd5\xe8\x0b\x01\xe7z\x82m\
\x00\x00\x00\x00IEND\xaeB`\x82'
up_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\
\x03IDATx\x9c\xc5\xd7\xcdo\xdbd\x1c\xc0\xf1\xaf\x1d\xbb1v\xd2\xae\xac\x1b\
\xd36\x10\x1b &!\x90V4\x06H\x1c&n\x08\xf1\x0f \xe0\xca\x15\x0e\xfb/8#.\x88\
\x0bB\\&M\x88\x0b\x87ich\x0c!\x0e\x83\xb2\xc2\xd6\xb1\xf5}I\xd3.m\x12\xe7\
\xf1\xe3\xe7\x85\x83\x9b\xbe\x904q\xb2\x03\xa7\xc4y\xfc\xf8c\xe7y~/v\xbe\x9b\
m\xd9WO\x86$\x1a\xda\n\xa4\x86D\x834\x90l\x1fK\x93\xfd\x16\xa7\x90n\x8fw\xce\
\xe9\x1c\x0b\x95\x8dw\xc6\x84\xde\xbe\x96\xca\xbew\xe6w\xce\xed8\xae\xb1\xf6\
\x7f\xc3\xb3\x1b0\x8f\x87ol\xc5\xfc}\xef\xc1H8Z\xe2Jm\x1f\xeb\xc9\xff\x98\
\xf9\x93\x9b?\\\xa2)\xe4\xd08*\xc15vt\xbc)4\xf7f~\xa3\xb1\xb6\xcc\xd2\xf2\
\xca\xd0\xb8U\t\xae6\xa3\xaf\xf9j\xb5F\xbd\xb2\x80q\n,\xcc\xfd54\x8e\x8c\xb7\
7\xe1\x88\x1bn\xee\xce,Jk\x9c\xb1\x88\xfa\xda*\xf5Fk(\x1c-q\x95\x19\r\xdfj\t\
V\xfe\xb9\x8d\xe3\x87\x10\x8c#\x95fm\xad:\x14n\xb3=`G\n\xb5\xc5\xa5E\xda\x8d\
:\x04\xe3P,\xe3\x04\xe3<\xaao"R\x93\x1bG%\xb8\xca\x8e\x10\xe7\xca\xb207\x8b\
\xf5\x9e\xd8\xc1\x9dh\n\xa9\x0c\x8dv\x92\x1bG\xcb,\x0f\x0c\x9bd66\x1b4\x1e\
\xad\xef\xc3)\x96\xb1~H[\xc8\xdc8*\xc1K\x8d\xc5\x1b\x02\x97\x1aV\x96\x16\x91\
J\xef\xc3\x9d\xa0\x0c\xc18\n\x0f\x9b\x13G%\xb8\xd6\x0c\x87\xc7BQ]Y\xe8\x89;\
\xc52v,\xc2C\xe5\xc2\xad\x96\xb8j\xbb\x16\xe4\xcd\xed\xd5Z\r!DO\x9cb\x99\xc8\
\x87\xc8w@\xc9\x8182\xdeMDy\x0bKm\xad\x82-N\x1c\x88\x87>L\x85.\x91\xa7\x07\
\xe2\xa8\x04W\xdb\xfcx#\x164c\xd1\x17?T\x84R\xd1a\xaa\\\x1c\x88\xef\xe4\x81\
\xbc%u}c\x93\xd4\x16\xfa\xe2\xa1\x0f\x91\x0f\xc7\'C\x82\x82\xed\x8b\xa3e\xb6\
\x04y\xf0\x964l5\xb6p\x8a\xa5\x81x\xe8\xc1\x91\xb2\xc7\xb1\'\xcb}\xf1l\t\x8c\
\xcd\xd5L4[\x02\xa9\xc9\x85G>\x94|\x87\x17OLR\xb0\xea@\x1c\x95\xe0\xeeM@\xfd\
\xeay3nc\xc7\xa2\\xg\xec\xf4\xd1\x88\xa3\x93\xa5\x03\xf1\x9d\x7f`\x10\xdeN4"\
5C\xe1\x91\x0f\xc7J\x05\xa6_8q n\xb5\xcc\xa2`P\'\x13\')\xc6\x0b\x86\xc2\x0f\
\x15\xb3\xcf\xe9\xd3SLDAO\x1c\x19\xe3*c\x07w2\x86\xbex\xe8\xdb\x9ex\xe4\xc3\
\xa9\xc3E^9s\xaa\'\xbe\xdb\x92\xf5\xc1\x852\x98B\xd0\x13\x1fs\x0c\x0fk\x1b\
\xcc\xcc-\xd1l\xc5]x\xe8\xc3D\xd1\xe1\xed\xb3\xcf\xe1;\xa6;\x1at\x82\xa7\x8c\
\xed\xdbFI\xe3v\xe1\xa1\x07B\xb4\xb9\xbb\xfc\x90j\xb5\x8aM\x05\xab\x8b\xf3\
\x9c=\xf3\x0c\x17^:N\x14z\x84>\x94\xb6\xe7\xbdvj\x82\xe7\x9f}\x9a\xdb3\xb7\
\xf6\xe1Y?`\x0e\xc6\x13\rA\xc1\xee\xc3}4+\x95\x1a\xb7n\xdf\xa5R\xa9`S\x01*\
\xa1\xd9\xa8\xf3\xd3\x8d\x9b|y\xf9*\xbf?\xa8\xe1\xbbv\xcffty\xef\xc2\xb9.\
\x1c\xb5\xa7\x1f\xe8\x85\x17\xac\xa24\x96\xe1A\xc1\xd2n\xb5\x98\xbd\xb7\xc0\
\xfd\xf9\x05R\x11w\xad\xa9M\x13\x16\xe7\x1f\xf0\xc5\xd7\x97\xf8\xfc\xf2/\xac\
\xd6Ev\xf3\x01\xbc;}\x92\xa7\x8e\x1c\xde\x87gy\xc0\xd8\x9e8Z\x12z\x96\xc9\
\xc0\xc15)\xcb\x955\xee\xdc\x9f\xa7\xb1\xf9h`zU\xa2\xc5\xb5kW\xb9\xf8\xd9W|{\
\xe3>\xad\xc4\xf0\xf21\x9f\x0bo\xbd\xb9\x0fG\'8\xef\x7fS\xb1?\xd6\x8fv\xe1\
\x05#9>\x19\xa0D\x9b\xda\xfa\x06I\xbb9\xb0\xb0\xf4\n5\'\x15\x9c?7\xcd\xa7\
\x1f\xbc\x83\xd6\x86\x0f?\xfe\x04\xd9\xda\x04\x9d\xcd\xf1\xb4\xb5={8l\xcaz-&\
nma\xd2\xc1U\xed\xa08\xb7*\xe1\xe7\xebW\xf8\xe8\xd7\xeb\xbc~\xfe\r|\x17\xa4\
\xdemV<m\xbaq\xab\x12\x94\x8cQ9\xeay?|\xef\x86\x8b\xeb\r\xae|\x7fi\xe7\xc9w\
\xdf\x0bl\xfe\x06rT|\xef\x9a\xff\xf7\xfa\xff\x02\x1b\x95\x05yYu\xd8\x0c\x00\
\x00\x00\x00IEND\xaeB`\x82'
tick_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x03\
\x02IDATx\x9c\xe5\x97?HzQ\x14\xc7\xbf\xf7\xf6\x93\x1e\x0f\xc4G\x7f\x96\x86\
\x04\xdb\x0b\x1c\x9a\xda\x83\x94H\xa1(!\x90\x8c\x0c\x87 r\x89p\n\xc1\xc9%\
\x08\x8apI4\xa8\x1e\x91$\xe5\xd0\xd4\x14\x15A A\x04\r.\x12TC\x96\x10t~\x93\
\xef\xa7\xe9\xf5O\xbfg\x0e\x1d\xb8\xf0x\xf7\x9c\xf3\xf9r\xee\xb9\xf7\xdd\xc7\
\x14EA+\x8d\xb7\x94\xde\n\x01\xc1`\x90\x86\x87\x87imm\x8d\x00\xe0\xcfO\x81#\
\x91\x08\xed\xed\xed!\x10\x08\xe0\xe9\xe9\t\x16\x8b\x05?"@UU:;;C \x10@:\x9d\
\x06\x11\x01\x00\xde\xde\xde\x9a/@UUJ$\x12\xd8\xd8\xd8\xd0\x80\x05\xbb\xbf\
\xbf\x07\xd0\xc4\x1e\xa8\x06\x07\x00I\x92\x9a\' \x16\x8b\xd1\xce\xce\x8e\x10\
>00\x00\xa7\xd3\t\xa0\tK\x10\x8b\xc5hss\x13\x87\x87\x87\xf8\xfc\xfc,\x9b\xef\
\xe9\xe9\xc1\xfc\xfc<|>\x1f\x03jT`\x7f\x7f\x9f\xf4\x86\xfb\xfd~,//\xb3\xc2;\
\xf6\xf5$TU\x95nnn\x90J\xa5`0\x18055\x05\xaf\xd7\xcb\xca\xb25\x087\x1a\x8dXY\
YA(\x14*\xcd\xa5(\x8a6\x92\xc9$\xb9\\.2\x1a\x8d\x04\x80\x00\xd0\xd0\xd0\x10\
\xa5R)*\xf6\xfb:\x92\xc9$\x8d\x8d\x8d\x11\xe7\\\x8b+\x1e\xb2,\xd3\xe2\xe2"\
\x9d\x9e\x9e\x96\xe5\xd1\x1e\x8e\x8f\x8f+&\xe9\xea\xea\xa2x<.\x14P\x0b.I\x92\
\x10\xae(\xca\xbf\x1e\xb8\xbc\xbc\xc4\xd1\xd1QY\xf9^__\xf1\xfc\xfc\\\xb1\xec\
\xaa\xaa\xd2\xc1\xc1\x81\xb0\xec\x9cs\xd8l6\x8c\x8c\x8c\xc0\xe9tV\\FM\xc0\
\xc5\xc5\x05>>>\xca\x1c\xf2\xf9<\x1e\x1e\x1e*\xc2\x13\x89\x04\xa2\xd1\xa8\
\x10>::\n\x8f\xc7\x83\xf1\xf1qa\x0fi\x02\xf2\xf9\xbc\xc8\x07www\x15\xe1\xa2}\
\xce\x18\x83\xddn\xc7\xdc\xdc\x1c\\.W\xd5\x06\xae\xeb \xcaf\xb3\xda\x96\xdc\
\xde\xde\xa6\xad\xad-!\x1c\x00\xacV+\xdcnwM8P\xe7A\x94N\xa7\xd9\xf5\xf55\x85\
\xc3a\n\x06\x838??\xafX\xf6\x02|ii\t3335\xe1u\x0bxyy\xa1P(\x04\xce9\xb2\xd9\
\xac\xd0\xcfj\xb5\xc2\xef\xf7k\xa7\x9cn\x02\x00\xe0\xf1\xf1Q8\xc79\xc7\xe0\
\xe0 \x16\x16\x16\x1a\x82\x97\x08hkkk$\xae\x04^\xe8\xf6\xe9\xe9\xe9\x86\xe0%\
\x02\xfa\xfa\xfa\xbe\r\xaf\xa7\xdb\x859\n\x0f&\x93\t\x8c\xd5\x9fC\x0fx\x89\
\x00\xb3\xd9\x0cY\x96\xeb\n2\x18\x0c\xba\xc0\x81\xa2%\xe8\xee\xeeFgg\'r\xb9\
\\\xd5\x00Y\x96\xe1\xf1x`\xb3\xd9099\xf9_p\xa0\xa8\x02\x92$\xa1\xb7\xb7\xb7&\
\xdc\xeb\xf5\xc2\xe1p\xe8\x02\x07\x8a*011\xc1\xd6\xd7\xd7\xe9\xfd\xfd\x1dWWW\
\xda\xed\xb5`\x1d\x1d\x1dp\xbb\xdd\xb0\xdb\xed\xc2\x0f\xcbw\xac\xecB\x12\x89\
D(\x1a\x8d\xe2\xe4\xe4\x04\xb9\\\x0e\x8c1X,\x16\xf8|>\xac\xae\xae\xea\x06\
\x16\n\x00\x80\xdd\xdd]\xba\xbd\xbdE&\x93A{{;\xfa\xfb\xfb1;;\xab;\\(\xe0\'\
\xed\xf7\xfd\x9c~\xb5\xbf\x8a\xf3q\xb2q\x86\xa0|\x00\x00\x00\x00IEND\xaeB`\
\x82'
cross_png = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x03\
\x9fIDATx\x9c\xc5\x97OH*_\x14\xc7\xbfW~\x82\x8c\x19Sh\xc2\x80\x8b\xfe\x10\
\x04A\x90P.\x84(r\x13ER\x14\x11\x18A\x11\x14\xba0\n\x83B\xa1\x90\\\x88\xa5\
\x05\xe5B\x11%7\x89\x14B\x08\xc2\xac\xda\xb6\x88V\xd12\xb0M\xb4jWx\xde\xe2a<\
_3\xe3(\xef\xf7\xde\x81\xb3P\xef9\xdf\xcf\x9d+\xdfs\x87\xf1<\x8f\x7f\x19\x9a\
\x7f\xaa\xfe7\x01\x82\xc1 \xcd\xcf\xcfS<\x1e\xa7_\xbfg\xf5\x8e \x9dNSKK\x0bf\
ffX3\xc2\xc9d\x92r\xb9\x1c\x8a\xc5"\xde\xde\xde044\x84\xbd\xbd=,--1Y\x80t:M\
\x8c1\xdc\xde\xde\xe2\xea\xea\n\x13\x13\x13\x98\x9a\x9aj\x18\xe2\xf0\xf0\x90\
\xe2\xf18\xee\xef\xefA\xf4s\xe3Z\xad\x16\xa3\xa3\xa3\xb0\xdb\xed\xb0\xdb\xed\
\x00\xcf\xf35y||L\xfd\xfd\xfd\xd4\xd3\xd3C\x1c\xc7\x11\x00\xe28\x8e\xbc^/\
\x89\xa2H\xbf\xaf\x97\xcaR\xa9D>\x9f\x8f\xccf3\x01\x90L\x8e\xe3(\x18\x0cRM\
\xe1\xc9\xc9\t\x19\x8dF\xd9\x025\x10\x85B\x81fggI\xa7\xd3\xc9\x8a\x03 \xa3\
\xd1H\x89D\xa2\x16\xe0\xe2\xe2\x82:::\x14\xa9\x95 \xb2\xd9,\xd9l6\xd2h4\x8a\
\xe2f\xb3\x99vvv\x88\xe7\xf9\xefG077\xa7Xl0\x18(\x14\n}\x038;;\xa3\x81\x81\
\x01\xc5Z\x00\xd4\xd5\xd5E\x91H\xe4\xab\xfe\x1b@*\x95\x92=\x86jZ,\x16J&\x93\
\xc4\xf3<DQ\xa4P(D\x82 (\xd6h4\x1a\xb2\xd9l\x94\xc9dj\xe0%\xcf\xb1\xdeS\x00@\
V\xab\x95\xb2\xd9,y<\x1e2\x18\x0c\x8ak\xb5Z-9\x9dN*\x14\n\xdf\x9e\x9c$@*\x95\
\xaa\xbb#\xc6\x18uvv\x92V\xabU\\\xc7q\x1cy<\x1e*\x16\x8b\x92\xff\x1bY#ZYY\
\xa1X,\x86\x8f\x8f\x0f\xc9\xdf\xd5D{{;\x96\x97\x97199)\xeb!\xb2V\xecp8~\x1aE\
\x93!\x08\x02vww\x91L&\x99\x92\x81\xc9\x02,,,0\x97\xcb\x05A\x10\x9a\x12\xdf\
\xda\xda\xc2\xc1\xc1A]\xe7T\x1cF\x9b\x9b\x9b\xcc\xe5rA\xa7\xd35,\xbe\xbf\xbf\
\xaf\xca\xb6\xebN\xc3\xf1\xf1q\x0c\x0f\x0f\xab\x12\xd7h4\x98\x9e\x9eV-\xae\n\
\xe0\xe1\xe1\x01OOO\xaa\x9aU*\x15\\__\xc3\xef\xf7S\xfd\xd5*\x00\xfc~?\x85\
\xc3a\x94\xcbe\xb5\xfdP.\x97\x11\x0e\x87\xd5C\xc8\r\x95H$R\xd7\x0b\x94R\x10\
\x84\x1a\xcb\x95\xcb\xffE\xbc\x11\x88\x9a\x0f\xa2(R \x10\xf8#\xe2j!j\xc4\xbd\
^\xef\xd7%D)M&\x13\x99L&\xd5\x10f\xb3\x99|>\x9f\xe4\x18\x07\xcf\xf3\xb8\xb9\
\xb9\xa1\xb5\xb55U\xe2\xd5\x1d\x05\x02\x01U\xeb\xab\xa9\xd7\xeb)\x16\x8bI\
\x03\xb8\xdd\xee\xba\x97\x88\xdf\x1f\xa7(\x8a\xe4\xf1x\xea\x0e\xa3j\xf6\xf6\
\xf6R.\x97\x93\x06\x88F\xa3\xa4\xd7\xeb\x15\x1b\xf4\xf5\xf5Q4\x1a\xadiP,\x16\
\xc9\xe9t*\xc23\xc6hdd\xe4\xeb\xfe \tpzzJ\xad\xad\xad\xb2M\x06\x07\x07)\x9b\
\xcdJ6\x90:>\xc6\x181\xc6\x08\x00uwwK\xee\xbc\x9a\xff\x01\xc0\xf3\xf33\xde\
\xdf\xdf!\x15\x16\x8b\x05n\xb7\x1b\x1b\x1b\x1b\x92\xf6\xba\xb8\xb8\xc8\xf2\
\xf9<\xb5\xb5\xb5!\x93\xc9\xe0\xf3\xf3\x13ccc\xd0\xe9tx}}\x85\xc3\xe1\xc0\
\xea\xea\xaa\xac5\xb3\xeae2\x91H\xa0T*\xa1R\xa9|\xc14:X\xce\xcf\xcf\x89\x88\
\xb0\xbe\xbe\xaez\x16|]H.//\xe9\xe5\xe5\x05\x8f\x8f\x8f8::\x02\x00loo#\x1a\
\x8d6\xf5F\xd40@5\xf2\xf9<\xdd\xdd\xdd\x01\x00\xacVk\xd3\xafdM\x03\xfc\xed\
\xf8\x01\xe9\t\x94\x8c\xa7\xf9\xf9<\x00\x00\x00\x00IEND\xaeB`\x82'
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

86
demo/BitmapButton.py Normal file
View File

@@ -0,0 +1,86 @@
import wx
import images
#import wx.lib.buttons
#wx.BitmapButton = wx.lib.buttons.GenBitmapButton
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1,
style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.log = log
if 0: # a test case for catching wx.PyAssertionError
#wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS)
#wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_EXCEPTION)
#wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
#wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_EXCEPTION | wx.PYAPP_ASSERT_DIALOG)
try:
bmp = wx.Bitmap("nosuchfile.bmp", wx.BITMAP_TYPE_BMP)
mask = wx.Mask(bmp, wx.BLUE)
except wx.PyAssertionError:
self.log.write("Caught wx.PyAssertionError! I will fix the problem.\n")
bmp = images.Test2.GetBitmap()
mask = wx.MaskColour(bmp, wx.BLUE)
else:
bmp = images.Test2.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b = wx.BitmapButton(self, -1, bmp, (20, 20),
(bmp.GetWidth()+10, bmp.GetHeight()+10))
b.SetToolTipString("This is a bitmap button.")
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
b = wx.BitmapButton(self, -1, bmp, (20, 120),
style = wx.NO_BORDER)
# hide a little surprise in the button...
img = images.Robin.GetImage()
# we need to make it be the same size as the primary image, so
# grab a subsection of this new image
cropped = img.GetSubImage((20, 20, bmp.GetWidth(), bmp.GetHeight()))
b.SetBitmapSelected(cropped.ConvertToBitmap())
b.SetToolTipString("This is a bitmap button with \nwx.NO_BORDER style.")
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
def OnClick(self, event):
self.log.write("Click! (%d)\n" % event.GetId())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>BitmapButton</h2>
<p>A BitmapButton control displays a bitmap. It can have a separate bitmap for each button state: normal, selected, disabled.</p>
<p>The bitmaps to be displayed should have a small number of colours, such as 16,
to avoid palette problems.</p>
<p>A bitmap can be derived from most image formats using the wx.Image class.</p>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

62
demo/BitmapComboBox.py Normal file
View File

@@ -0,0 +1,62 @@
import wx
import wx.combo
import images
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
bcb1 = wx.combo.BitmapComboBox(self, pos=(25,25), size=(200,-1))
bcb2 = wx.combo.BitmapComboBox(self, pos=(250,25), size=(200,-1))
for bcb in [bcb1, bcb2]:
for x in range(12):
name = 'LB%02d' % (x+1)
obj = getattr(images, name)
img = obj.GetImage()
img.Rescale(20,20)
bmp = img.ConvertToBitmap()
bcb.Append('images.%s' % name, bmp, name)
self.Bind(wx.EVT_COMBOBOX, self.OnCombo, bcb)
def OnCombo(self, evt):
bcb = evt.GetEventObject()
idx = evt.GetInt()
st = bcb.GetString(idx)
cd = bcb.GetClientData(idx)
self.log.write("EVT_COMBOBOX: Id %d, string '%s', clientData '%s'" % (idx, st, cd))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.combo.BitmapComboBox</center></h2>
A combobox that displays a bitmap in front of the list items. It
currently only allows using bitmaps of one size, and resizes itself so
that a bitmap can be shown next to the text field.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

148
demo/BitmapFromBuffer.py Normal file
View File

@@ -0,0 +1,148 @@
import wx
import array
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.width, self.height = 120,120
self.MakeBitmapRGB(self.width, self.height)
self.MakeBitmapRGBA(self.width, self.height)
self.MakeBitmapRGBpA(self.width, self.height)
def GetRGB(self, x, y, bpp):
# calculate some colour values for this sample based on x,y position
r = g = b = 0
if y < self.height/3: r = 255
if y >= self.height/3 and y <= 2*self.height/3: g = 255
if y > 2*self.height/3: b = 255
if bpp == 4:
a = int(x * 255.0 / self.width)
return r, g, b, a
else:
return r, g, b
def MakeBitmapRGB(self, width, height):
# Make a bitmap using an array of RGB bytes
bpp = 3 # bytes per pixel
bytes = array.array('B', [0] * width*height*bpp)
for y in xrange(height):
for x in xrange(width):
offset = y*width*bpp + x*bpp
r,g,b = self.GetRGB(x, y, bpp)
bytes[offset + 0] = r
bytes[offset + 1] = g
bytes[offset + 2] = b
self.rgbBmp = wx.BitmapFromBuffer(width, height, bytes)
def MakeBitmapRGBA(self, width, height):
# Make a bitmap using an array of RGBA bytes
bpp = 4 # bytes per pixel
bytes = array.array('B', [0] * width*height*bpp)
for y in xrange(height):
for x in xrange(width):
offset = y*width*bpp + x*bpp
r,g,b,a = self.GetRGB(x, y, bpp)
bytes[offset + 0] = r
bytes[offset + 1] = g
bytes[offset + 2] = b
bytes[offset + 3] = a
self.rgbaBmp = wx.BitmapFromBufferRGBA(width, height, bytes)
def MakeBitmapRGBpA(self, width, height):
# Make a bitmap using an array of RGB bytes plus a separate
# buffer for the alpha channel
bpp = 3 # bytes per pixel
bytes = array.array('B', [0] * width*height*bpp)
for y in xrange(height):
for x in xrange(width):
offset = y*width*bpp + x*bpp
r,g,b = self.GetRGB(x, y, bpp)
bytes[offset + 0] = r
bytes[offset + 1] = g
bytes[offset + 2] = b
# just use an alpha buffer with a constant alpha value for all
# pixels for this example, it could just as easily have
# varying alpha values like the other sample.
alpha = array.array('B', [128]*width*height)
self.rgbaBmp2 = wx.BitmapFromBuffer(width, height, bytes, alpha)
def DrawBitmapAndMessage(self, dc, bmp, msg, x_, y_):
x, y = x_, y_
# draw some text to help show the alpha
dc.SetFont(self.GetFont())
while y < y_ + self.height + 2*dc.GetCharHeight():
dc.DrawText(msg, x,y)
y += dc.GetCharHeight() + 5
# draw the bitmap over the text
dc.DrawBitmap(bmp, x+15,y_+15, True)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
self.DrawBitmapAndMessage(dc, self.rgbBmp, "No alpha channel in this image", 30,35)
self.DrawBitmapAndMessage(dc, self.rgbaBmp, "This image has some alpha", 325,35)
self.DrawBitmapAndMessage(dc, self.rgbaBmp2,"This one made with RGB+A", 180,220)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>BitmapFromBuffer</center></h2>
Two new wx.Bitmap factory functions allow you to create a wx.Bitmap
directly from a data buffer. The the buffer can be any Python object
that implements the buffer interface, or is convertable to a buffer,
such as a string or an array. The new functions are: <ul>
<li><b>wx.BitmapFromBuffer</b>(width, height, dataBuffer, alphaBuffer=None):
Creates the bitmap from a buffer of RGB bytes, optionally with a separate
buffer of alpha bytes.
<li><b>wx.BitmapFromBufferRGBA</b>(width, height, dataBuffer): Creates
the bitmap from a buffer containing RGBA bytes.
</ul>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

76
demo/Button.py Normal file
View File

@@ -0,0 +1,76 @@
import wx
import images
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1,
style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.log = log
b = wx.Button(self, 10, "Default Button", (20, 20))
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
b.SetDefault()
b.SetSize(b.GetBestSize())
b = wx.Button(self, 20, "HELLO AGAIN!", (20, 80))
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
b.SetToolTipString("This is a Hello button...")
b = wx.Button(self, 40, "Flat Button?", (20,160), style=wx.NO_BORDER)
b.SetToolTipString("This button has a style flag of wx.NO_BORDER.\n"
"On some platforms that will give it a flattened look.")
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
b = wx.Button(self, 50, "wx.Button with icon", (20, 220))
b.SetToolTipString("wx.Button can how have an icon on the left, right,\n"
"above or below the label.")
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
b.SetBitmap(images.Mondrian.Bitmap,
wx.LEFT # Left is the default, the image can be on the other sides too
#wx.RIGHT
#wx.TOP
#wx.BOTTOM
)
b.SetBitmapMargins((2,2)) # default is 4 but that seems too big to me.
# Setting the bitmap and margins changes the best size, so
# reset the initial size since we're not using a sizer in this
# example which would have taken care of this for us.
b.SetInitialSize()
#b = wx.Button(self, 60, "Multi-line\nbutton", (20, 280))
#b = wx.Button(self, 70, pos=(160, 280))
#b.SetLabel("Another\nmulti-line")
def OnClick(self, event):
self.log.write("Click! (%d)\n" % event.GetId())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>Button</h2>
A button is a control that contains a text string or a bitmap and can be
placed on nearly any kind of window.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

196
demo/Cairo.py Normal file
View File

@@ -0,0 +1,196 @@
import wx
import math
try:
import wx.lib.wxcairo
import cairo
haveCairo = True
except ImportError:
haveCairo = False
from Main import opj
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
if self.IsDoubleBuffered():
dc = wx.PaintDC(self)
else:
dc = wx.BufferedPaintDC(self)
dc.SetBackground(wx.Brush('white'))
dc.Clear()
self.Render(dc)
def Render(self, dc):
# Draw some stuff on the plain dc
sz = self.GetSize()
dc.SetPen(wx.Pen("navy", 1))
x = y = 0
while x < sz.width * 2 or y < sz.height * 2:
x += 20
y += 20
dc.DrawLine(x, 0, 0, y)
# now draw something with cairo
ctx = wx.lib.wxcairo.ContextFromDC(dc)
ctx.set_line_width(15)
ctx.move_to(125, 25)
ctx.line_to(225, 225)
ctx.rel_line_to(-200, 0)
ctx.close_path()
ctx.set_source_rgba(0, 0, 0.5, 1)
ctx.stroke()
# and something else...
ctx.arc(200, 200, 80, 0, math.pi*2)
ctx.set_source_rgba(0, 1, 1, 0.5)
ctx.fill_preserve()
ctx.set_source_rgb(1, 0.5, 0)
ctx.stroke()
# here's a gradient pattern
ptn = cairo.RadialGradient(315, 70, 25,
302, 70, 128)
ptn.add_color_stop_rgba(0, 1,1,1,1)
ptn.add_color_stop_rgba(1, 0,0,0,1)
ctx.set_source(ptn)
ctx.arc(328, 96, 75, 0, math.pi*2)
ctx.fill()
# Draw some text
face = wx.lib.wxcairo.FontFaceFromFont(
wx.FFont(10, wx.SWISS, wx.FONTFLAG_BOLD))
ctx.set_font_face(face)
ctx.set_font_size(60)
ctx.move_to(360, 180)
ctx.set_source_rgb(0, 0, 0)
ctx.show_text("Hello")
# Text as a path, with fill and stroke
ctx.move_to(400, 220)
ctx.text_path("World")
ctx.set_source_rgb(0.39, 0.07, 0.78)
ctx.fill_preserve()
ctx.set_source_rgb(0,0,0)
ctx.set_line_width(2)
ctx.stroke()
# Show iterating and modifying a (text) path
ctx.new_path()
ctx.move_to(0, 0)
ctx.set_source_rgb(0.3, 0.3, 0.3)
ctx.set_font_size(30)
text = "This path was warped..."
ctx.text_path(text)
tw, th = ctx.text_extents(text)[2:4]
self.warpPath(ctx, tw, th, 360,300)
ctx.fill()
# Drawing a bitmap. Note that we can easily load a PNG file
# into a surface, but I wanted to show how to convert from a
# wx.Bitmap here instead. This is how to do it using just cairo:
#img = cairo.ImageSurface.create_from_png(opj('bitmaps/toucan.png'))
# And this is how to convert a wx.Btmap to a cairo image
# surface. NOTE: currently on Mac there appears to be a
# problem using conversions of some types of images. They
# show up totally transparent when used. The conversion itself
# appears to be working okay, because converting back to
# wx.Bitmap or writing the image surface to a file produces
# the expected result. The other platforms are okay.
bmp = wx.Bitmap(opj('bitmaps/toucan.png'))
#bmp = wx.Bitmap(opj('bitmaps/splash.png'))
img = wx.lib.wxcairo.ImageSurfaceFromBitmap(bmp)
ctx.set_source_surface(img, 70, 230)
ctx.paint()
# this is how to convert an image surface to a wx.Bitmap
bmp2 = wx.lib.wxcairo.BitmapFromImageSurface(img)
dc.DrawBitmap(bmp2, 280, 300)
def warpPath(self, ctx, tw, th, dx, dy):
def f(x, y):
xn = x - tw/2
yn = y+ xn ** 3 / ((tw/2)**3) * 70
return xn+dx, yn+dy
path = ctx.copy_path()
ctx.new_path()
for type, points in path:
if type == cairo.PATH_MOVE_TO:
x, y = f(*points)
ctx.move_to(x, y)
elif type == cairo.PATH_LINE_TO:
x, y = f(*points)
ctx.line_to(x, y)
elif type == cairo.PATH_CURVE_TO:
x1, y1, x2, y2, x3, y3 = points
x1, y1 = f(x1, y1)
x2, y2 = f(x2, y2)
x3, y3 = f(x3, y3)
ctx.curve_to(x1, y1, x2, y2, x3, y3)
elif type == cairo.PATH_CLOSE_PATH:
ctx.close_path()
#----------------------------------------------------------------------
if not haveCairo:
from wx.lib.msgpanel import MessagePanel
def runTest(frame, nb, log):
win = MessagePanel(nb, 'This demo requires the Pycairo package,\n'
'or there is some other unmet dependency.',
'Sorry', wx.ICON_WARNING)
return win
else:
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
if haveCairo:
extra = "\n<h3>wx.lib.wxcairo</h3>\n%s" % (
wx.lib.wxcairo.__doc__.replace('\n\n', '\n<p>'))
else:
extra = '\n<p>See the docstring in the wx.lib.wxcairo module for details about installing dependencies.'
overview = """<html><body>
<h2><center>Cairo Integration</center></h2>
This sample shows how to draw on a DC using the cairo 2D graphics
library and the pycairo Python extension module that wraps the cairo
API. For more information about cairo please see
http://cairographics.org/.
%s
</body></html>
""" % extra
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

132
demo/Cairo_Snippets.py Normal file
View File

@@ -0,0 +1,132 @@
import wx
try:
import wx.lib.wxcairo
import cairo
haveCairo = True
except ImportError:
haveCairo = False
from math import pi as M_PI # used by many snippets
from snippets import snip_list, snippet_normalize
from Main import opj, DemoCodeEditor
#----------------------------------------------------------------------
# TODO: Add the ability for the user to edit and render their own snippet
class DisplayPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, style=wx.BORDER_SIMPLE)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.curr_snippet = ''
def OnPaint(self, evt):
dc = wx.PaintDC(self)
if self.curr_snippet:
width, height = self.GetClientSize()
cr = wx.lib.wxcairo.ContextFromDC(dc)
exec(self.curr_snippet, globals(), locals())
def SetSnippet(self, text):
self.curr_snippet = text
self.Refresh()
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.lb = wx.ListBox(self, choices=snip_list)
self.canvas = DisplayPanel(self)
self.editor = DemoCodeEditor(self, style=wx.BORDER_SIMPLE)
self.editor.SetEditable(False)
self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self.lb)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.lb, 0, wx.EXPAND)
sizer.Add((15,1))
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.canvas, 1, wx.EXPAND)
vbox.Add((1, 15))
vbox.Add(self.editor, 1, wx.EXPAND)
sizer.Add(vbox, 1, wx.EXPAND)
border = wx.BoxSizer()
border.Add(sizer, 1, wx.EXPAND|wx.ALL, 30)
self.SetSizer(border)
def OnListBoxSelect(self, evt):
snippet_file = opj('snippets/%s.py' % evt.GetString())
text = file(snippet_file).read()
self.canvas.SetSnippet(text)
self.editor.SetValue(text)
#----------------------------------------------------------------------
if not haveCairo:
from wx.lib.msgpanel import MessagePanel
def runTest(frame, nb, log):
win = MessagePanel(nb, 'This demo requires the Pycairo package,\n'
'or there is some other unmet dependency.',
'Sorry', wx.ICON_WARNING)
return win
else:
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
if haveCairo:
extra = "\n<h3>wx.lib.wxcairo</h3>\n%s" % (
wx.lib.wxcairo.__doc__.replace('\n\n', '\n<p>'))
else:
extra = '\n<p>See the docstring in the wx.lib.wxcairo module for details about installing dependencies.'
overview = """<html><body>
<h2><center>Cairo Integration</center></h2>
The wx.lib.wxcairo module provides a bit of glue that will allow you to
use the Pycairo package drawing directly on wx.DC's.
<p> This sample draws the standard 'snippet' examples that come with
the Pycairo pacakge, and a few others. The C version of the samples
can be seen at http://cairographics.org/samples/
<p> In most snippets you'll see a call to a snippet_normalize()
function. This is part of the demo and not part of Cairo. It is
simply scaling the context such that the range of 0.0 to 1.0 is the
min(width, height) of the window in pixels. In other words, it allows
the rendering code to use a range or 0.0 to 1.0 and it will always fit
in the drawing area. (Try resizing the demo and reselecting a snippet
to see this.)
<pre>
def snippet_normalize(ctx, width, height):
size = min(width, height)
ctx.scale(size, size)
ctx.set_line_width(0.04)
</pre>
%s
</body></html>
""" % extra
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

660
demo/Calendar.py Normal file
View File

@@ -0,0 +1,660 @@
#----------------------------------------------------------------------------
# Name: Calendar.py
# Purpose: Calendar control display testing on panel for wxPython demo
#
# Author: Lorne White (email: lwhite1@planet.eon.net)
#
# Version 0.9
# Date: Feb 26, 2001
# Licence: wxWindows license
#----------------------------------------------------------------------------
# 11/15/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Updated for wx namespace
#
# 11/26/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Ugh. AFter updating to the Bind() method, things lock up
# on various control clicks. Will have to debug. Only seems
# to happen on windows with calendar controls, though.
#
# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Lockup issue clarification: it appears that the spinner is
# the culprit.
#
import os
import wx
import wx.lib.calendar
import images
# highlighted days in month
test_days ={ 0: [],
1: [3, 7, 9, 21],
2: [2, 10, 4, 9],
3: [4, 20, 29],
4: [1, 12, 22],
5: [2, 10, 15],
6: [4, 8, 17],
7: [6, 7, 8],
8: [5, 10, 20],
9: [1, 2, 5, 29],
10: [2, 4, 6, 22],
11: [6, 9, 12, 28, 29],
12: [8, 9, 10, 11, 20] }
# test of full window calendar control functions
def GetMonthList():
monthlist = []
for i in range(13):
name = wx.lib.calendar.Month[i]
if name != None:
monthlist.append(name)
return monthlist
class TestPanel(wx.Panel):
def __init__(self, parent, log, frame):
wx.Panel.__init__(self, parent, -1)
self.log = log
self.frame = frame
self.calend = wx.lib.calendar.Calendar(self, -1, (100, 50), (200, 180))
# start_month = 2 # preselect the date for calendar
# start_year = 2001
start_month = self.calend.GetMonth() # get the current month & year
start_year = self.calend.GetYear()
# month list from DateTime module
monthlist = GetMonthList()
self.date = wx.ComboBox(self, -1, "",
(100, 20), (90, -1),
monthlist, wx.CB_DROPDOWN)
self.date.SetSelection(start_month-1)
self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, self.date)
# set start month and year
self.calend.SetMonth(start_month)
self.calend.SetYear(start_year)
# set attributes of calendar
self.calend.hide_title = True
self.calend.HideGrid()
self.calend.SetWeekColor('WHITE', 'BLACK')
# display routine
self.ResetDisplay()
# mouse click event
self.Bind(wx.lib.calendar.EVT_CALENDAR, self.MouseClick, self.calend)
# scroll bar for month selection
self.scroll = wx.ScrollBar(self, -1, (100, 240), (200, 20), wx.SB_HORIZONTAL)
self.scroll.SetScrollbar(start_month-1, 1, 12, 1, True)
self.Bind(wx.EVT_COMMAND_SCROLL, self.Scroll, self.scroll)
# spin control for year selection
self.dtext = wx.TextCtrl(self, -1, str(start_year), (200, 20), (60, -1))
h = self.dtext.GetSize().height
self.spin = wx.SpinButton(self, -1, (270, 20), (h*2, h))
self.spin.SetRange(1980, 2010)
self.spin.SetValue(start_year)
self.Bind(wx.EVT_SPIN, self.OnSpin, self.spin)
# button for calendar dialog test
self.but1 = wx.Button(self, -1, "Test Calendar Dialog", (380, 80))
self.Bind(wx.EVT_BUTTON, self.TestDlg, self.but1)
# button for calendar window test
self.but2 = wx.Button(self, -1, "Test Calendar Window", (380, 180))
self.Bind(wx.EVT_BUTTON, self.TestFrame, self.but2)
self.but3 = wx.Button(self, -1, "Test Calendar Print", (380, 280))
self.Bind(wx.EVT_BUTTON, self.OnPreview, self.but3)
# calendar dialog
def TestDlg(self, event): # test the date dialog
dlg = wx.lib.calendar.CalenDlg(self)
dlg.Centre()
if dlg.ShowModal() == wx.ID_OK:
result = dlg.result
day = result[1]
month = result[2]
year = result[3]
new_date = str(month) + '/'+ str(day) + '/'+ str(year)
self.log.WriteText('Date Selected: %s\n' % new_date)
else:
self.log.WriteText('No Date Selected')
# calendar window test
def TestFrame(self, event):
frame = CalendFrame(self, -1, "Test Calendar", self.log)
frame.Show(True)
return True
# calendar print preview
def OnPreview(self, event):
month = self.calend.GetMonth()
year = self.calend.GetYear()
prt = PrintCalend(self.frame, month, year)
prt.Preview()
# month and year control events
def OnSpin(self, event):
year = event.GetPosition()
self.dtext.SetValue(str(year))
self.calend.SetYear(year)
self.calend.Refresh()
def EvtComboBox(self, event):
name = event.GetString()
self.log.WriteText('EvtComboBox: %s\n' % name)
monthval = self.date.FindString(name)
self.scroll.SetScrollbar(monthval, 1, 12, 1, True)
self.calend.SetMonth(monthval+1)
self.ResetDisplay()
def Scroll(self, event):
value = self.scroll.GetThumbPosition()
monthval = int(value)+1
self.calend.SetMonth(monthval)
self.ResetDisplay()
self.log.WriteText('Month: %s\n' % value)
name = wx.lib.calendar.Month[monthval]
self.date.SetValue(name)
# log mouse events
def MouseClick(self, evt):
text = '%s CLICK %02d/%02d/%d' % (evt.click, evt.day, evt.month, evt.year) # format date
self.log.WriteText('Date Selected: ' + text + '\n')
# set the highlighted days for the calendar
def ResetDisplay(self):
month = self.calend.GetMonth()
try:
set_days = test_days[month]
except:
set_days = [1, 5, 12]
self.calend.AddSelect([4, 11], 'BLUE', 'WHITE')
self.calend.SetSelDay(set_days)
self.calend.Refresh()
# increment and decrement toolbar controls
def OnIncYear(self, event):
self.calend.IncYear()
self.ResetDisplay()
def OnDecYear(self, event):
self.calend.DecYear()
self.ResetDisplay()
def OnIncMonth(self, event):
self.calend.IncMonth()
self.ResetDisplay()
def OnDecMonth(self, event):
self.calend.DecMonth()
self.ResetDisplay()
def OnCurrent(self, event):
self.calend.SetCurrentDay()
self.ResetDisplay()
# test of full window calendar control functions
class CalendFrame(wx.Frame):
def __init__(self, parent, id, title, log):
wx.Frame.__init__(self, parent, id, title, size=(400, 400),
style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.log = log
self.CreateStatusBar()
self.mainmenu = wx.MenuBar()
menu = wx.Menu()
menu = self.MakeFileMenu()
self.mainmenu.Append(menu, '&File')
self.MakeToolMenu() # toolbar
self.SetMenuBar(self.mainmenu)
self.calend = wx.lib.calendar.Calendar(self, -1)
self.calend.SetCurrentDay()
self.calend.grid_color = 'BLUE'
self.calend.SetBusType()
# self.calend.ShowWeekEnd()
self.ResetDisplay()
self.Bind(wx.lib.calendar.EVT_CALENDAR, self.MouseClick, self.calend)
def MouseClick(self, evt):
text = '%s CLICK %02d/%02d/%d' % (evt.click, evt.day, evt.month, evt.year) # format date
self.log.WriteText('Date Selected: ' + text + '\n')
def OnCloseWindow(self, event):
self.Destroy()
def ResetDisplay(self):
month = self.calend.GetMonth()
try:
set_days = test_days[month]
except:
set_days = [1, 5, 12]
self.calend.AddSelect([2, 16], 'GREEN', 'WHITE')
self.calend.SetSelDay(set_days)
self.calend.Refresh()
def OnIncYear(self, event):
self.calend.IncYear()
self.ResetDisplay()
def OnDecYear(self, event):
self.calend.DecYear()
self.ResetDisplay()
def OnIncMonth(self, event):
self.calend.IncMonth()
self.ResetDisplay()
def OnDecMonth(self, event):
self.calend.DecMonth()
self.ResetDisplay()
def OnCurrent(self, event):
self.calend.SetCurrentDay()
self.ResetDisplay()
def MakeFileMenu(self):
menu = wx.Menu()
mID = wx.NewId()
menu.Append(mID, 'Decrement', 'Next')
self.Bind(wx.EVT_MENU, self.OnDecMonth, id=mID)
mID = wx.NewId()
menu.Append(mID, 'Increment', 'Dec')
self.Bind(wx.EVT_MENU, self.OnIncMonth, id=mID)
menu.AppendSeparator()
mID = wx.NewId()
menu.Append(mID, 'E&xit', 'Exit')
self.Bind(wx.EVT_MENU, self.OnCloseWindow, id=mID)
return menu
def MakeToolMenu(self):
tb = self.CreateToolBar(wx.TB_HORIZONTAL|wx.NO_BORDER)
mID = wx.NewId()
SetToolPath(self, tb, mID, images.DbDec.GetBitmap(), 'Dec Year')
self.Bind(wx.EVT_TOOL, self.OnDecYear, id=mID)
mID = wx.NewId()
SetToolPath(self, tb, mID, images.Dec.GetBitmap(), 'Dec Month')
self.Bind(wx.EVT_TOOL, self.OnDecMonth, id=mID)
mID = wx.NewId()
SetToolPath(self, tb, mID, images.Pt.GetBitmap(), 'Current Month')
self.Bind(wx.EVT_TOOL, self.OnCurrent, id=mID)
mID = wx.NewId()
SetToolPath(self, tb, mID, images.Inc.GetBitmap(), 'Inc Month')
self.Bind(wx.EVT_TOOL, self.OnIncMonth, id=mID)
mID = wx.NewId()
SetToolPath(self, tb, mID, images.DbInc.GetBitmap(), 'Inc Year')
self.Bind(wx.EVT_TOOL, self.OnIncYear, id=mID)
tb.Realize()
#---------------------------------------------------------------------------
# example class for printing/previewing calendars
class PrintCalend:
def __init__(self, parent, month, year):
self.frame = parent
self.month = month
self.year = year
self.SetParms()
self.SetCal()
self.printData = wx.PrintData()
def SetCal(self):
self.grid_color = 'BLUE'
self.back_color = 'WHITE'
self.sel_color = 'RED'
self.high_color = 'LIGHT BLUE'
self.font = wx.SWISS
self.bold = wx.NORMAL
self.sel_key = None # last used by
self.sel_lst = [] # highlighted selected days
self.size = None
self.hide_title = False
self.hide_grid = False
self.set_day = None
def SetParms(self):
self.ymax = 1
self.xmax = 1
self.page = 1
self.total_pg = 1
self.preview = None
self.scale = 1.0
self.pagew = 8.5
self.pageh = 11.0
self.txt_marg = 0.1
self.lf_marg = 0
self.top_marg = 0
self.page = 0
def SetDates(self, month, year):
self.month = month
self.year = year
def SetStyleDef(self, desc):
self.style = desc
def SetCopies(self, copies): # number of copies of label
self.copies = copies
def SetStart(self, start): # start position of label
self.start = start
def Preview(self):
printout = SetPrintout(self)
printout2 = SetPrintout(self)
self.preview = wx.PrintPreview(printout, printout2, self.printData)
if not self.preview.Ok():
wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
return
self.preview.SetZoom(60) # initial zoom value
frame = wx.PreviewFrame(self.preview, self.frame, "Print preview")
frame.Initialize()
frame.SetPosition(self.frame.GetPosition())
frame.SetSize(self.frame.GetSize())
frame.Show(True)
def Print(self):
pdd = wx.PrintDialogData()
pdd.SetPrintData(self.printData)
printer = wx.Printer(pdd)
printout = SetPrintout(self)
frame = wx.Frame(None, -1, "Test")
if not printer.Print(frame, printout):
wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
else:
self.printData = printer.GetPrintDialogData().GetPrintData()
printout.Destroy()
def DoDrawing(self, DC):
size = DC.GetSize()
DC.BeginDrawing()
cal = wx.lib.calendar.PrtCalDraw(self)
if self.preview is None:
cal.SetPSize(size[0]/self.pagew, size[1]/self.pageh)
cal.SetPreview(False)
else:
if self.preview == 1:
cal.SetPSize(size[0]/self.pagew, size[1]/self.pageh)
else:
cal.SetPSize(self.pwidth, self.pheight)
cal.SetPreview(self.preview)
cal.hide_title = self.hide_title # set the calendar parameters
cal.hide_grid = self.hide_grid
cal.grid_color = self.grid_color
cal.high_color = self.high_color
cal.back_color = self.back_color
cal.outer_border = False
cal.font = self.font
cal.bold = self.bold
cal_size = (3.0, 3.0)
cal.SetSize(cal_size)
year, month = self.year, self.month
x = 0.5
for i in range(2):
y = 0.5
for j in range(3):
cal.SetCal(year, month) # current month
cal.SetPos(x, y)
try:
set_days = test_days[month]
except:
set_days = [1, 5, 12]
cal.AddSelect([2, 16], 'GREEN', 'WHITE')
cal.DrawCal(DC, set_days)
year, month = self.IncMonth(year, month)
y = y + 3.5
x = x + 4.0 # next column
DC.EndDrawing()
self.ymax = DC.MaxY()
self.xmax = DC.MaxX()
def IncMonth(self, year, month): # next month
month = month + 1
if month > 12:
month = 1
year = year + 1
return year, month
def GetTotalPages(self):
self.pg_cnt = 1
return self.pg_cnt
def SetPage(self, page):
self.page = page
def SetPageSize(self, width, height):
self.pwidth, self.pheight = width, height
def SetTotalSize(self, width, height):
self.ptwidth, self.ptheight = width, height
def SetPreview(self, preview, scale):
self.preview = preview
self.scale = scale
def SetTotalSize(self, width, height):
self.ptwidth = width
self.ptheight = height
def SetToolPath(self, tb, id, bmp, title):
tb.AddSimpleTool(id, bmp, title, title)
class SetPrintout(wx.Printout):
def __init__(self, canvas):
wx.Printout.__init__(self)
self.canvas = canvas
self.end_pg = 1
def OnBeginDocument(self, start, end):
return super(SetPrintout, self).OnBeginDocument(start, end)
def OnEndDocument(self):
super(SetPrintout, self).OnEndDocument()
def HasPage(self, page):
if page <= self.end_pg:
return True
else:
return False
def GetPageInfo(self):
self.end_pg = self.canvas.GetTotalPages()
str_pg = 1
try:
end_pg = self.end_pg
except:
end_pg = 1
return (str_pg, end_pg, str_pg, end_pg)
def OnPreparePrinting(self):
super(SetPrintout, self).OnPreparePrinting()
def OnBeginPrinting(self):
dc = self.GetDC()
self.preview = self.IsPreview()
if (self.preview):
self.pixelsPerInch = self.GetPPIScreen()
else:
self.pixelsPerInch = self.GetPPIPrinter()
(w, h) = dc.GetSize()
scaleX = float(w) / 1000
scaleY = float(h) / 1000
self.printUserScale = min(scaleX, scaleY)
super(SetPrintout, self).OnBeginPrinting()
def GetSize(self):
self.psizew, self.psizeh = self.GetPPIPrinter()
return self.psizew, self.psizeh
def GetTotalSize(self):
self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
return self.ptsizew, self.ptsizeh
def OnPrintPage(self, page):
dc = self.GetDC()
(w, h) = dc.GetSize()
scaleX = float(w) / 1000
scaleY = float(h) / 1000
self.printUserScale = min(scaleX, scaleY)
dc.SetUserScale(self.printUserScale, self.printUserScale)
self.preview = self.IsPreview()
self.canvas.SetPreview(self.preview, self.printUserScale)
self.canvas.SetPage(page)
self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
self.psizew, self.psizeh = self.GetPPIPrinter()
self.canvas.SetPageSize(self.psizew, self.psizeh)
self.canvas.DoDrawing(dc)
return True
class MyApp(wx.App):
def OnInit(self):
frame = CalendFrame(None, -1, "Test Calendar", log)
frame.Show(True)
self.SetTopWindow(frame)
return True
#---------------------------------------------------------------------------
def MessageDlg(self, message, type = 'Message'):
dlg = wx.MessageDialog(self, message, type, wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log, frame)
return win
#---------------------------------------------------------------------------
overview = """\
This control provides a Calendar control class for displaying and selecting dates.
In addition, the class is extended and can be used for printing/previewing.
Additional features include weekend highlighting and business type Monday-Sunday
format.
See example for various methods used to set display month, year, and highlighted
dates (different font and background colours).
by Lorne White
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

118
demo/CalendarCtrl.py Normal file
View File

@@ -0,0 +1,118 @@
import wx
import wx.calendar as wxcal
#----------------------------------------------------------------------
description = """\
This sample shows the wx.calendar.CalendarCtrl in a variety of styles
and modes. If this platform supports a native calendar widget then
that is what is shown to the left. However it may not support all of
the features and attributes of the older wx calendar, so we now have
the ability to explicitly use the generic widget via the
GenericCalendarCtrl class, and that is what is used for the two
calendars below.
""".replace('\n', ' ')
class TestPanel(wx.Panel):
def __init__(self, parent, ID, log):
wx.Panel.__init__(self, parent, ID)
self.log = log
native = wxcal.CalendarCtrl(self, -1, wx.DateTime.Today(),
style=wxcal.CAL_SEQUENTIAL_MONTH_SELECTION)
txt = wx.StaticText(self, -1, description)
txt.Wrap(300)
cal = self.cal = wxcal.GenericCalendarCtrl(self, -1, wx.DateTime.Today(),
style = wxcal.CAL_SHOW_HOLIDAYS
| wxcal.CAL_SUNDAY_FIRST
| wxcal.CAL_SEQUENTIAL_MONTH_SELECTION
)
cal2 = wxcal.GenericCalendarCtrl(self, -1, wx.DateTime.Today())
# Track a few holidays
self.holidays = [(1,1), (10,31), (12,25) ] # (these don't move around)
self.OnChangeMonth()
# bind some event handlers to each calendar
for c in native, cal, cal2:
c.Bind(wxcal.EVT_CALENDAR, self.OnCalSelected)
c.Bind(wxcal.EVT_CALENDAR_MONTH, self.OnChangeMonth)
c.Bind(wxcal.EVT_CALENDAR_SEL_CHANGED, self.OnCalSelChanged)
c.Bind(wxcal.EVT_CALENDAR_WEEKDAY_CLICKED, self.OnCalWeekdayClicked)
# create some sizers for layout
fgs = wx.FlexGridSizer(cols=2, hgap=50, vgap=50)
fgs.Add(native)
fgs.Add(txt)
fgs.Add(cal)
fgs.Add(cal2)
box = wx.BoxSizer()
box.Add(fgs, 1, wx.EXPAND|wx.ALL, 25)
self.SetSizer(box)
def OnCalSelected(self, evt):
self.log.write('OnCalSelected: %s\n' % evt.GetDate())
def OnCalWeekdayClicked(self, evt):
self.log.write('OnCalWeekdayClicked: %s\n' % evt.GetWeekDay())
def OnCalSelChanged(self, evt):
cal = evt.GetEventObject()
self.log.write("OnCalSelChanged:\n\t%s: %s\n\t%s: %s" %
("EventObject", cal.__class__,
"Date ", cal.GetDate(),
))
def OnChangeMonth(self, evt=None):
if evt is None:
cal = self.cal
else:
cal = evt.GetEventObject()
self.log.write('OnChangeMonth: %s\n' % cal.GetDate())
cur_month = cal.GetDate().GetMonth() + 1 # convert wxDateTime 0-11 => 1-12
for month, day in self.holidays:
if month == cur_month:
cal.SetHoliday(day)
# August 14th is a special day, mark it with a blue square...
if cur_month == 8:
attr = wxcal.CalendarDateAttr(border=wxcal.CAL_BORDER_SQUARE,
colBorder="blue")
cal.SetAttr(14, attr)
else:
cal.ResetAttr(14)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, -1, log)
return win
#----------------------------------------------------------------------
overview = """\
<html><body>
<h2>CalendarCtrl</h2>
Yet <i>another</i> calendar control. This one is a wrapper around the C++
version described in the docs. This one will probably be a bit more efficient
than the one in wxPython.lib.calendar, but I like a few things about it better,
so I think both will stay in wxPython.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

73
demo/CheckBox.py Normal file
View File

@@ -0,0 +1,73 @@
import wx
#---------------------------------------------------------------------------
class TestCheckBox(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
st = wx.StaticText(self, -1, "This example demonstrates the wx.CheckBox control.")#, (10, 10))
cb1 = wx.CheckBox(self, -1, "Apples")#, (65, 40), (150, 20), wx.NO_BORDER)
cb2 = wx.CheckBox(self, -1, "Oranges")#, (65, 60), (150, 20), wx.NO_BORDER)
cb2.SetValue(True)
cb3 = wx.CheckBox(self, -1, "Pears")#, (65, 80), (150, 20), wx.NO_BORDER)
cb4 = wx.CheckBox(self, -1, "3-state checkbox",
style=wx.CHK_3STATE|wx.CHK_ALLOW_3RD_STATE_FOR_USER)
cb5 = wx.CheckBox(self, -1, "Align Right", style=wx.ALIGN_RIGHT)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb1)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb2)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb3)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb4)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb5)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddMany( [ cb1,
cb2,
cb3,
(20,20),
cb4,
(20,20),
cb5
])
border = wx.BoxSizer(wx.VERTICAL)
border.Add(st, 0, wx.ALL, 15)
border.Add(sizer, 0, wx.LEFT, 50)
self.SetSizer(border)
def EvtCheckBox(self, event):
self.log.write('EvtCheckBox: %d\n' % event.IsChecked())
cb = event.GetEventObject()
if cb.Is3State():
self.log.write("\t3StateValue: %s\n" % cb.Get3StateValue())
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestCheckBox(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
A checkbox is a labelled box which is either on (checkmark is visible) or off
(no checkmark).
"""
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

74
demo/CheckListBox.py Normal file
View File

@@ -0,0 +1,74 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
sampleList = ['zero', 'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten', 'eleven',
'twelve', 'thirteen', 'fourteen']
wx.StaticText(self, -1, "This example uses the wxCheckListBox control.", (45, 15))
lb = wx.CheckListBox(self, -1, (80, 50), wx.DefaultSize, sampleList)
self.Bind(wx.EVT_LISTBOX, self.EvtListBox, lb)
self.Bind(wx.EVT_CHECKLISTBOX, self.EvtCheckListBox, lb)
lb.SetSelection(0)
self.lb = lb
lb.Bind(wx.EVT_RIGHT_DOWN, self.OnDoHitTest)
pos = lb.GetPosition().x + lb.GetSize().width + 25
btn = wx.Button(self, -1, "Test SetString", (pos, 50))
self.Bind(wx.EVT_BUTTON, self.OnTestButton, btn)
def EvtListBox(self, event):
self.log.WriteText('EvtListBox: %s\n' % event.GetString())
def EvtCheckListBox(self, event):
index = event.GetSelection()
label = self.lb.GetString(index)
status = 'un'
if self.lb.IsChecked(index):
status = ''
self.log.WriteText('Box %s is %schecked \n' % (label, status))
self.lb.SetSelection(index) # so that (un)checking also selects (moves the highlight)
def OnTestButton(self, evt):
self.lb.SetString(4, "FUBAR")
def OnDoHitTest(self, evt):
item = self.lb.HitTest(evt.GetPosition())
self.log.write("HitTest: %d\n" % item)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
A checklistbox is like a Listbox, but allows items to be checked or unchecked rather
than relying on extended selection (e.g. shift-select) to select multiple items in
the list.
This class is currently implemented under Windows and GTK.
This demo shows the basic CheckListBox and how to use the SetString method to change
labels dynamically.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

View File

@@ -0,0 +1,96 @@
import sys
import wx
from wx.lib.mixins.listctrl import CheckListCtrlMixin
from ListCtrl import musicdata
#----------------------------------------------------------------------
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin):
def __init__(self, parent, log):
wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
CheckListCtrlMixin.__init__(self)
self.log = log
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
def OnItemActivated(self, evt):
self.ToggleItem(evt.m_itemIndex)
# this is called by the base class when an item is checked/unchecked
def OnCheckItem(self, index, flag):
data = self.GetItemData(index)
title = musicdata[data][1]
if flag:
what = "checked"
else:
what = "unchecked"
self.log.write('item "%s", at index %d was %s\n' % (title, index, what))
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.list = CheckListCtrl(self, log)
sizer = wx.BoxSizer()
sizer.Add(self.list, 1, wx.EXPAND)
self.SetSizer(sizer)
self.list.InsertColumn(0, "Artist")
self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
self.list.InsertColumn(2, "Genre")
for key, data in musicdata.iteritems():
index = self.list.InsertStringItem(sys.maxint, data[0])
self.list.SetStringItem(index, 1, data[1])
self.list.SetStringItem(index, 2, data[2])
self.list.SetItemData(index, key)
self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
self.list.SetColumnWidth(2, 100)
self.list.CheckItem(4)
self.list.CheckItem(7)
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list)
def OnItemSelected(self, evt):
self.log.write('item selected: %s\n' % evt.m_itemIndex)
def OnItemDeselected(self, evt):
self.log.write('item deselected: %s\n' % evt.m_itemIndex)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><centerCheckListCtrlMixin></center></h2>
CheckListCtrlMixin is a simple mixin class that can add a checkbox to
the first column of a wx.ListCtrl.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

54
demo/Choice.py Normal file
View File

@@ -0,0 +1,54 @@
import wx
#---------------------------------------------------------------------------
class TestChoice(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sampleList = ['zero', 'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight']
wx.StaticText(self, -1, "This example uses the wxChoice control.", (15, 10))
wx.StaticText(self, -1, "Select one:", (15, 50), (75, -1))
self.ch = wx.Choice(self, -1, (100, 50), choices = sampleList)
self.Bind(wx.EVT_CHOICE, self.EvtChoice, self.ch)
def EvtChoice(self, event):
self.log.WriteText('EvtChoice: %s\n' % event.GetString())
self.ch.Append("A new item")
if event.GetString() == 'one':
self.log.WriteText('Well done!\n')
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestChoice(nb, log)
return win
#---------------------------------------------------------------------------
overview = """
A Choice control is used to select one of a list of strings. Unlike a listbox,
only the current selection is visible until the user pulls down the menu of
choices.
This demo illustrates how to set up the Choice control and how to extract the
selected choice once it is selected.
Note that the syntax of the constructor is different than the C++ implementation.
The number of choices and the choice array are consilidated into one python
<code>list</code>.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

79
demo/Choicebook.py Normal file
View File

@@ -0,0 +1,79 @@
import wx
#----------------------------------------------------------------------------
pageTexts = [ "Yet",
"Another",
"Way",
"To",
"Select",
"Pages"
]
class TestCB(wx.Choicebook):
def __init__(self, parent, id, log):
wx.Choicebook.__init__(self, parent, id)
self.log = log
# Now make a bunch of panels for the choice book
count = 1
for txt in pageTexts:
win = wx.Panel(self)
if count == 1:
st = wx.StaticText(win, -1,
"wx.Choicebook is yet another way to switch between 'page' windows",
(10, 10))
else:
st = wx.StaticText(win, -1, "Page: %d" % count, (10,10))
count += 1
self.AddPage(win, txt)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
def OnPageChanged(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel))
event.Skip()
def OnPageChanging(self, event):
old = event.GetOldSelection()
new = event.GetSelection()
sel = self.GetSelection()
self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel))
event.Skip()
#----------------------------------------------------------------------------
def runTest(frame, nb, log):
testWin = TestCB(nb, -1, log)
return testWin
#----------------------------------------------------------------------------
overview = """\
<html><body>
<h2>wx.Choicebook</h2>
<p>
This class is a control similar to a notebook control, but uses a
wx.Choice to manage the selection of the pages.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

125
demo/CollapsiblePane.py Normal file
View File

@@ -0,0 +1,125 @@
import wx
#----------------------------------------------------------------------
label1 = "Click here to show pane"
label2 = "Click here to hide pane"
btnlbl1 = "call Expand(True)"
btnlbl2 = "call Expand(False)"
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
title = wx.StaticText(self, label="wx.CollapsiblePane")
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
title.SetForegroundColour("blue")
self.cp = cp = wx.CollapsiblePane(self, label=label1,
style=wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, cp)
self.MakePaneContent(cp.GetPane())
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
sizer.Add(title, 0, wx.ALL, 25)
sizer.Add(cp, 0, wx.RIGHT|wx.LEFT|wx.EXPAND, 25)
self.btn = btn = wx.Button(self, label=btnlbl1)
self.Bind(wx.EVT_BUTTON, self.OnToggle, btn)
sizer.Add(btn, 0, wx.ALL, 25)
def OnToggle(self, evt):
self.cp.Collapse(self.cp.IsExpanded())
self.OnPaneChanged()
def OnPaneChanged(self, evt=None):
if evt:
self.log.write('wx.EVT_COLLAPSIBLEPANE_CHANGED: %s' % evt.Collapsed)
# redo the layout
self.Layout()
# and also change the labels
if self.cp.IsExpanded():
self.cp.SetLabel(label2)
self.btn.SetLabel(btnlbl2)
else:
self.cp.SetLabel(label1)
self.btn.SetLabel(btnlbl1)
self.btn.SetInitialSize()
def MakePaneContent(self, pane):
'''Just make a few controls to put on the collapsible pane'''
nameLbl = wx.StaticText(pane, -1, "Name:")
name = wx.TextCtrl(pane, -1, "");
addrLbl = wx.StaticText(pane, -1, "Address:")
addr1 = wx.TextCtrl(pane, -1, "");
addr2 = wx.TextCtrl(pane, -1, "");
cstLbl = wx.StaticText(pane, -1, "City, State, Zip:")
city = wx.TextCtrl(pane, -1, "", size=(150,-1));
state = wx.TextCtrl(pane, -1, "", size=(50,-1));
zip = wx.TextCtrl(pane, -1, "", size=(70,-1));
addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
addrSizer.AddGrowableCol(1)
addrSizer.Add(nameLbl, 0,
wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(name, 0, wx.EXPAND)
addrSizer.Add(addrLbl, 0,
wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(addr1, 0, wx.EXPAND)
addrSizer.Add((5,5))
addrSizer.Add(addr2, 0, wx.EXPAND)
addrSizer.Add(cstLbl, 0,
wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
cstSizer = wx.BoxSizer(wx.HORIZONTAL)
cstSizer.Add(city, 1)
cstSizer.Add(state, 0, wx.LEFT|wx.RIGHT, 5)
cstSizer.Add(zip)
addrSizer.Add(cstSizer, 0, wx.EXPAND)
border = wx.BoxSizer()
border.Add(addrSizer, 1, wx.EXPAND|wx.ALL, 5)
pane.SetSizer(border)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.CollapsiblePane</center></h2>
A collapsable panel is a container with an embedded button-like
control which can be used by the user to collapse or expand the pane's
contents.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

20
demo/ColorPanel.py Normal file
View File

@@ -0,0 +1,20 @@
#
# Note: this module is not a demo per se, but is used by many of
# the demo modules for various purposes.
#
import wx
#---------------------------------------------------------------------------
class ColoredPanel(wx.Window):
def __init__(self, parent, color):
wx.Window.__init__(self, parent, -1, style = wx.SIMPLE_BORDER)
self.SetBackgroundColour(color)
if wx.Platform == '__WXGTK__':
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
#---------------------------------------------------------------------------

202
demo/ColourDB.py Normal file
View File

@@ -0,0 +1,202 @@
import wx
import wx.lib.colourdb
import images
#----------------------------------------------------------------------
class TestWindow(wx.ScrolledWindow):
def __init__(self, parent):
wx.ScrolledWindow.__init__(self, parent, -1)
# Populate our color list
self.clrList = wx.lib.colourdb.getColourInfoList()
# Just for style points, we'll use this as a background image.
self.bg_bmp = images.GridBG.GetBitmap()
# This could also be done by getting the window's default font;
# either way, we need to have a font loaded for later on.
#self.SetBackgroundColour("WHITE")
self.font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
# Create drawing area and set its font
dc = wx.ClientDC(self)
dc.SetFont(self.font)
# Using GetFullTextExtent(), we calculate a basic 'building block'
# that will be used to draw a depiction of the color list. We're
# using 'Wy' as the model becuase 'W' is a wide character and 'y'
# has a descender. This constitutes a 'worst case' scenario, which means
# that no matter what we draw later, text-wise, we'll have room for it
w,h,d,e = dc.GetFullTextExtent("Wy")
# Height plus descender
self.textHeight = h + d
# Pad a little bit
self.lineHeight = self.textHeight + 5
# ... and this is the basic width.
self.cellWidth = w
# jmg 11/8/03: why 24?
numCells = 24
# 'prep' our scroll bars.
self.SetScrollbars(
self.cellWidth, self.lineHeight, numCells, len(self.clrList) + 2
)
# Bind event handlers
self.SetBackgroundStyle(wx.BG_STYLE_ERASE)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
# tile the background bitmap loaded in __init__()
def TileBackground(self, dc):
sz = self.GetClientSize()
w = self.bg_bmp.GetWidth()
h = self.bg_bmp.GetHeight()
# adjust for scrolled position
spx, spy = self.GetScrollPixelsPerUnit()
vsx, vsy = self.GetViewStart()
dx, dy = (spx * vsx) % w, (spy * vsy) % h
x = -dx
while x < sz.width:
y = -dy
while y < sz.height:
dc.DrawBitmap(self.bg_bmp, x, y)
y = y + h
x = x + w
# Redraw the background over a 'damaged' area.
def OnEraseBackground(self, evt):
dc = evt.GetDC()
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
self.TileBackground(dc)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
self.PrepareDC(dc)
self.Draw(dc, self.GetUpdateRegion(), self.GetViewStart())
def Draw(self, dc, rgn=None, vs=None):
dc.SetTextForeground("BLACK")
dc.SetPen(wx.Pen("BLACK", 1, wx.SOLID))
dc.SetFont(self.font)
colours = self.clrList
numColours = len(colours)
if rgn:
# determine the subset of the color list that has been exposed
# and needs drawn. This is based on all the precalculation we
# did in __init__()
rect = rgn.GetBox()
pixStart = vs[1]*self.lineHeight + rect.y
pixStop = pixStart + rect.height
start = pixStart / self.lineHeight - 1
stop = pixStop / self.lineHeight
else:
start = 0
stop = numColours
for line in range(max(0,start), min(stop,numColours)):
clr = colours[line][0]
y = (line+1) * self.lineHeight + 2
dc.DrawText(clr, self.cellWidth, y)
brush = wx.Brush(clr, wx.SOLID)
dc.SetBrush(brush)
dc.DrawRectangle(10 * self.cellWidth, y,
6 * self.cellWidth, self.textHeight)
dc.DrawText(str(tuple(colours[line][1:])),
18 * self.cellWidth, y)
hexstr = "#%02X%02X%02X" % tuple(colours[line][1:])
dc.DrawText(hexstr, 25 * self.cellWidth, y)
# On wxGTK there needs to be a panel under wx.ScrolledWindows if they are
# going to be in a wxNotebook. And, in this demo, we are.
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.win = TestWindow(self)
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, evt):
self.win.SetSize(evt.GetSize())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
# This loads a whole bunch of new color names and values
# into TheColourDatabase
#
# Note 11/24/03 - jg - I moved this into runTest() because
# there must be a wx.App existing before this function
# can be called - this is a change from 2.4 -> 2.5.
wx.lib.colourdb.updateColourDB()
win = TestPanel(nb)
return win
#----------------------------------------------------------------------
overview = """
<html>
<body>
<B><font size=+2>ColourDB</font></b>
<p>wxWindows maintains a database of standard RGB colours for a predefined
set of named colours (such as "BLACK'', "LIGHT GREY''). The application
may add to this set if desired by using Append. There is only one instance
of this class: <b>TheColourDatabase</b>.
<p>The <code>colourdb</code> library is a lightweight API that pre-defines
a multitude of colors for you to use 'out of the box', and this demo serves
to show you these colors (it also serves as a handy reference).
<p>A secondary benefit of this demo is the use of the <b>ScrolledWindow</b> class
and the use of various *DC() classes, including background tiling and the use of
font data to generate a "building block" type of construct for repetitive use.
<p>
<B><font size=+2>Important note</font></b>
<p>
With implementation of V2.5 and later, it is required to have a wx.App already
initialized before <b><code>wx.updateColourDB()</code></b> can be called.
Trying to do otherwise will cause an exception to be raised.
</body>
</html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

72
demo/ColourDialog.py Normal file
View File

@@ -0,0 +1,72 @@
import wx
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a ColourDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
dlg = wx.ColourDialog(self)
# Ensure the full colour dialog is displayed,
# not the abbreviated version.
dlg.GetColourData().SetChooseFull(True)
if dlg.ShowModal() == wx.ID_OK:
# If the user selected OK, then the dialog's wx.ColourData will
# contain valid information. Fetch the data ...
data = dlg.GetColourData()
# ... then do something with it. The actual colour data will be
# returned as a three-tuple (r, g, b) in this particular case.
self.log.WriteText('You selected: %s\n' % str(data.GetColour().Get()))
# Once the dialog is destroyed, Mr. wx.ColourData is no longer your
# friend. Don't use it again!
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
This class represents the colour chooser dialog.
Use of this dialog is a multi-stage process.
The actual information about how to display the dialog and the colors in the
dialog's 'registers' are contained in a wx.ColourData instance that is created by
the dialog at init time. Before displaying the dialog, you may alter these settings
to suit your needs. In the example, we set the dialog up to show the extended colour
data selection pane. Otherwise, only the more compact and less extensive colour
dialog is shown. You may also preset the colour as well as other items.
If the user selects something and selects OK, then the wx.ColourData instance contains
the colour data that the user selected. Before destroying the dialog, retrieve the data.
<b>Do not try to retain the wx.ColourData instance.</b> It will probably not be valid
after the dialog is destroyed.
Along with he wx.ColourDialog documentation, see also the wx.ColourData documentation
for details.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

116
demo/ColourSelect.py Normal file
View File

@@ -0,0 +1,116 @@
#----------------------------------------------------------------------------
# Name: ColourSelect.py
# Purpose: Colour Selection control display testing on panel for wxPython demo
#
# Author: Lorne White (email: lorne.white@telusplanet.net)
#
# Version 0.6
# Date: Nov 14, 2001
# Licence: wxWindows license
#
# Change Log: Add Label parameter to accommodate updated library code
#
# Cliff Wells (logiplexsoftware@earthlink.net) 2002/03/11
# - added code to demonstrate EVT_COLOURSELECT
# - use sizers
# - other minor "improvements"
#----------------------------------------------------------------------------
#
import wx
import wx.lib.colourselect as csel
#----------------------------------------------------------------------------
class TestColourSelect(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.SetAutoLayout(True)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(mainSizer)
t = wx.StaticText(self, -1,
"This example uses a colour selection control based on the wxButton\n"
"and wxColourDialog Classes. Click Button to get Colour Values")
mainSizer.Add(t, 0, wx.ALL, 3)
b = wx.Button(self, -1, "Show All Colours")
self.Bind(wx.EVT_BUTTON, self.OnShowAll, id=b.GetId())
mainSizer.Add(b, 0, wx.ALL, 3)
buttonSizer = wx.FlexGridSizer(cols=2) # sizer to contain all the example buttons
# show a button with all default values
self.colourDefaults = csel.ColourSelect(self, -1)
self.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour, id=self.colourDefaults.GetId())
buttonSizer.AddMany([
(wx.StaticText(self, -1, "Default Colour/Size"), 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
(self.colourDefaults, 0, wx.ALL, 3),
])
# build several examples of buttons with different colours and sizes
buttonData = [
("Default Size", (255, 255, 0), wx.DefaultSize, ""),
("Another Size", (255, 0, 255), (60, 20), ""),
("Another Colour", (0, 255, 0), wx.DefaultSize, ""),
("Larger Size", (0, 0, 255), (60, 60), ""),
("With a Label", (127, 0, 255), wx.DefaultSize, "Colour..."),
("Another Colour/Label", (255, 100, 130), (120, -1), "Choose Colour..."),
]
self.buttonRefs = [] # for saving references to buttons
# build each button and save a reference to it
for name, color, size, label in buttonData:
b = csel.ColourSelect(self, -1, label, color, size = size)
b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
self.buttonRefs.append((name, b)) # store reference to button
buttonSizer.AddMany([
(wx.StaticText(self, -1, name), 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
(b, 0, wx.ALL, 3),
])
mainSizer.Add(buttonSizer, 0, wx.ALL, 3)
self.Layout()
def OnSelectColour(self, event):
self.log.WriteText("Colour selected: %s" % str(event.GetValue()))
def OnShowAll(self, event):
# show the state of each button
result = []
colour = self.colourDefaults.GetColour() # default control value
result.append("Default Colour/Size: " + str(colour))
for name, button in self.buttonRefs:
colour = button.GetColour() # get the colour selection button result
result.append(name + ": " + str(colour)) # create string list for easy viewing of results
out_result = ', '.join(result)
self.log.WriteText("Colour Results: " + out_result + "\n")
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestColourSelect(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
A coloured button that when clicked allows the user to select a colour from the wxColourDialog.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

110
demo/ComboBox.py Normal file
View File

@@ -0,0 +1,110 @@
import wx
#---------------------------------------------------------------------------
class TestComboBox(wx.Panel):
def OnSetFocus(self, evt):
print "OnSetFocus"
evt.Skip()
def OnKillFocus(self, evt):
print "OnKillFocus"
evt.Skip()
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sampleList = ['zero', 'one', 'two', 'three', 'four', 'five',
#'this is a long item that needs a scrollbar...',
'six', 'seven', 'eight']
wx.StaticText(self, -1, "This example uses the wx.ComboBox control.", (8, 10))
wx.StaticText(self, -1, "Select one:", (15, 50), (75, 18))
# This combobox is created with a preset list of values.
cb = wx.ComboBox(self, 500, "default value", (90, 50),
(160, -1), sampleList,
wx.CB_DROPDOWN
#| wx.TE_PROCESS_ENTER
#| wx.CB_SORT
)
self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, cb)
self.Bind(wx.EVT_TEXT, self.EvtText, cb)
self.Bind(wx.EVT_TEXT_ENTER, self.EvtTextEnter, cb)
cb.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
cb.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
# Once the combobox is set up, we can append some more data to it.
cb.Append("foo", "This is some client data for this item")
# This combobox is created with no values initially.
cb = wx.ComboBox(
self, 501, "default value", (90, 80), (160, -1), [], wx.CB_DROPDOWN)
# Here we dynamically add our values to the second combobox.
for item in sampleList:
cb.Append(item, item.upper())
self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, cb)
# When the user selects something, we go here.
def EvtComboBox(self, evt):
cb = evt.GetEventObject()
data = cb.GetClientData(evt.GetSelection())
self.log.WriteText('EvtComboBox: %s\nClientData: %s\n' % (evt.GetString(), data))
if evt.GetString() == 'one':
self.log.WriteText("You follow directions well!\n\n")
# Capture events every time a user hits a key in the text entry field.
def EvtText(self, evt):
self.log.WriteText('EvtText: %s\n' % evt.GetString())
evt.Skip()
# Capture events when the user types something into the control then
# hits ENTER.
def EvtTextEnter(self, evt):
self.log.WriteText('EvtTextEnter: %s' % evt.GetString())
evt.Skip()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestComboBox(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
A ComboBox is like a combination of an edit control and a listbox. It can be
displayed as static list with editable or read-only text field; or a drop-down
list with text field; or a drop-down list without a text field.
This example shows both a preset ComboBox and one that is dynamically created
(that is, it is initially empty but then we 'grow' it out of program-supplied
data). The former is common for read-only controls.
This example also shows the two form factors for the ComboBox. The first is more
common, and resembles a Choice control. The latter, although less common, shows
how all the values in the ComboBox can be visible, yet the functionality is the
same for both.
Finally, this demo shows how event handling can differ. The first ComboBox is set
up to handle EVT_TEXT_ENTER events, in which text is typed in and then ENTER is
hit by the user. This allows the user to enter a line of text which can then be
processed by the program. EVT_TEXT can also be processed, but in that case the
event is generated every time that the user hits a key in the ComboBox entry field.
"""
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

480
demo/ComboCtrl.py Normal file
View File

@@ -0,0 +1,480 @@
import wx
import wx.combo
import os
#----------------------------------------------------------------------
class NullLog:
def write(*args):
pass
# This class is used to provide an interface between a ComboCtrl and a
# ListCtrl that is used as the popoup for the combo widget. In this
# case we use multiple inheritance to derive from both wx.ListCtrl and
# wx.ComboPopup, but it also works well when deriving from just
# ComboPopup and using a has-a relationship with the popup control,
# you just need to be sure to return the control itself from the
# GetControl method.
class ListCtrlComboPopup(wx.ListCtrl, wx.combo.ComboPopup):
def __init__(self, log=None):
if log:
self.log = log
else:
self.log = NullLog()
# Since we are using multiple inheritance, and don't know yet
# which window is to be the parent, we'll do 2-phase create of
# the ListCtrl instead, and call its Create method later in
# our Create method. (See Create below.)
self.PostCreate(wx.PreListCtrl())
# Also init the ComboPopup base class.
wx.combo.ComboPopup.__init__(self)
def AddItem(self, txt):
self.InsertStringItem(self.GetItemCount(), txt)
def OnMotion(self, evt):
item, flags = self.HitTest(evt.GetPosition())
if item >= 0:
self.Select(item)
self.curitem = item
def OnLeftDown(self, evt):
self.value = self.curitem
self.Dismiss()
# The following methods are those that are overridable from the
# ComboPopup base class. Most of them are not required, but all
# are shown here for demonstration purposes.
# This is called immediately after construction finishes. You can
# use self.GetCombo if needed to get to the ComboCtrl instance.
def Init(self):
self.log.write("ListCtrlComboPopup.Init")
self.value = -1
self.curitem = -1
# Create the popup child control. Return true for success.
def Create(self, parent):
self.log.write("ListCtrlComboPopup.Create")
wx.ListCtrl.Create(self, parent,
style=wx.LC_LIST|wx.LC_SINGLE_SEL|wx.SIMPLE_BORDER)
#self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
return True
# Return the widget that is to be used for the popup
def GetControl(self):
#self.log.write("ListCtrlComboPopup.GetControl")
return self
# Called just prior to displaying the popup, you can use it to
# 'select' the current item.
def SetStringValue(self, val):
self.log.write("ListCtrlComboPopup.SetStringValue")
idx = self.FindItem(-1, val)
if idx != wx.NOT_FOUND:
self.Select(idx)
# Return a string representation of the current item.
def GetStringValue(self):
self.log.write("ListCtrlComboPopup.GetStringValue")
if self.value >= 0:
return self.GetItemText(self.value)
return ""
# Called immediately after the popup is shown
def OnPopup(self):
self.log.write("ListCtrlComboPopup.OnPopup")
wx.combo.ComboPopup.OnPopup(self)
# Called when popup is dismissed
def OnDismiss(self):
self.log.write("ListCtrlComboPopup.OnDismiss")
wx.combo.ComboPopup.OnDismiss(self)
# This is called to custom paint in the combo control itself
# (ie. not the popup). Default implementation draws value as
# string.
def PaintComboControl(self, dc, rect):
self.log.write("ListCtrlComboPopup.PaintComboControl")
wx.combo.ComboPopup.PaintComboControl(self, dc, rect)
# Receives key events from the parent ComboCtrl. Events not
# handled should be skipped, as usual.
def OnComboKeyEvent(self, event):
self.log.write("ListCtrlComboPopup.OnComboKeyEvent")
wx.combo.ComboPopup.OnComboKeyEvent(self, event)
# Implement if you need to support special action when user
# double-clicks on the parent wxComboCtrl.
def OnComboDoubleClick(self):
self.log.write("ListCtrlComboPopup.OnComboDoubleClick")
wx.combo.ComboPopup.OnComboDoubleClick(self)
# Return final size of popup. Called on every popup, just prior to OnPopup.
# minWidth = preferred minimum width for window
# prefHeight = preferred height. Only applies if > 0,
# maxHeight = max height for window, as limited by screen size
# and should only be rounded down, if necessary.
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
self.log.write("ListCtrlComboPopup.GetAdjustedSize: %d, %d, %d" % (minWidth, prefHeight, maxHeight))
return wx.combo.ComboPopup.GetAdjustedSize(self, minWidth, prefHeight, maxHeight)
# Return true if you want delay the call to Create until the popup
# is shown for the first time. It is more efficient, but note that
# it is often more convenient to have the control created
# immediately.
# Default returns false.
def LazyCreate(self):
self.log.write("ListCtrlComboPopup.LazyCreate")
return wx.combo.ComboPopup.LazyCreate(self)
#----------------------------------------------------------------------
# This class is a popup containing a TreeCtrl. This time we'll use a
# has-a style (instead of is-a like above.)
class TreeCtrlComboPopup(wx.combo.ComboPopup):
# overridden ComboPopup methods
def Init(self):
self.value = None
self.curitem = None
def Create(self, parent):
self.tree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
|wx.TR_HAS_BUTTONS
|wx.TR_SINGLE
|wx.TR_LINES_AT_ROOT
|wx.SIMPLE_BORDER)
self.tree.Bind(wx.EVT_MOTION, self.OnMotion)
self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
def GetControl(self):
return self.tree
def GetStringValue(self):
if self.value:
return self.tree.GetItemText(self.value)
return ""
def OnPopup(self):
if self.value:
self.tree.EnsureVisible(self.value)
self.tree.SelectItem(self.value)
def SetStringValue(self, value):
# this assumes that item strings are unique...
root = self.tree.GetRootItem()
if not root:
return
found = self.FindItem(root, value)
if found:
self.value = found
self.tree.SelectItem(found)
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
return wx.Size(minWidth, min(200, maxHeight))
# helpers
def FindItem(self, parentItem, text):
item, cookie = self.tree.GetFirstChild(parentItem)
while item:
if self.tree.GetItemText(item) == text:
return item
if self.tree.ItemHasChildren(item):
item = self.FindItem(item, text)
item, cookie = self.tree.GetNextChild(parentItem, cookie)
return wx.TreeItemId();
def AddItem(self, value, parent=None):
if not parent:
root = self.tree.GetRootItem()
if not root:
root = self.tree.AddRoot("<hidden root>")
parent = root
item = self.tree.AppendItem(parent, value)
return item
def OnMotion(self, evt):
# have the selection follow the mouse, like in a real combobox
item, flags = self.tree.HitTest(evt.GetPosition())
if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
self.tree.SelectItem(item)
self.curitem = item
evt.Skip()
def OnLeftDown(self, evt):
# do the combobox selection
item, flags = self.tree.HitTest(evt.GetPosition())
if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
self.curitem = item
self.value = item
self.Dismiss()
evt.Skip()
#----------------------------------------------------------------------
# Here we subclass wx.combo.ComboCtrl to do some custom popup animation
CUSTOM_COMBOBOX_ANIMATION_DURATION = 200
class ComboCtrlWithCustomPopupAnim(wx.combo.ComboCtrl):
def __init__(self, *args, **kw):
wx.combo.ComboCtrl.__init__(self, *args, **kw)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.aniTimer = wx.Timer(self)
def AnimateShow(self, rect, flags):
self.aniStart = wx.GetLocalTimeMillis()
self.aniRect = wx.Rect(*rect)
self.aniFlags = flags
dc = wx.ScreenDC()
bmp = wx.EmptyBitmap(rect.width, rect.height)
mdc = wx.MemoryDC(bmp)
if "wxMac" in wx.PlatformInfo:
pass
else:
mdc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
del mdc
self.aniBackBitmap = bmp
self.aniTimer.Start(10, wx.TIMER_CONTINUOUS)
self.OnTimer(None)
return False
def OnTimer(self, evt):
stopTimer = False
popup = self.GetPopupControl().GetControl()
rect = self.aniRect
dc = wx.ScreenDC()
if self.IsPopupWindowState(self.Hidden):
stopTimer = True
else:
pos = wx.GetLocalTimeMillis() - self.aniStart
if pos < CUSTOM_COMBOBOX_ANIMATION_DURATION:
# Actual animation happens here
width = rect.width
height = rect.height
center_x = rect.x + (width/2)
center_y = rect.y + (height/2)
dc.SetPen( wx.BLACK_PEN )
dc.SetBrush( wx.TRANSPARENT_BRUSH )
w = (((pos*256)/CUSTOM_COMBOBOX_ANIMATION_DURATION)*width)/256
ratio = float(w) / float(width)
h = int(height * ratio)
dc.DrawBitmap( self.aniBackBitmap, rect.x, rect.y )
dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h )
else:
stopTimer = True
if stopTimer:
dc.DrawBitmap( self.aniBackBitmap, rect.x, rect.y )
popup.Move( (0, 0) )
self.aniTimer.Stop()
self.DoShowPopup( rect, self.aniFlags )
#----------------------------------------------------------------------
# FileSelectorCombo displays a dialog instead of a popup control, it
# also uses a custom bitmap on the combo button.
class FileSelectorCombo(wx.combo.ComboCtrl):
def __init__(self, *args, **kw):
wx.combo.ComboCtrl.__init__(self, *args, **kw)
# make a custom bitmap showing "..."
bw, bh = 14, 16
bmp = wx.EmptyBitmap(bw,bh)
dc = wx.MemoryDC(bmp)
# clear to a specific background colour
bgcolor = wx.Colour(255,254,255)
dc.SetBackground(wx.Brush(bgcolor))
dc.Clear()
# draw the label onto the bitmap
label = "..."
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.FONTWEIGHT_BOLD)
dc.SetFont(font)
tw,th = dc.GetTextExtent(label)
dc.DrawText(label, (bw-tw)/2, (bw-tw)/2)
del dc
# now apply a mask using the bgcolor
bmp.SetMaskColour(bgcolor)
# and tell the ComboCtrl to use it
self.SetButtonBitmaps(bmp, True)
self.Bind(wx.EVT_TEXT, self.onText)
def onText(self, evt):
print 'EVT_TEXT:', self.GetValue()
evt.Skip()
# Overridden from ComboCtrl, called when the combo button is clicked
def OnButtonClick(self):
path = ""
name = ""
if self.GetValue():
path, name = os.path.split(self.GetValue())
dlg = wx.FileDialog(self, "Choose File", path, name,
"All files (*.*)|*.*", wx.FD_OPEN)
if dlg.ShowModal() == wx.ID_OK:
self.SetValue(dlg.GetPath())
dlg.Destroy()
self.SetFocus()
# Overridden from ComboCtrl to avoid assert since there is no ComboPopup
def DoSetPopupControl(self, popup):
pass
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
fgs = wx.FlexGridSizer(cols=3, hgap=10, vgap=10)
cc = self.MakeLCCombo(log=self.log)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, "wx.ComboCtrl with a ListCtrl popup"))
cc = self.MakeLCCombo(style=wx.CB_READONLY)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, " Read-only"))
cc = self.MakeLCCombo()
cc.SetButtonPosition(side=wx.LEFT)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, " Button on the left"))
cc = self.MakeLCCombo()
cc.SetPopupMaxHeight(250)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, " Max height of popup set"))
cc = wx.combo.ComboCtrl(self, size=(250,-1))
tcp = TreeCtrlComboPopup()
cc.SetPopupControl(tcp)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, "TreeCtrl popup"))
# add some items to the tree
for i in range(5):
item = tcp.AddItem('Item %d' % (i+1))
for j in range(15):
tcp.AddItem('Subitem %d-%d' % (i+1, j+1), parent=item)
cc = ComboCtrlWithCustomPopupAnim(self, size=(250, -1))
popup = ListCtrlComboPopup()
cc.SetPopupMaxHeight(150)
cc.SetPopupControl(popup)
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, "Custom popup animation"))
for word in "How cool was that!? Way COOL!".split():
popup.AddItem(word)
if "wxMac" in wx.PlatformInfo:
cc.SetValue("Sorry, animation not working yet on Mac")
cc = FileSelectorCombo(self, size=(250, -1))
fgs.Add(cc)
fgs.Add((10,10))
fgs.Add(wx.StaticText(self, -1, "Custom popup action, and custom button bitmap"))
box = wx.BoxSizer()
box.Add(fgs, 1, wx.EXPAND|wx.ALL, 20)
self.SetSizer(box)
def MakeLCCombo(self, log=None, style=0):
# Create a ComboCtrl
cc = wx.combo.ComboCtrl(self, style=style, size=(250,-1))
# Create a Popup
popup = ListCtrlComboPopup(log)
# Associate them with each other. This also triggers the
# creation of the ListCtrl.
cc.SetPopupControl(popup)
# Add some items to the listctrl.
for x in range(75):
popup.AddItem("Item-%02d" % x)
return cc
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.combo.ComboCtrl</center></h2>
A combo control is a generic combobox that allows a totally custom
popup. In addition it has other customization features. For instance,
position and size of the dropdown button can be changed.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

69
demo/ComboTreeBox.py Normal file
View File

@@ -0,0 +1,69 @@
import wx
from wx.lib.combotreebox import ComboTreeBox
#---------------------------------------------------------------------------
class TestComboTreeBox(wx.Panel):
def __init__(self, parent, log):
super(TestComboTreeBox, self).__init__(parent)
self.log = log
panelSizer = wx.FlexGridSizer(cols=2)
panelSizer.AddGrowableCol(1)
for style, labelText in [(0, 'Default style:'),
(wx.CB_READONLY, 'Read-only style:')]:
label = wx.StaticText(self, label=labelText)
panelSizer.Add(label, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL,
border=5)
comboBox = self._createComboTreeBox(style)
panelSizer.Add(comboBox, flag=wx.EXPAND|wx.ALL, border=5)
self.SetSizerAndFit(panelSizer)
def _createComboTreeBox(self, style):
comboBox = ComboTreeBox(self, style=style)
self._bindEventHandlers(comboBox)
for i in range(5):
child = comboBox.Append('Item %d'%i)
for j in range(5):
grandChild = comboBox.Append('Item %d.%d'%(i,j), child)
for k in range(5):
comboBox.Append('Item %d.%d.%d'%(i,j, k), grandChild)
return comboBox
def _bindEventHandlers(self, comboBox):
for eventType, handler in [(wx.EVT_COMBOBOX, self.OnItemSelected),
(wx.EVT_TEXT, self.OnItemEntered)]:
comboBox.Bind(eventType, handler)
def OnItemSelected(self, event):
self.log.WriteText('You selected: %s\n'%event.GetString())
event.Skip()
def OnItemEntered(self, event):
self.log.WriteText('You entered: %s\n'%event.GetString())
event.Skip()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestComboTreeBox(nb, log)
return win
#---------------------------------------------------------------------------
overview = wx.lib.combotreebox.__doc__
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys, os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

47
demo/CommandLinkButton.py Normal file
View File

@@ -0,0 +1,47 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
cmd = wx.CommandLinkButton(self, -1,
"wx.CommandLinkButton",
"""\
This type of button includes both a main label and a 'note' that is meant to
contain a description of what the button does or what it is used for. On
Windows 7 it is a new native widget type, on the other platforms it is
implemented generically.""",
pos=(25,25))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.CommandLinkButton</center></h2>
This type of button includes both a main label and a 'note' that is meant to
contain a description of what the button does or what it is used for. On
Windows 7 it is a new native widget type, on the other platforms it is
implemented generically.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

111
demo/ContextHelp.py Normal file
View File

@@ -0,0 +1,111 @@
import wx
#----------------------------------------------------------------------
# We first have to set an application-wide help provider. Normally you
# would do this in your app's OnInit or in other startup code...
provider = wx.SimpleHelpProvider()
wx.HelpProvider_Set(provider)
# This panel is chock full of controls about which we can demonstrate the
# help system.
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
# This help text, set for the panel itself, will be used if context
# sensitive help cannot be found for any particular control.
self.SetHelpText("This is a wx.Panel.")
sizer = wx.BoxSizer(wx.VERTICAL)
# Init the context help button.
# And even include help text about the help button :-)
cBtn = wx.ContextHelpButton(self)
cBtn.SetHelpText("wx.ContextHelpButton")
cBtnText = wx.StaticText(self, -1,
"This is a wx.ContextHelpButton. Clicking it puts the\n"
"app into context sensitive help mode."
)
# Yes, even static text can have help text associated with it :-)
cBtnText.SetHelpText("Some helpful text...")
s = wx.BoxSizer(wx.HORIZONTAL)
s.Add(cBtn, 0, wx.ALL, 5)
s.Add(cBtnText, 0, wx.ALL, 5)
sizer.Add((20,20))
sizer.Add(s)
# A text control with help text.
text = wx.TextCtrl(self, -1, "Each sub-window can have its own help message",
size=(240, 60), style=wx.TE_MULTILINE)
text.SetHelpText("This is my very own help message. This is a really long long long long long long long long long long long long long long long long long long long long message!")
sizer.Add((20,20))
sizer.Add(text)
# Same thing, but this time to demonstrate how the help event can be
# intercepted.
text = wx.TextCtrl(self, -1, "You can also intercept the help event if you like. Watch the log window when you click here...",
size=(240, 60), style = wx.TE_MULTILINE)
text.SetHelpText("Yet another context help message.")
sizer.Add((20,20))
sizer.Add(text)
text.Bind(wx.EVT_HELP, self.OnCtxHelp, text)
text = wx.TextCtrl(self, -1, "This one displays the tip itself...",
size=(240, 60), style = wx.TE_MULTILINE)
sizer.Add((20,20))
sizer.Add(text)
text.Bind(wx.EVT_HELP, self.OnCtxHelp2, text)
border = wx.BoxSizer(wx.VERTICAL)
border.Add(sizer, 0, wx.ALL, 25)
self.SetAutoLayout(True)
self.SetSizer(border)
self.Layout()
# On the second text control above, we intercept the help event. This is where
# we process it. Anything could happen here. In this case we're just printing
# some stuff about it, then passing it on, at which point we see the help tip.
def OnCtxHelp(self, evt):
self.log.write("OnCtxHelp: %s" % evt)
evt.Skip()
# On the third text control above, we intercept the help event.
# Here, we print a note about it, generate our own tip window, and,
# unlike last time, we don't pass it on to the underlying provider.
def OnCtxHelp2(self, evt):
self.log.write("OnCtxHelp2: %s\n" % evt)
tip = wx.TipWindow(self, "This is a wx.TipWindow")
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """
This demo shows how to incorporate Context Sensitive
help into your application using the wx.SimpleHelpProvider class.
"""
#----------------------------------------------------------------------
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

139
demo/Cursor.py Normal file
View File

@@ -0,0 +1,139 @@
import wx
import images
#----------------------------------------------------------------------
CUSTOMID = 1111
cursors = {
"wx.CURSOR_ARROW" : wx.CURSOR_ARROW,
"wx.CURSOR_RIGHT_ARROW" : wx.CURSOR_RIGHT_ARROW,
"wx.CURSOR_BULLSEYE" : wx.CURSOR_BULLSEYE,
"wx.CURSOR_CHAR" : wx.CURSOR_CHAR,
"wx.CURSOR_CROSS" : wx.CURSOR_CROSS,
"wx.CURSOR_HAND" : wx.CURSOR_HAND,
"wx.CURSOR_IBEAM" : wx.CURSOR_IBEAM,
"wx.CURSOR_LEFT_BUTTON" : wx.CURSOR_LEFT_BUTTON,
"wx.CURSOR_MAGNIFIER" : wx.CURSOR_MAGNIFIER,
"wx.CURSOR_MIDDLE_BUTTON" : wx.CURSOR_MIDDLE_BUTTON,
"wx.CURSOR_NO_ENTRY" : wx.CURSOR_NO_ENTRY,
"wx.CURSOR_PAINT_BRUSH" : wx.CURSOR_PAINT_BRUSH,
"wx.CURSOR_PENCIL" : wx.CURSOR_PENCIL,
"wx.CURSOR_POINT_LEFT" : wx.CURSOR_POINT_LEFT,
"wx.CURSOR_POINT_RIGHT" : wx.CURSOR_POINT_RIGHT,
"wx.CURSOR_QUESTION_ARROW" : wx.CURSOR_QUESTION_ARROW,
"wx.CURSOR_RIGHT_BUTTON" : wx.CURSOR_RIGHT_BUTTON,
"wx.CURSOR_SIZENESW" : wx.CURSOR_SIZENESW,
"wx.CURSOR_SIZENS" : wx.CURSOR_SIZENS,
"wx.CURSOR_SIZENWSE" : wx.CURSOR_SIZENWSE,
"wx.CURSOR_SIZEWE" : wx.CURSOR_SIZEWE,
"wx.CURSOR_SIZING" : wx.CURSOR_SIZING,
"wx.CURSOR_SPRAYCAN" : wx.CURSOR_SPRAYCAN,
"wx.CURSOR_WAIT" : wx.CURSOR_WAIT,
"wx.CURSOR_WATCH" : wx.CURSOR_WATCH,
"wx.CURSOR_BLANK" : wx.CURSOR_BLANK,
"wx.CURSOR_DEFAULT" : wx.CURSOR_DEFAULT,
"wx.CURSOR_COPY_ARROW" : wx.CURSOR_COPY_ARROW,
"wx.CURSOR_ARROWWAIT" : wx.CURSOR_ARROWWAIT,
"zz [custom cursor]" : CUSTOMID,
}
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
# create a list of choices from the dictionary above
choices = cursors.keys()
choices.sort()
# create the controls
self.cb = wx.ComboBox(self, -1, "wx.CURSOR_DEFAULT", choices=choices,
style=wx.CB_READONLY)
self.tx = wx.StaticText(self, -1,
"This sample allows you to see all the stock cursors \n"
"available to wxPython. Simply select a name from the \n"
"wx.Choice and then move the mouse into the window \n"
"below to see the cursor. NOTE: not all stock cursors \n"
"have a specific representaion on all platforms.")
self.win = wx.Window(self, -1, size=(200,200), style=wx.SIMPLE_BORDER)
self.win.SetBackgroundColour("white")
# bind an event or two
self.Bind(wx.EVT_COMBOBOX, self.OnChooseCursor, self.cb)
self.win.Bind(wx.EVT_LEFT_DOWN, self.OnDrawDot)
# Setup the layout
gbs = wx.GridBagSizer()
gbs.Add(self.cb, (2,1))
gbs.Add(self.tx, (2,3))
gbs.Add(self.win, (5,0), (1, 6), wx.ALIGN_CENTER)
self.SetSizer(gbs)
def OnChooseCursor(self, evt):
# clear the dots
self.win.Refresh()
choice = self.cb.GetStringSelection()
self.log.write("Selecting the %s cursor\n" % choice)
cnum = cursors[choice]
if cnum == CUSTOMID:
image = images.Pointy.GetImage()
# since this image didn't come from a .cur file, tell it where the hotspot is
image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 1)
image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 1)
# make the image into a cursor
cursor = wx.CursorFromImage(image)
else:
# create one of the stock (built-in) cursors
cursor = wx.StockCursor(cnum)
# set the cursor for the window
self.win.SetCursor(cursor)
def OnDrawDot(self, evt):
# Draw a dot so the user can see where the hotspot is
dc = wx.ClientDC(self.win)
dc.SetPen(wx.Pen("RED"))
dc.SetBrush(wx.Brush("RED"))
pos = evt.GetPosition()
dc.DrawCircle(pos.x, pos.y, 4)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.Cursor</center></h2>
This demo shows the stock mouse cursors that are available to wxPython.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

347
demo/CustomDragAndDrop.py Normal file
View File

@@ -0,0 +1,347 @@
import cPickle
import wx
#----------------------------------------------------------------------
class DoodlePad(wx.Window):
def __init__(self, parent, log):
wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
self.log = log
self.SetBackgroundColour(wx.WHITE)
self.lines = []
self.x = self.y = 0
self.SetMode("Draw")
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def SetMode(self, mode):
self.mode = mode
if self.mode == "Draw":
self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
else:
self.SetCursor(wx.STANDARD_CURSOR)
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.DrawSavedLines(dc)
def DrawSavedLines(self, dc):
dc.BeginDrawing()
dc.SetPen(wx.Pen(wx.BLUE, 3))
for line in self.lines:
for coords in line:
dc.DrawLine(*coords)
dc.EndDrawing()
def OnLeftDown(self, event):
if self.mode == "Drag":
self.StartDragOpperation()
elif self.mode == "Draw":
self.curLine = []
self.x, self.y = event.GetPositionTuple()
self.CaptureMouse()
else:
wx.Bell()
self.log.write("unknown mode!\n")
def OnLeftUp(self, event):
if self.HasCapture():
self.lines.append(self.curLine)
self.curLine = []
self.ReleaseMouse()
def OnRightUp(self, event):
self.lines = []
self.Refresh()
def OnMotion(self, event):
if self.HasCapture() and event.Dragging() and not self.mode == "Drag":
dc = wx.ClientDC(self)
dc.BeginDrawing()
dc.SetPen(wx.Pen(wx.BLUE, 3))
coords = (self.x, self.y) + event.GetPositionTuple()
self.curLine.append(coords)
dc.DrawLine(*coords)
self.x, self.y = event.GetPositionTuple()
dc.EndDrawing()
def StartDragOpperation(self):
# pickle the lines list
linesdata = cPickle.dumps(self.lines, 1)
# create our own data format and use it in a
# custom data object
ldata = wx.CustomDataObject("DoodleLines")
ldata.SetData(linesdata)
# Also create a Bitmap version of the drawing
size = self.GetSize()
bmp = wx.EmptyBitmap(size.width, size.height)
dc = wx.MemoryDC()
dc.SelectObject(bmp)
dc.SetBackground(wx.WHITE_BRUSH)
dc.Clear()
self.DrawSavedLines(dc)
dc.SelectObject(wx.NullBitmap)
# Now make a data object for the bitmap and also a composite
# data object holding both of the others.
bdata = wx.BitmapDataObject(bmp)
data = wx.DataObjectComposite()
data.Add(ldata)
data.Add(bdata)
# And finally, create the drop source and begin the drag
# and drop opperation
dropSource = wx.DropSource(self)
dropSource.SetData(data)
self.log.WriteText("Begining DragDrop\n")
result = dropSource.DoDragDrop(wx.Drag_AllowMove)
self.log.WriteText("DragDrop completed: %d\n" % result)
if result == wx.DragMove:
self.lines = []
self.Refresh()
#----------------------------------------------------------------------
class DoodleDropTarget(wx.DropTarget):
def __init__(self, window, log):
wx.DropTarget.__init__(self)
self.log = log
self.dv = window
# specify the type of data we will accept
self.data = wx.CustomDataObject("DoodleLines")
self.SetDataObject(self.data)
# some virtual methods that track the progress of the drag
def OnEnter(self, x, y, d):
self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
return d
def OnLeave(self):
self.log.WriteText("OnLeave\n")
def OnDrop(self, x, y):
self.log.WriteText("OnDrop: %d %d\n" % (x, y))
return True
def OnDragOver(self, x, y, d):
#self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d))
# The value returned here tells the source what kind of visual
# feedback to give. For example, if wxDragCopy is returned then
# only the copy cursor will be shown, even if the source allows
# moves. You can use the passed in (x,y) to determine what kind
# of feedback to give. In this case we return the suggested value
# which is based on whether the Ctrl key is pressed.
return d
# Called when OnDrop returns True. We need to get the data and
# do something with it.
def OnData(self, x, y, d):
self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
# copy the data from the drag source to our data object
if self.GetData():
# convert it back to a list of lines and give it to the viewer
linesdata = self.data.GetData()
lines = cPickle.loads(linesdata)
self.dv.SetLines(lines)
# what is returned signals the source what to do
# with the original data (move, copy, etc.) In this
# case we just return the suggested value given to us.
return d
class DoodleViewer(wx.Window):
def __init__(self, parent, log):
wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
self.log = log
self.SetBackgroundColour(wx.WHITE)
self.lines = []
self.x = self.y = 0
dt = DoodleDropTarget(self, log)
self.SetDropTarget(dt)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def SetLines(self, lines):
self.lines = lines
self.Refresh()
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.DrawSavedLines(dc)
def DrawSavedLines(self, dc):
dc.BeginDrawing()
dc.SetPen(wx.Pen(wx.RED, 3))
for line in self.lines:
for coords in line:
dc.DrawLine(*coords)
dc.EndDrawing()
#----------------------------------------------------------------------
class CustomDnDPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
# Make the controls
text1 = wx.StaticText(self, -1,
"Draw a little picture in this window\n"
"then switch the mode below and drag the\n"
"picture to the lower window or to another\n"
"application that accepts Bitmaps as a\n"
"drop target.\n"
)
rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP)
rb1.SetValue(True)
rb2 = wx.RadioButton(self, -1, "Drag")
rb2.SetValue(False)
text2 = wx.StaticText(self, -1,
"The lower window is accepting a\n"
"custom data type that is a pickled\n"
"Python list of lines data.")
self.pad = DoodlePad(self, log)
view = DoodleViewer(self, log)
# put them in sizers
sizer = wx.BoxSizer(wx.HORIZONTAL)
box = wx.BoxSizer(wx.VERTICAL)
rbox = wx.BoxSizer(wx.HORIZONTAL)
rbox.Add(rb1)
rbox.Add(rb2)
box.Add(text1, 0, wx.ALL, 10)
box.Add(rbox, 0, wx.ALIGN_CENTER)
box.Add((10,90))
box.Add(text2, 0, wx.ALL, 10)
sizer.Add(box)
dndsizer = wx.BoxSizer(wx.VERTICAL)
dndsizer.Add(self.pad, 1, wx.EXPAND|wx.ALL, 5)
dndsizer.Add(view, 1, wx.EXPAND|wx.ALL, 5)
sizer.Add(dndsizer, 1, wx.EXPAND)
self.SetAutoLayout(True)
self.SetSizer(sizer)
# Events
self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb1)
self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb2)
def OnRadioButton(self, evt):
rb = self.FindWindowById(evt.GetId())
self.pad.SetMode(rb.GetLabel())
#----------------------------------------------------------------------
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.SetAutoLayout(True)
sizer = wx.BoxSizer(wx.VERTICAL)
msg = "Custom Drag-And-Drop"
text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
text.SetLabel(msg)
w,h = text.GetTextExtent(msg)
text.SetSize(wx.Size(w,h+1))
text.SetForegroundColour(wx.BLUE)
sizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
#win = TestPanel(nb, log)
win = CustomDnDPanel(nb, log)
return win
if __name__ == '__main__':
import sys
class DummyLog:
def WriteText(self, text):
sys.stdout.write(text)
class TestApp(wx.App):
def OnInit(self):
self.MakeFrame()
return True
def MakeFrame(self, event=None):
frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400))
menu = wx.Menu()
item = menu.Append(-1, "Window")
mb = wx.MenuBar()
mb.Append(menu, "New")
frame.SetMenuBar(mb)
frame.Bind(wx.EVT_MENU, self.MakeFrame, item)
panel = TestPanel(frame, DummyLog())
frame.Show(True)
self.SetTopWindow(frame)
#----------------------------------------------------------------------
app = TestApp(0)
app.MainLoop()
#----------------------------------------------------------------------
overview = """<html><body>
This demo shows Drag and Drop using a custom data type and a custom
data object. A type called "DoodleLines" is created and a Python
Pickle of a list is actually transfered in the drag and drop
opperation.
A second data object is also created containing a bitmap of the image
and is made available to any drop target that accepts bitmaps, such as
MS Word.
The two data objects are combined in a wx.DataObjectComposite and the
rest is handled by the framework.
</body></html>
"""

180
demo/DVC_CustomRenderer.py Normal file
View File

@@ -0,0 +1,180 @@
import wx
import wx.dataview as dv
#----------------------------------------------------------------------
class MyCustomRenderer(dv.PyDataViewCustomRenderer):
def __init__(self, log, *args, **kw):
dv.PyDataViewCustomRenderer.__init__(self, *args, **kw)
self.log = log
self.value = None
def SetValue(self, value):
#self.log.write('SetValue: %s' % value)
self.value = value
return True
def GetValue(self):
#self.log.write('GetValue')
return self.value
def GetSize(self):
# Return the size needed to display the value. The renderer
# has a helper function we can use for measuring text that is
# aware of any custom attributes that may have been set for
# this item.
return self.GetTextExtent(self.value)
def Render(self, rect, dc, state):
if state != 0:
self.log.write('Render: %s, %d' % (rect, state))
if not state & dv.DATAVIEW_CELL_SELECTED:
# we'll draw a shaded background to see if the rect correctly
# fills the cell
dc.SetBrush(wx.Brush('light grey'))
dc.SetPen(wx.TRANSPARENT_PEN)
rect.Deflate(1, 1)
dc.DrawRoundedRectangleRect(rect, 2)
# And then finish up with this helper function that draws the
# text for us, dealing with alignment, font and color
# attributes, etc
self.RenderText(self.value,
4, # x-offset, to compensate for the rounded rectangles
rect,
dc,
state # wxDataViewCellRenderState flags
)
# The HasEditorCtrl, CreateEditorCtrl and GetValueFromEditorCtrl
# methods need to be implemented if this renderer is going to
# support in-place editing of the cell value, otherwise they can
# be omitted.
def HasEditorCtrl(self):
self.log.write('HasEditorCtrl')
return True
def CreateEditorCtrl(self, parent, labelRect, value):
self.log.write('CreateEditorCtrl: %s' % labelRect)
ctrl = wx.TextCtrl(parent,
value=value,
pos=labelRect.Position,
size=labelRect.Size)
# select the text and put the caret at the end
ctrl.SetInsertionPointEnd()
ctrl.SelectAll()
return ctrl
def GetValueFromEditorCtrl(self, editor):
self.log.write('GetValueFromEditorCtrl: %s' % editor)
value = editor.GetValue()
return value
# The LeftClick and Activate methods serve as notifications
# letting you know that the user has either clicked or
# double-clicked on an item. Implementing them in your renderer
# is optional.
def LeftClick(self, pos, cellRect, model, item, col):
self.log.write('LeftClick')
return False
def Activate(self, cellRect, model, item, col):
self.log.write('Activate')
return False
#----------------------------------------------------------------------
# To help focus this sammple on the custom renderer, we'll reuse the
# model class from another sample.
from DVC_IndexListModel import TestModel
class TestPanel(wx.Panel):
def __init__(self, parent, log, model=None, data=None):
self.log = log
wx.Panel.__init__(self, parent, -1)
# Create a dataview control
self.dvc = dv.DataViewCtrl(self,
style=wx.BORDER_THEME
| dv.DV_ROW_LINES
#| dv.DV_HORIZ_RULES
| dv.DV_VERT_RULES
| dv.DV_MULTIPLE
)
# Create an instance of the model
if model is None:
self.model = TestModel(data, log)
else:
self.model = model
self.dvc.AssociateModel(self.model)
# Now we create some columns.
c0 = self.dvc.AppendTextColumn("Id", 0, width=40)
c0.Alignment = wx.ALIGN_RIGHT
c0.MinWidth = 40
# We'll use our custom renderer for these columns
for title, col, width in [ ('Artist', 1, 170),
('Title', 2, 260),
('Genre', 3, 80)]:
renderer = MyCustomRenderer(self.log, mode=dv.DATAVIEW_CELL_EDITABLE)
#renderer.SetMode(dv.DATAVIEW_CELL_EDITABLE)
column = dv.DataViewColumn(title, renderer, col, width=width)
column.Alignment = wx.ALIGN_LEFT
self.dvc.AppendColumn(column)
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.dvc, 1, wx.EXPAND)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
# Get the data from the ListCtrl sample to play with, converting it
# from a dictionary to a list of lists, including the dictionary key
# as the first element of each sublist.
import ListCtrl
musicdata = ListCtrl.musicdata.items()
musicdata.sort()
musicdata = [[str(k)] + list(v) for k,v in musicdata]
win = TestPanel(nb, log, data=musicdata)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DemoName</center></h2>
Say something nice here
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

353
demo/DVC_DataViewModel.py Normal file
View File

@@ -0,0 +1,353 @@
import wx
import wx.dataview as dv
import images
import random
#----------------------------------------------------------------------
def makeBlank(self):
# Just a little helper function to make an empty image for our
# model to use.
empty = wx.EmptyBitmap(16,16,32)
dc = wx.MemoryDC(empty)
dc.SetBackground(wx.Brush((0,0,0,0)))
dc.Clear()
del dc
return empty
#----------------------------------------------------------------------
# We'll use instaces of these classes to hold our music data. Items in the
# tree will get associated back to the coresponding Song or Genre object.
class Song(object):
def __init__(self, id, artist, title, genre):
self.id = id
self.artist = artist
self.title = title
self.genre = genre
self.like = False
# get a random date value
d = random.choice(range(27))+1
m = random.choice(range(12))
y = random.choice(range(1980, 2005))
self.date = wx.DateTimeFromDMY(d,m,y)
def __repr__(self):
return 'Song: %s-%s' % (self.artist, self.title)
class Genre(object):
def __init__(self, name):
self.name = name
self.songs = []
def __repr__(self):
return 'Genre: ' + self.name
#----------------------------------------------------------------------
# This model acts as a bridge between the DataViewCtrl and the music data, and
# organizes it hierarchically as a collection of Genres, each of which is a
# collection of songs. We derive the class from PyDataViewModel, which knows
# how to reflect the C++ virtual methods to the Python methods in the derived
# class.
# This model provides these data columns:
#
# 0. Genre: string
# 1. Artist: string
# 2. Title: string
# 3. id: integer
# 4. Aquired: date
# 5. Liked: bool
#
class MyTreeListModel(dv.PyDataViewModel):
def __init__(self, data, log):
dv.PyDataViewModel.__init__(self)
self.data = data
self.log = log
# The objmapper is an instance of DataViewItemObjectMapper and is used
# to help associate Python objects with DataViewItem objects. Normally
# a dictionary is used so any Python object can be used as data nodes.
# If the data nodes are weak-referencable then the objmapper can use a
# WeakValueDictionary instead. Each PyDataViewModel automagically has
# an instance of DataViewItemObjectMapper preassigned. This
# self.objmapper is used by the self.ObjectToItem and
# self.ItemToObject methods used below.
self.objmapper.UseWeakRefs(True)
# Report how many columns this model provides data for.
def GetColumnCount(self):
return 6
# Map the data column numbers to the data type
def GetColumnType(self, col):
mapper = { 0 : 'string',
1 : 'string',
2 : 'string',
3.: 'string', # the real value is an int, but the renderer should convert it okay
4 : 'datetime',
5 : 'bool',
}
return mapper[col]
def GetChildren(self, parent, children):
# The view calls this method to find the children of any node in the
# control. There is an implicit hidden root node, and the top level
# item(s) should be reported as children of this node. A List view
# simply provides all items as children of this hidden root. A Tree
# view adds additional items as children of the other items, as needed,
# to provide the tree hierachy.
##self.log.write("GetChildren\n")
# If the parent item is invalid then it represents the hidden root
# item, so we'll use the genre objects as its children and they will
# end up being the collection of visible roots in our tree.
if not parent:
for genre in self.data:
children.append(self.ObjectToItem(genre))
return len(self.data)
# Otherwise we'll fetch the python object associated with the parent
# item and make DV items for each of it's child objects.
node = self.ItemToObject(parent)
if isinstance(node, Genre):
for song in node.songs:
children.append(self.ObjectToItem(song))
return len(node.songs)
return 0
def IsContainer(self, item):
# Return True if the item has children, False otherwise.
##self.log.write("IsContainer\n")
# The hidden root is a container
if not item:
return True
# and in this model the genre objects are containers
node = self.ItemToObject(item)
if isinstance(node, Genre):
return True
# but everything else (the song objects) are not
return False
#def HasContainerColumns(self, item):
# self.log.write('HasContainerColumns\n')
# return True
def GetParent(self, item):
# Return the item which is this item's parent.
##self.log.write("GetParent\n")
if not item:
return dv.NullDataViewItem
node = self.ItemToObject(item)
if isinstance(node, Genre):
return dv.NullDataViewItem
elif isinstance(node, Song):
for g in self.data:
if g.name == node.genre:
return self.ObjectToItem(g)
def GetValue(self, item, col):
# Return the value to be displayed for this item and column. For this
# example we'll just pull the values from the data objects we
# associated with the items in GetChildren.
# Fetch the data object for this item.
node = self.ItemToObject(item)
if isinstance(node, Genre):
# We'll only use the first column for the Genre objects,
# for the other columns lets just return empty values
mapper = { 0 : node.name,
1 : "",
2 : "",
3 : "",
4 : wx.DateTimeFromTimeT(0), # TODO: There should be some way to indicate a null value...
5 : False,
}
return mapper[col]
elif isinstance(node, Song):
mapper = { 0 : node.genre,
1 : node.artist,
2 : node.title,
3 : node.id,
4 : node.date,
5 : node.like,
}
return mapper[col]
else:
raise RuntimeError("unknown node type")
def GetAttr(self, item, col, attr):
##self.log.write('GetAttr')
node = self.ItemToObject(item)
if isinstance(node, Genre):
attr.SetColour('blue')
attr.SetBold(True)
return True
return False
def SetValue(self, value, item, col):
self.log.write("SetValue: %s\n" % value)
# We're not allowing edits in column zero (see below) so we just need
# to deal with Song objects and cols 1 - 5
node = self.ItemToObject(item)
if isinstance(node, Song):
if col == 1:
node.artist = value
elif col == 2:
node.title = value
elif col == 3:
node.id = value
elif col == 4:
node.date = value
elif col == 5:
node.like = value
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log, data=None, model=None):
self.log = log
wx.Panel.__init__(self, parent, -1)
# Create a dataview control
self.dvc = dv.DataViewCtrl(self,
style=wx.BORDER_THEME
| dv.DV_ROW_LINES # nice alternating bg colors
#| dv.DV_HORIZ_RULES
| dv.DV_VERT_RULES
| dv.DV_MULTIPLE
)
# Create an instance of our model...
if model is None:
self.model = MyTreeListModel(data, log)
else:
self.model = model
# Tel the DVC to use the model
self.dvc.AssociateModel(self.model)
# Define the columns that we want in the view. Notice the
# parameter which tells the view which col in the data model to pull
# values from for each view column.
if 1:
self.tr = tr = dv.DataViewTextRenderer()
c0 = dv.DataViewColumn("Genre", # title
tr, # renderer
0, # data model column
width=80)
self.dvc.AppendColumn(c0)
else:
self.dvc.AppendTextColumn("Genre", 0, width=80)
c1 = self.dvc.AppendTextColumn("Artist", 1, width=170, mode=dv.DATAVIEW_CELL_EDITABLE)
c2 = self.dvc.AppendTextColumn("Title", 2, width=260, mode=dv.DATAVIEW_CELL_EDITABLE)
c3 = self.dvc.AppendDateColumn('Acquired', 4, width=100, mode=dv.DATAVIEW_CELL_ACTIVATABLE)
c4 = self.dvc.AppendToggleColumn('Like', 5, width=40, mode=dv.DATAVIEW_CELL_ACTIVATABLE)
# Notice how we pull the data from col 3, but this is the 6th col
# added to the DVC. The order of the view columns is not dependent on
# the order of the model columns at all.
c5 = self.dvc.AppendTextColumn("id", 3, width=40, mode=dv.DATAVIEW_CELL_EDITABLE)
c5.Alignment = wx.ALIGN_RIGHT
# Set some additional attributes for all the columns
for c in self.dvc.Columns:
c.Sortable = True
c.Reorderable = True
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.dvc, 1, wx.EXPAND)
b1 = wx.Button(self, label="New View", name="newView")
self.Bind(wx.EVT_BUTTON, self.OnNewView, b1)
self.Sizer.Add(b1, 0, wx.ALL, 5)
def OnNewView(self, evt):
f = wx.Frame(None, title="New view, shared model", size=(600,400))
TestPanel(f, self.log, model=self.model)
b = f.FindWindowByName("newView")
b.Disable()
f.Show()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
# Reuse the music data in the ListCtrl sample, and put it in a
# hierarchical structure so we can show it as a tree
import ListCtrl
musicdata = ListCtrl.musicdata.items()
musicdata.sort()
## For testing Unicode
#musicdata = {
# 1 : (u'BE \u662f', u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01', u"Rock \u662f"),
#}
#musicdata = musicdata.items()
# our data structure will be a collection of Genres, each of which is a
# collection of Songs
data = dict()
for key, val in musicdata:
song = Song(str(key), val[0], val[1], val[2])
genre = data.get(song.genre)
if genre is None:
genre = Genre(song.genre)
data[song.genre] = genre
genre.songs.append(song)
data = data.values()
# Finally create the test window
win = TestPanel(nb, log, data=data)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DataViewCtrl with custom DataViewModel</center></h2>
This sample shows how to derive a class from PyDataViewModel, implement a set
of hierarchical data objects and use the DataViewControl to view and
manipulate them.
<p> See the comments in the source for lots of details.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

253
demo/DVC_IndexListModel.py Normal file
View File

@@ -0,0 +1,253 @@
import wx
import wx.dataview as dv
#----------------------------------------------------------------------
# This model class provides the data to the view when it is asked for.
# Since it is a list-only model (no hierachical data) then it is able
# to be referenced by row rather than by item object, so in this way
# it is easier to comprehend and use than other model types. In this
# example we also provide a Compare function to assist with sorting of
# items in our model. Notice that the data items in the data model
# object don't ever change position due to a sort or column
# reordering. The view manages all of that and maps view rows and
# columns to the model's rows and columns as needed.
#
# For this example our data is stored in a simple list of lists. In
# real life you can use whatever you want or need to hold your data.
class TestModel(dv.PyDataViewIndexListModel):
def __init__(self, data, log):
dv.PyDataViewIndexListModel.__init__(self, len(data))
self.data = data
self.log = log
# All of our columns are strings. If the model or the renderers
# in the view are other types then that should be reflected here.
def GetColumnType(self, col):
return "string"
# This method is called to provide the data object for a
# particular row,col
def GetValueByRow(self, row, col):
return self.data[row][col]
# This method is called when the user edits a data item in the view.
def SetValueByRow(self, value, row, col):
self.log.write("SetValue: (%d,%d) %s\n" % (row, col, value))
self.data[row][col] = value
# Report how many columns this model provides data for.
def GetColumnCount(self):
return len(self.data[0])
# Report the number of rows in the model
def GetCount(self):
#self.log.write('GetCount')
return len(self.data)
# Called to check if non-standard attributes should be used in the
# cell at (row, col)
def GetAttrByRow(self, row, col, attr):
##self.log.write('GetAttrByRow: (%d, %d)' % (row, col))
if col == 3:
attr.SetColour('blue')
attr.SetBold(True)
return True
return False
# This is called to assist with sorting the data in the view. The
# first two args are instances of the DataViewItem class, so we
# need to convert them to row numbers with the GetRow method.
# Then it's just a matter of fetching the right values from our
# data set and comparing them. The return value is -1, 0, or 1,
# just like Python's cmp() function.
def Compare(self, item1, item2, col, ascending):
if not ascending: # swap sort order?
item2, item1 = item1, item2
row1 = self.GetRow(item1)
row2 = self.GetRow(item2)
if col == 0:
return cmp(int(self.data[row1][col]), int(self.data[row2][col]))
else:
return cmp(self.data[row1][col], self.data[row2][col])
def DeleteRows(self, rows):
# make a copy since we'll be sorting(mutating) the list
rows = list(rows)
# use reverse order so the indexes don't change as we remove items
rows.sort(reverse=True)
for row in rows:
# remove it from our data structure
del self.data[row]
# notify the view(s) using this model that it has been removed
self.RowDeleted(row)
def AddRow(self, value):
# update data structure
self.data.append(value)
# notify views
self.RowAppended()
class TestPanel(wx.Panel):
def __init__(self, parent, log, model=None, data=None):
self.log = log
wx.Panel.__init__(self, parent, -1)
# Create a dataview control
self.dvc = dv.DataViewCtrl(self,
style=wx.BORDER_THEME
| dv.DV_ROW_LINES # nice alternating bg colors
#| dv.DV_HORIZ_RULES
| dv.DV_VERT_RULES
| dv.DV_MULTIPLE
)
# Create an instance of our simple model...
if model is None:
self.model = TestModel(data, log)
else:
self.model = model
# ...and associate it with the dataview control. Models can
# be shared between multiple DataViewCtrls, so this does not
# assign ownership like many things in wx do. There is some
# internal reference counting happening so you don't really
# need to hold a reference to it either, but we do for this
# example so we can fiddle with the model from the widget
# inspector or whatever.
self.dvc.AssociateModel(self.model)
# Now we create some columns. The second parameter is the
# column number within the model that the DataViewColumn will
# fetch the data from. This means that you can have views
# using the same model that show different columns of data, or
# that they can be in a different order than in the model.
self.dvc.AppendTextColumn("Artist", 1, width=170, mode=dv.DATAVIEW_CELL_EDITABLE)
self.dvc.AppendTextColumn("Title", 2, width=260, mode=dv.DATAVIEW_CELL_EDITABLE)
self.dvc.AppendTextColumn("Genre", 3, width=80, mode=dv.DATAVIEW_CELL_EDITABLE)
# There are Prepend methods too, and also convenience methods
# for other data types but we are only using strings in this
# example. You can also create a DataViewColumn object
# yourself and then just use AppendColumn or PrependColumn.
c0 = self.dvc.PrependTextColumn("Id", 0, width=40)
# The DataViewColumn object is returned from the Append and
# Prepend methods, and we can modify some of it's properties
# like this.
c0.Alignment = wx.ALIGN_RIGHT
c0.Renderer.Alignment = wx.ALIGN_RIGHT
c0.MinWidth = 40
# Through the magic of Python we can also access the columns
# as a list via the Columns property. Here we'll mark them
# all as sortable and reorderable.
for c in self.dvc.Columns:
c.Sortable = True
c.Reorderable = True
# Let's change our minds and not let the first col be moved.
c0.Reorderable = False
# set the Sizer property (same as SetSizer)
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.dvc, 1, wx.EXPAND)
# Add some buttons to help out with the tests
b1 = wx.Button(self, label="New View", name="newView")
self.Bind(wx.EVT_BUTTON, self.OnNewView, b1)
b2 = wx.Button(self, label="Add Row")
self.Bind(wx.EVT_BUTTON, self.OnAddRow, b2)
b3 = wx.Button(self, label="Delete Row(s)")
self.Bind(wx.EVT_BUTTON, self.OnDeleteRows, b3)
btnbox = wx.BoxSizer(wx.HORIZONTAL)
btnbox.Add(b1, 0, wx.LEFT|wx.RIGHT, 5)
btnbox.Add(b2, 0, wx.LEFT|wx.RIGHT, 5)
btnbox.Add(b3, 0, wx.LEFT|wx.RIGHT, 5)
self.Sizer.Add(btnbox, 0, wx.TOP|wx.BOTTOM, 5)
# Bind some events so we can see what the DVC sends us
self.Bind(dv.EVT_DATAVIEW_ITEM_EDITING_DONE, self.OnEditingDone, self.dvc)
self.Bind(dv.EVT_DATAVIEW_ITEM_VALUE_CHANGED, self.OnValueChanged, self.dvc)
def OnNewView(self, evt):
f = wx.Frame(None, title="New view, shared model", size=(600,400))
TestPanel(f, self.log, self.model)
b = f.FindWindowByName("newView")
b.Disable()
f.Show()
def OnDeleteRows(self, evt):
# Remove the selected row(s) from the model. The model will take care
# of notifying the view (and any other observers) that the change has
# happened.
items = self.dvc.GetSelections()
rows = [self.model.GetRow(item) for item in items]
self.model.DeleteRows(rows)
def OnAddRow(self, evt):
# Add some bogus data to a new row in the model's data
id = len(self.model.data) + 1
value = [str(id),
'new artist %d' % id,
'new title %d' % id,
'genre %d' % id]
self.model.AddRow(value)
def OnEditingDone(self, evt):
self.log.write("OnEditingDone\n")
def OnValueChanged(self, evt):
self.log.write("OnValueChanged\n")
#----------------------------------------------------------------------
def runTest(frame, nb, log):
# Get the data from the ListCtrl sample to play with, converting it
# from a dictionary to a list of lists, including the dictionary key
# as the first element of each sublist.
import ListCtrl
musicdata = ListCtrl.musicdata.items()
musicdata.sort()
musicdata = [[str(k)] + list(v) for k,v in musicdata]
win = TestPanel(nb, log, data=musicdata)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DataViewCtrl with DataViewIndexListModel</center></h2>
This sample shows how to derive a class from PyDataViewIndexListModel and use
it to interface with a list of data items. (This model does not have any
hierarchical relationships in the data.)
<p> See the comments in the source for lots of details.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

68
demo/DVC_ListCtrl.py Normal file
View File

@@ -0,0 +1,68 @@
import wx
import wx.dataview as dv
#----------------------------------------------------------------------
# Reuse the music data in the ListCtrl sample
import ListCtrl
musicdata = ListCtrl.musicdata.items()
musicdata.sort()
musicdata = [[str(k)] + list(v) for k,v in musicdata]
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
# create the listctrl
self.dvlc = dvlc = dv.DataViewListCtrl(self)
# Give it some columns.
# The ID col we'll customize a bit:
dvlc.AppendTextColumn('id', width=40)
dvlc.AppendTextColumn('artist', width=170)
dvlc.AppendTextColumn('title', width=260)
dvlc.AppendTextColumn('genre', width=80)
# Load the data. Each item (row) is added as a sequence of values
# whose order matches the columns
for itemvalues in musicdata:
dvlc.AppendItem(itemvalues)
# Set the layout so the listctrl fills the panel
self.Sizer = wx.BoxSizer()
self.Sizer.Add(dvlc, 1, wx.EXPAND)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DataViewListCtrl</center></h2>
The DataViewListCtrl class is much like the traditional wx.ListCtrl in report
mode, in that it stores all items itself and all access to the data is through
the list ctrl's API. However it is derived from DataViewCtrl and uses a model
class internally, so it also has many of the benefits of the data view classes
available as well.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

75
demo/DVC_TreeCtrl.py Normal file
View File

@@ -0,0 +1,75 @@
import wx
import wx.dataview as dv
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent)
# create the treectrl
self.dvtc = dvtc = dv.DataViewTreeCtrl(self)
isz = (16,16)
il = wx.ImageList(*isz)
fldridx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER, wx.ART_OTHER, isz))
fldropenidx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER_OPEN, wx.ART_OTHER, isz))
fileidx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
dvtc.SetImageList(il)
self.root = dvtc.AppendContainer(dv.NullDataViewItem,
"The Root Item",
fldridx, fldropenidx)
for x in range(15):
child = dvtc.AppendContainer(self.root, "Item %d" % x,
fldridx, fldropenidx)
for y in range(5):
last = dvtc.AppendContainer(
child, "item %d-%s" % (x, chr(ord("a")+y)),
fldridx, fldropenidx)
for z in range(5):
item = dvtc.AppendItem(
last, "item %d-%s-%d" % (x, chr(ord("a")+y), z),
fileidx)
# Set the layout so the treectrl fills the panel
self.Sizer = wx.BoxSizer()
self.Sizer.Add(dvtc, 1, wx.EXPAND)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DataViewTreeCtrl</center></h2>
The DataViewTreeCtrl class is much like the traditional wx.TreeCtrl,
in that it stores all items itself and all access to the data is
through the tree ctrl's API. However it is derived from DataViewCtrl
and uses a model class internally, so it also has many of the benefits
of the data view classes available as well.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

64
demo/DatePickerCtrl.py Normal file
View File

@@ -0,0 +1,64 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
dpc = wx.DatePickerCtrl(self, size=(120,-1),
style = wx.DP_DROPDOWN
| wx.DP_SHOWCENTURY
| wx.DP_ALLOWNONE )
self.Bind(wx.EVT_DATE_CHANGED, self.OnDateChanged, dpc)
sizer.Add(dpc, 0, wx.ALL, 50)
# In some cases the widget used above will be a native date
# picker, so show the generic one too.
dpc = wx.GenericDatePickerCtrl(self, size=(120,-1),
style = wx.TAB_TRAVERSAL
| wx.DP_DROPDOWN
| wx.DP_SHOWCENTURY
| wx.DP_ALLOWNONE )
self.Bind(wx.EVT_DATE_CHANGED, self.OnDateChanged, dpc)
sizer.Add(dpc, 0, wx.LEFT, 50)
def OnDateChanged(self, evt):
self.log.write("OnDateChanged: %s\n" % evt.GetDate())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.DatePickerCtrl</center></h2>
This control allows the user to select a date. Unlike
wx.calendar.CalendarCtrl, which is a relatively big control,
wx.DatePickerCtrl is implemented as a small window showing the
currently selected date. The control can be edited using the keyboard,
and can also display a popup window for more user-friendly date
selection, depending on the styles used and the platform.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

224
demo/DelayedResult.py Normal file
View File

@@ -0,0 +1,224 @@
"""
This demonstrates a simple use of delayedresult: get/compute
something that takes a long time, without hanging the GUI while this
is taking place.
The top button runs a small GUI that uses wx.lib.delayedresult.startWorker
to wrap a long-running function into a separate thread. Just click
Get, and move the slider, and click Get and Abort a few times, and
observe that GUI responds. The key functions to look for in the code
are startWorker() and __handleResult().
The second button runs the same GUI, but without delayedresult. Click
Get: now the get/compute is taking place in main thread, so the GUI
does not respond to user actions until worker function returns, it's
not even possible to Abort.
"""
import wx
import wx.lib.delayedresult as delayedresult
class FrameSimpleDelayedBase(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
pnl = wx.Panel(self)
self.checkboxUseDelayed = wx.CheckBox(pnl, -1, "Using delayedresult")
self.buttonGet = wx.Button(pnl, -1, "Get")
self.buttonAbort = wx.Button(pnl, -1, "Abort")
self.slider = wx.Slider(pnl, -1, 0, 0, 10, size=(100,-1),
style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
self.textCtrlResult = wx.TextCtrl(pnl, -1, "", style=wx.TE_READONLY)
self.checkboxUseDelayed.SetValue(1)
self.checkboxUseDelayed.Enable(False)
self.buttonAbort.Enable(False)
vsizer = wx.BoxSizer(wx.VERTICAL)
hsizer = wx.BoxSizer(wx.HORIZONTAL)
vsizer.Add(self.checkboxUseDelayed, 0, wx.ALL, 10)
hsizer.Add(self.buttonGet, 0, wx.ALL, 5)
hsizer.Add(self.buttonAbort, 0, wx.ALL, 5)
hsizer.Add(self.slider, 0, wx.ALL, 5)
hsizer.Add(self.textCtrlResult, 0, wx.ALL, 5)
vsizer.Add(hsizer, 0, wx.ALL, 5)
pnl.SetSizer(vsizer)
vsizer.SetSizeHints(self)
self.Bind(wx.EVT_BUTTON, self.handleGet, self.buttonGet)
self.Bind(wx.EVT_BUTTON, self.handleAbort, self.buttonAbort)
class FrameSimpleDelayed(FrameSimpleDelayedBase):
"""This demos simplistic use of delayedresult module."""
def __init__(self, *args, **kwargs):
FrameSimpleDelayedBase.__init__(self, *args, **kwargs)
self.jobID = 0
self.abortEvent = delayedresult.AbortEvent()
self.Bind(wx.EVT_CLOSE, self.handleClose)
def setLog(self, log):
self.log = log
def handleClose(self, event):
"""Only needed because in demo, closing the window does not kill the
app, so worker thread continues and sends result to dead frame; normally
your app would exit so this would not happen."""
if self.buttonAbort.IsEnabled():
self.log( "Exiting: Aborting job %s" % self.jobID )
self.abortEvent.set()
self.Destroy()
def handleGet(self, event):
"""Compute result in separate thread, doesn't affect GUI response."""
self.buttonGet.Enable(False)
self.buttonAbort.Enable(True)
self.abortEvent.clear()
self.jobID += 1
self.log( "Starting job %s in producer thread: GUI remains responsive"
% self.jobID )
delayedresult.startWorker(self._resultConsumer, self._resultProducer,
wargs=(self.jobID,self.abortEvent), jobID=self.jobID)
def _resultProducer(self, jobID, abortEvent):
"""Pretend to be a complex worker function or something that takes
long time to run due to network access etc. GUI will freeze if this
method is not called in separate thread."""
import time
count = 0
while not abortEvent() and count < 50:
time.sleep(0.1)
count += 1
return jobID
def handleAbort(self, event):
"""Abort the result computation."""
self.log( "Aborting result for job %s" % self.jobID )
self.buttonGet.Enable(True)
self.buttonAbort.Enable(False)
self.abortEvent.set()
def _resultConsumer(self, delayedResult):
jobID = delayedResult.getJobID()
assert jobID == self.jobID
try:
result = delayedResult.get()
except Exception, exc:
self.log( "Result for job %s raised exception: %s" % (jobID, exc) )
return
# output result
self.log( "Got result for job %s: %s" % (jobID, result) )
self.textCtrlResult.SetValue(str(result))
# get ready for next job:
self.buttonGet.Enable(True)
self.buttonAbort.Enable(False)
class FrameSimpleDirect(FrameSimpleDelayedBase):
"""This does not use delayedresult so the GUI will freeze while
the GET is taking place."""
def __init__(self, *args, **kwargs):
self.jobID = 1
FrameSimpleDelayedBase.__init__(self, *args, **kwargs)
self.checkboxUseDelayed.SetValue(False)
def setLog(self, log):
self.log = log
def handleGet(self, event):
"""Use delayedresult, this will compute result in separate
thread, and will affect GUI response because a thread is not
used."""
self.buttonGet.Enable(False)
self.buttonAbort.Enable(True)
self.log( "Doing job %s without delayedresult (same as GUI thread): GUI hangs (for a while)" % self.jobID )
result = self._resultProducer(self.jobID)
self._resultConsumer( result )
def _resultProducer(self, jobID):
"""Pretend to be a complex worker function or something that takes
long time to run due to network access etc. GUI will freeze if this
method is not called in separate thread."""
import time
time.sleep(5)
return jobID
def handleAbort(self, event):
"""can never be called"""
pass
def _resultConsumer(self, result):
# output result
self.log( "Got result for job %s: %s" % (self.jobID, result) )
self.textCtrlResult.SetValue(str(result))
# get ready for next job:
self.buttonGet.Enable(True)
self.buttonAbort.Enable(False)
self.jobID += 1
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
vsizer = wx.BoxSizer(wx.VERTICAL)
b = wx.Button(self, -1, "Long-running function in separate thread")
vsizer.Add(b, 0, wx.ALL, 5)
self.Bind(wx.EVT_BUTTON, self.OnButton1, b)
b = wx.Button(self, -1, "Long-running function in GUI thread")
vsizer.Add(b, 0, wx.ALL, 5)
self.Bind(wx.EVT_BUTTON, self.OnButton2, b)
bdr = wx.BoxSizer()
bdr.Add(vsizer, 0, wx.ALL, 50)
self.SetSizer(bdr)
self.Layout()
def OnButton1(self, evt):
frame = FrameSimpleDelayed(self, title="Long-running function in separate thread")
frame.setLog(self.log.WriteText)
frame.Show()
def OnButton2(self, evt):
frame = FrameSimpleDirect(self, title="Long-running function in GUI thread")
frame.setLog(self.log.WriteText)
frame.Show()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = __doc__
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

173
demo/Dialog.py Normal file
View File

@@ -0,0 +1,173 @@
import wx
#---------------------------------------------------------------------------
# Create and set a help provider. Normally you would do this in
# the app's OnInit as it must be done before any SetHelpText calls.
provider = wx.SimpleHelpProvider()
wx.HelpProvider.Set(provider)
#---------------------------------------------------------------------------
class TestDialog(wx.Dialog):
def __init__(
self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition,
style=wx.DEFAULT_DIALOG_STYLE,
):
# Instead of calling wx.Dialog.__init__ we precreate the dialog
# so we can set an extra style that must be set before
# creation, and then we create the GUI object using the Create
# method.
pre = wx.PreDialog()
pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
pre.Create(parent, ID, title, pos, size, style)
# This next step is the most important, it turns this Python
# object into the real wrapper of the dialog (instead of pre)
# as far as the wxPython extension is concerned.
self.PostCreate(pre)
# Now continue with the normal construction of the dialog
# contents
sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(self, -1, "This is a wx.Dialog")
label.SetHelpText("This is the help text for the label")
sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
box = wx.BoxSizer(wx.HORIZONTAL)
label = wx.StaticText(self, -1, "Field #1:")
label.SetHelpText("This is the help text for the label")
box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
text = wx.TextCtrl(self, -1, "", size=(80,-1))
text.SetHelpText("Here's some help text for field #1")
box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
box = wx.BoxSizer(wx.HORIZONTAL)
label = wx.StaticText(self, -1, "Field #2:")
label.SetHelpText("This is the help text for the label")
box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
text = wx.TextCtrl(self, -1, "", size=(80,-1))
text.SetHelpText("Here's some help text for field #2")
box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
btnsizer = wx.StdDialogButtonSizer()
if wx.Platform != "__WXMSW__":
btn = wx.ContextHelpButton(self)
btnsizer.AddButton(btn)
btn = wx.Button(self, wx.ID_OK)
btn.SetHelpText("The OK button completes the dialog")
btn.SetDefault()
btnsizer.AddButton(btn)
btn = wx.Button(self, wx.ID_CANCEL)
btn.SetHelpText("The Cancel button cancels the dialog. (Cool, huh?)")
btnsizer.AddButton(btn)
btnsizer.Realize()
sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
self.SetSizer(sizer)
sizer.Fit(self)
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a custom Dialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
b = wx.Button(self, -1, "Show dialog with ShowWindowModal", (50, 140))
self.Bind(wx.EVT_BUTTON, self.OnShowWindowModal, b)
self.Bind(wx.EVT_WINDOW_MODAL_DIALOG_CLOSED, self.OnWindowModalDialogClosed)
def OnButton(self, evt):
dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200),
style=wx.DEFAULT_DIALOG_STYLE,
)
dlg.CenterOnScreen()
# this does not return until the dialog is closed.
val = dlg.ShowModal()
if val == wx.ID_OK:
self.log.WriteText("You pressed OK\n")
else:
self.log.WriteText("You pressed Cancel\n")
dlg.Destroy()
def OnShowWindowModal(self, evt):
dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200),
style=wx.DEFAULT_DIALOG_STYLE)
dlg.ShowWindowModal()
def OnWindowModalDialogClosed(self, evt):
dialog = evt.GetDialog()
val = evt.GetReturnCode()
try:
btnTxt = { wx.ID_OK : "OK",
wx.ID_CANCEL: "Cancel" }[val]
except KeyError:
btnTxt = '<unknown>'
wx.MessageBox("You closed the window-modal dialog with the %s button" % btnTxt)
dialog.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
wxPython offers quite a few general purpose dialogs for useful data input from
the user; they are all based on the wx.Dialog class, which you can also subclass
to create custom dialogs to suit your needs.
The Dialog class, in addition to dialog-like behaviors, also supports the full
wxWindows layout featureset, which means that you can incorporate sizers or
layout constraints as needed to achieve the look and feel desired. It even supports
context-sensitive help, which is illustrated in this example.
The example is very simple; in real world situations, a dialog that had input
fields such as this would no doubt be required to deliver those values back to
the calling function. The Dialog class supports data retrieval in this manner.
<b>However, the data must be retrieved prior to the dialog being destroyed.</b>
The example shown here is <i>modal</i>; non-modal dialogs are possible as well.
See the documentation for the <code>Dialog</code> class for more details.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

127
demo/DialogUnits.py Normal file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python
#----------------------------------------------------------------------------
# Name: DialogUnits.py
# Purpose: A minimal wxPython program that is a bit smarter than test1.
#
# Author: Robin Dunn
#
# Created: A long time ago, in a galaxy far, far away...
# RCS-ID: $Id$
# Copyright: (c) 1998 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------------
#
import wx
#---------------------------------------------------------------------------
# Create a new frame class, derived from the wxPython Frame.
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
# First, call the base class' __init__ method to create the frame
wx.Frame.__init__(self, parent, id, title, (100, 100), (160, 100))
# Associate some events with methods of this class
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_MOVE, self.OnMove)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
# Add a panel and some controls to display the size and position
panel = wx.Panel(self, -1)
wx.StaticText(panel, -1, "Size:",
wx.DLG_PNT(panel, (4, 4)), wx.DefaultSize
)
wx.StaticText(panel, -1, "Pos:",
wx.DLG_PNT(panel, (4, 16)), wx.DefaultSize
)
self.sizeCtrl = wx.TextCtrl(panel, -1, "",
wx.DLG_PNT(panel, (24, 4)),
wx.DLG_SZE(panel, (36, -1)),
wx.TE_READONLY)
self.posCtrl = wx.TextCtrl(panel, -1, "",
wx.DLG_PNT(panel, (24, 16)),
wx.DLG_SZE(panel, (36, -1)),
wx.TE_READONLY)
#print wx.DLG_PNT(panel, (24, 4)), wx.DLG_SZE(panel, (36, -1))
#print wx.DLG_PNT(panel, (24, 16)),wx.DLG_SZE(panel, (36, -1))
# This method is called automatically when the CLOSE event is
# sent to this window
def OnCloseWindow(self, event):
# tell the window to kill itself
self.Destroy()
# This method is called by the System when the window is resized,
# because of the association above.
def OnSize(self, event):
size = event.GetSize()
self.sizeCtrl.SetValue("%s, %s" % (size.width, size.height))
# tell the event system to continue looking for an event handler,
# so the default handler will get called.
event.Skip()
# This method is called by the System when the window is moved,
# because of the association above.
def OnMove(self, event):
pos = event.GetPosition()
self.posCtrl.SetValue("%s, %s" % (pos.x, pos.y))
#---------------------------------------------------------------------------
# if running standalone
if __name__ == "__main__":
# Every wxWindows application must have a class derived from wxApp
class MyApp(wx.App):
# wxWindows calls this method to initialize the application
def OnInit(self):
# Create an instance of our customized Frame class
frame = MyFrame(None, -1, "This is a test")
frame.Show(True)
# Tell wxWindows that this is our main window
self.SetTopWindow(frame)
# Return a success flag
return True
app = MyApp(0) # Create an instance of the application class
app.MainLoop() # Tell it to start processing events
#---------------------------------------------------------------------------
# if running as part of the Demo Framework...
def runTest(frame, nb, log):
win = MyFrame(frame, -1, "This is a test")
frame.otherWin = win
win.Show(True)
overview = """\
A simple example that shows how to use Dialog Units.
"""
#----------------------------------------------------------------------------
#

57
demo/DirDialog.py Normal file
View File

@@ -0,0 +1,57 @@
import wx
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a DirDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
# In this case we include a "New directory" button.
dlg = wx.DirDialog(self, "Choose a directory:",
style=wx.DD_DEFAULT_STYLE
#| wx.DD_DIR_MUST_EXIST
#| wx.DD_CHANGE_DIR
)
# If the user selects OK, then we process the dialog's data.
# This is done by getting the path data from the dialog - BEFORE
# we destroy it.
if dlg.ShowModal() == wx.ID_OK:
self.log.WriteText('You selected: %s\n' % dlg.GetPath())
# Only destroy a dialog after you're done with it.
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
This class represents the directory chooser dialog. It is used when all you
need from the user is the name of a directory. Data is retrieved via utility
methods; see the <code>DirDialog</code> documentation for specifics.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

273
demo/DragAndDrop.py Normal file
View File

@@ -0,0 +1,273 @@
import wx
#----------------------------------------------------------------------
ID_CopyBtn = wx.NewId()
ID_PasteBtn = wx.NewId()
ID_BitmapBtn = wx.NewId()
#----------------------------------------------------------------------
class ClipTextPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
#self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(
wx.StaticText(
self, -1, "Copy/Paste text to/from\n"
"this window and other apps"
),
0, wx.EXPAND|wx.ALL, 2
)
self.text = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.HSCROLL)
sizer.Add(self.text, 1, wx.EXPAND)
hsz = wx.BoxSizer(wx.HORIZONTAL)
hsz.Add(wx.Button(self, ID_CopyBtn, " Copy "), 1, wx.EXPAND|wx.ALL, 2)
hsz.Add(wx.Button(self, ID_PasteBtn, " Paste "), 1, wx.EXPAND|wx.ALL, 2)
sizer.Add(hsz, 0, wx.EXPAND)
sizer.Add(
wx.Button(self, ID_BitmapBtn, " Copy Bitmap "),
0, wx.EXPAND|wx.ALL, 2
)
self.Bind(wx.EVT_BUTTON, self.OnCopy, id=ID_CopyBtn)
self.Bind(wx.EVT_BUTTON, self.OnPaste, id=ID_PasteBtn)
self.Bind(wx.EVT_BUTTON, self.OnCopyBitmap, id=ID_BitmapBtn)
self.SetAutoLayout(True)
self.SetSizer(sizer)
def OnCopy(self, evt):
self.do = wx.TextDataObject()
self.do.SetText(self.text.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(self.do)
wx.TheClipboard.Close()
else:
wx.MessageBox("Unable to open the clipboard", "Error")
def OnPaste(self, evt):
success = False
do = wx.TextDataObject()
if wx.TheClipboard.Open():
success = wx.TheClipboard.GetData(do)
wx.TheClipboard.Close()
if success:
self.text.SetValue(do.GetText())
else:
wx.MessageBox(
"There is no data in the clipboard in the required format",
"Error"
)
def OnCopyBitmap(self, evt):
dlg = wx.FileDialog(self, "Choose a bitmap to copy", wildcard="*.bmp")
if dlg.ShowModal() == wx.ID_OK:
bmp = wx.Bitmap(dlg.GetPath(), wx.BITMAP_TYPE_BMP)
bmpdo = wx.BitmapDataObject(bmp)
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(bmpdo)
wx.TheClipboard.Close()
wx.MessageBox(
"The bitmap is now in the Clipboard. Switch to a graphics\n"
"editor and try pasting it in..."
)
else:
wx.MessageBox(
"There is no data in the clipboard in the required format",
"Error"
)
dlg.Destroy()
#----------------------------------------------------------------------
class OtherDropTarget(wx.PyDropTarget):
def __init__(self, window, log):
wx.PyDropTarget.__init__(self)
self.log = log
self.do = wx.FileDataObject()
self.SetDataObject(self.do)
def OnEnter(self, x, y, d):
self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d))
return wx.DragCopy
#def OnDragOver(self, x, y, d):
# self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d))
# return wx.DragCopy
def OnLeave(self):
self.log.WriteText("OnLeave\n")
def OnDrop(self, x, y):
self.log.WriteText("OnDrop: %d %d\n" % (x, y))
return True
def OnData(self, x, y, d):
self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d))
self.GetData()
self.log.WriteText("%s\n" % self.do.GetFilenames())
return d
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, window, log):
wx.FileDropTarget.__init__(self)
self.window = window
self.log = log
def OnDropFiles(self, x, y, filenames):
self.window.SetInsertionPointEnd()
self.window.WriteText("\n%d file(s) dropped at %d,%d:\n" %
(len(filenames), x, y))
for file in filenames:
self.window.WriteText(file + '\n')
class MyTextDropTarget(wx.TextDropTarget):
def __init__(self, window, log):
wx.TextDropTarget.__init__(self)
self.window = window
self.log = log
def OnDropText(self, x, y, text):
self.window.WriteText("(%d, %d)\n%s\n" % (x, y, text))
def OnDragOver(self, x, y, d):
return wx.DragCopy
class FileDropPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
#self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(
wx.StaticText(self, -1, " \nDrag some files here:"),
0, wx.EXPAND|wx.ALL, 2
)
self.text = wx.TextCtrl(
self, -1, "",
style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY
)
dt = MyFileDropTarget(self, log)
self.text.SetDropTarget(dt)
sizer.Add(self.text, 1, wx.EXPAND)
sizer.Add(
wx.StaticText(self, -1, " \nDrag some text here:"),
0, wx.EXPAND|wx.ALL, 2
)
self.text2 = wx.TextCtrl(
self, -1, "",
style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY
)
dt = MyTextDropTarget(self.text2, log)
self.text2.SetDropTarget(dt)
sizer.Add(self.text2, 1, wx.EXPAND)
self.SetAutoLayout(True)
self.SetSizer(sizer)
def WriteText(self, text):
self.text.WriteText(text)
def SetInsertionPointEnd(self):
self.text.SetInsertionPointEnd()
#----------------------------------------------------------------------
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.SetAutoLayout(True)
outsideSizer = wx.BoxSizer(wx.VERTICAL)
msg = "Clipboard / Drag-And-Drop"
text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
text.SetLabel(msg)
w,h = text.GetTextExtent(msg)
text.SetSize(wx.Size(w,h+1))
text.SetForegroundColour(wx.BLUE)
outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
inSizer = wx.BoxSizer(wx.HORIZONTAL)
inSizer.Add(ClipTextPanel(self, log), 1, wx.EXPAND)
inSizer.Add(FileDropPanel(self, log), 1, wx.EXPAND)
outsideSizer.Add(inSizer, 1, wx.EXPAND)
self.SetSizer(outsideSizer)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
<html>
<body>
This demo shows some examples of data transfer through clipboard or
drag and drop. In wxWindows, these two ways to transfer data (either
between different applications or inside one and the same) are very
similar which allows to implement both of them using almost the same
code - or, in other words, if you implement drag and drop support for
your application, you get clipboard support for free and vice versa.
<p>
At the heart of both clipboard and drag and drop operations lies the
wxDataObject class. The objects of this class (or, to be precise,
classes derived from it) represent the data which is being carried by
the mouse during drag and drop operation or copied to or pasted from
the clipboard. wxDataObject is a "smart" piece of data because it
knows which formats it supports (see GetFormatCount and GetAllFormats)
and knows how to render itself in any of them (see GetDataHere). It
can also receive its value from the outside in a format it supports if
it implements the SetData method. Please see the documentation of this
class for more details.
<p>
Both clipboard and drag and drop operations have two sides: the source
and target, the data provider and the data receiver. These which may
be in the same application and even the same window when, for example,
you drag some text from one position to another in a word
processor. Let us describe what each of them should do.
</body>
</html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

327
demo/DragImage.py Normal file
View File

@@ -0,0 +1,327 @@
import wx
import images
#----------------------------------------------------------------------
class DragShape:
def __init__(self, bmp):
self.bmp = bmp
self.pos = (0,0)
self.shown = True
self.text = None
self.fullscreen = False
def HitTest(self, pt):
rect = self.GetRect()
return rect.InsideXY(pt.x, pt.y)
def GetRect(self):
return wx.Rect(self.pos[0], self.pos[1],
self.bmp.GetWidth(), self.bmp.GetHeight())
def Draw(self, dc, op = wx.COPY):
if self.bmp.Ok():
memDC = wx.MemoryDC()
memDC.SelectObject(self.bmp)
dc.Blit(self.pos[0], self.pos[1],
self.bmp.GetWidth(), self.bmp.GetHeight(),
memDC, 0, 0, op, True)
return True
else:
return False
#----------------------------------------------------------------------
class DragCanvas(wx.ScrolledWindow):
def __init__(self, parent, ID):
wx.ScrolledWindow.__init__(self, parent, ID)
self.shapes = []
self.dragImage = None
self.dragShape = None
self.hiliteShape = None
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
self.bg_bmp = images.Background.GetBitmap()
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
# Make a shape from an image and mask. This one will demo
# dragging outside the window
bmp = images.TestStar.GetBitmap()
#bmp = wx.Bitmap('bitmaps/toucan.png')
shape = DragShape(bmp)
shape.pos = (5, 5)
shape.fullscreen = True
self.shapes.append(shape)
bmp = images.TheKid.GetBitmap()
shape = DragShape(bmp)
shape.pos = (200, 5)
self.shapes.append(shape)
# Make a shape from some text
text = "Some Text"
bg_colour = wx.Colour(57, 115, 57) # matches the bg image
font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD)
textExtent = self.GetFullTextExtent(text, font)
# create a bitmap the same size as our text
bmp = wx.EmptyBitmap(textExtent[0], textExtent[1])
# 'draw' the text onto the bitmap
dc = wx.MemoryDC()
dc.SelectObject(bmp)
dc.SetBackground(wx.Brush(bg_colour, wx.SOLID))
dc.Clear()
dc.SetTextForeground(wx.RED)
dc.SetFont(font)
dc.DrawText(text, 0, 0)
dc.SelectObject(wx.NullBitmap)
mask = wx.Mask(bmp, bg_colour)
bmp.SetMask(mask)
shape = DragShape(bmp)
shape.pos = (5, 100)
shape.text = "Some dragging text"
self.shapes.append(shape)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
# We're not doing anything here, but you might have reason to.
# for example, if you were dragging something, you might elect to
# 'drop it' when the cursor left the window.
def OnLeaveWindow(self, evt):
pass
# tile the background bitmap
def TileBackground(self, dc):
sz = self.GetClientSize()
w = self.bg_bmp.GetWidth()
h = self.bg_bmp.GetHeight()
x = 0
while x < sz.width:
y = 0
while y < sz.height:
dc.DrawBitmap(self.bg_bmp, x, y)
y = y + h
x = x + w
# Go through our list of shapes and draw them in whatever place they are.
def DrawShapes(self, dc):
for shape in self.shapes:
if shape.shown:
shape.Draw(dc)
# This is actually a sophisticated 'hit test', but in this
# case we're also determining which shape, if any, was 'hit'.
def FindShape(self, pt):
for shape in self.shapes:
if shape.HitTest(pt):
return shape
return None
# Clears the background, then redraws it. If the DC is passed, then
# we only do so in the area so designated. Otherwise, it's the whole thing.
def OnEraseBackground(self, evt):
dc = evt.GetDC()
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
self.TileBackground(dc)
# Fired whenever a paint event occurs
def OnPaint(self, evt):
dc = wx.PaintDC(self)
self.PrepareDC(dc)
self.DrawShapes(dc)
# Left mouse button is down.
def OnLeftDown(self, evt):
# Did the mouse go down on one of our shapes?
shape = self.FindShape(evt.GetPosition())
# If a shape was 'hit', then set that as the shape we're going to
# drag around. Get our start position. Dragging has not yet started.
# That will happen once the mouse moves, OR the mouse is released.
if shape:
self.dragShape = shape
self.dragStartPos = evt.GetPosition()
# Left mouse button up.
def OnLeftUp(self, evt):
if not self.dragImage or not self.dragShape:
self.dragImage = None
self.dragShape = None
return
# Hide the image, end dragging, and nuke out the drag image.
self.dragImage.Hide()
self.dragImage.EndDrag()
self.dragImage = None
if self.hiliteShape:
self.RefreshRect(self.hiliteShape.GetRect())
self.hiliteShape = None
# reposition and draw the shape
# Note by jmg 11/28/03
# Here's the original:
#
# self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos
#
# So if there are any problems associated with this, use that as
# a starting place in your investigation. I've tried to simulate the
# wx.Point __add__ method here -- it won't work for tuples as we
# have now from the various methods
#
# There must be a better way to do this :-)
#
self.dragShape.pos = (
self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0],
self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1]
)
self.dragShape.shown = True
self.RefreshRect(self.dragShape.GetRect())
self.dragShape = None
# The mouse is moving
def OnMotion(self, evt):
# Ignore mouse movement if we're not dragging.
if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
return
# if we have a shape, but haven't started dragging yet
if self.dragShape and not self.dragImage:
# only start the drag after having moved a couple pixels
tolerance = 2
pt = evt.GetPosition()
dx = abs(pt.x - self.dragStartPos.x)
dy = abs(pt.y - self.dragStartPos.y)
if dx <= tolerance and dy <= tolerance:
return
# refresh the area of the window where the shape was so it
# will get erased.
self.dragShape.shown = False
self.RefreshRect(self.dragShape.GetRect(), True)
self.Update()
if self.dragShape.text:
self.dragImage = wx.DragString(self.dragShape.text,
wx.StockCursor(wx.CURSOR_HAND))
else:
self.dragImage = wx.DragImage(self.dragShape.bmp,
wx.StockCursor(wx.CURSOR_HAND))
hotspot = self.dragStartPos - self.dragShape.pos
self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
self.dragImage.Move(pt)
self.dragImage.Show()
# if we have shape and image then move it, posibly highlighting another shape.
elif self.dragShape and self.dragImage:
onShape = self.FindShape(evt.GetPosition())
unhiliteOld = False
hiliteNew = False
# figure out what to hilite and what to unhilite
if self.hiliteShape:
if onShape is None or self.hiliteShape is not onShape:
unhiliteOld = True
if onShape and onShape is not self.hiliteShape and onShape.shown:
hiliteNew = True
# if needed, hide the drag image so we can update the window
if unhiliteOld or hiliteNew:
self.dragImage.Hide()
if unhiliteOld:
dc = wx.ClientDC(self)
self.hiliteShape.Draw(dc)
self.hiliteShape = None
if hiliteNew:
dc = wx.ClientDC(self)
self.hiliteShape = onShape
self.hiliteShape.Draw(dc, wx.INVERT)
# now move it and show it again if needed
self.dragImage.Move(evt.GetPosition())
if unhiliteOld or hiliteNew:
self.dragImage.Show()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = wx.Panel(nb, -1)
canvas = DragCanvas(win, -1)
def onSize(evt, panel=win, canvas=canvas):
canvas.SetSize(panel.GetSize())
win.Bind(wx.EVT_SIZE, onSize)
return win
#----------------------------------------------------------------------
overview = """\
DragImage is used when you wish to drag an object on the screen, and a simple
cursor is not enough.
On Windows, the WIN32 API is used to do achieve smooth dragging. On other
platforms, <code>GenericDragImage</code> is used. Applications may also prefer to use
<code>GenericDragImage</code> on Windows, too.
<b>wxPython note</b>: wxPython uses <code>GenericDragImage</code> on all
platforms, but uses the <code>DragImage</code> name.
To use this class, when you wish to start dragging an image, create a
<code>DragImage</code> object and store it somewhere you can access it as the
drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move
the image, initially call Show and then Move. If you wish to update the screen
contents during the drag (for example, highlight an item as in the example), first
call Hide, update the screen, call Move, and then call Show.
You can drag within one window, or you can use full-screen dragging either across
the whole screen, or just restricted to one area of the screen to save resources.
If you want the user to drag between two windows, then you will need to use
full-screen dragging.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

57
demo/DragScroller.py Normal file
View File

@@ -0,0 +1,57 @@
import wx
import wx.lib.dragscroller
#-------------------------------------------------------------------------------
def runTest(frame, nb, log):
win = DragScrollerExample(nb, -1)
return win
class DragScrollerExample(wx.ScrolledWindow):
def __init__(self, parent, id=-1):
wx.ScrolledWindow.__init__(self, parent, id)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
self.SetScrollbars(1, 1, 2000, 2000, 0, 0)
self.scroller = wx.lib.dragscroller.DragScroller(self)
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.PrepareDC(dc)
pen = wx.Pen(wx.BLACK, 5)
dc.SetPen(pen)
for y in range(10):
for x in range(10):
dc.DrawCircle(x*400+20, y*400+20, 200)
dc.DrawText('Right click and drag in the direction you want to scroll.',
20, 20)
dc.DrawText('The distance from the start of the drag determines the speed.',
20, 50)
def OnRightDown(self, event):
self.scroller.Start(event.GetPosition())
def OnRightUp(self, event):
self.scroller.Stop()
#-------------------------------------------------------------------------------
overview = """<html><body>
<h2>DragScroller</h2>
<p>
A helper class that adds scrolling to a wx.ScrolledWindow in the direction
of the drag.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])])

453
demo/DrawXXXList.py Normal file
View File

@@ -0,0 +1,453 @@
import random
import time
import wx
#----------------------------------------------------------------------
colours = [
"BLACK",
"BLUE",
"BLUE VIOLET",
"BROWN",
"CYAN",
"DARK GREY",
"DARK GREEN",
"GOLD",
"GREY",
"GREEN",
"MAGENTA",
"NAVY",
"PINK",
"RED",
"SKY BLUE",
"VIOLET",
"YELLOW",
]
#----------------------------------------------------------------------
def makeRandomPoints(num, w, h):
pnts = []
for i in range(num):
x = random.randint(0, w)
y = random.randint(0, h)
pnts.append( (x,y) )
return pnts
def makeRandomLines(num, w, h):
pnts = []
for i in range(num):
x1 = random.randint(0, w)
y1 = random.randint(0, h)
x2 = random.randint(0, w)
y2 = random.randint(0, h)
pnts.append( (x1,y1, x2,y2) )
return pnts
def makeRandomRectangles(num, W, H):
rects = []
for i in range(num):
w = random.randint(10, W/2)
h = random.randint(10, H/2)
x = random.randint(0, W - w)
y = random.randint(0, H - h)
rects.append( (x, y, w, h) )
return rects
def makeRandomText(num):
Np = 8 # number of characters in text
text = []
for i in range(num):
word = []
for i in range(Np):
c = chr( random.randint(48, 122) )
word.append( c )
text.append( "".join(word) )
return text
def makeRandomPolygons(num, W, H):
Np = 8 # number of points per polygon
polys = []
for i in range(num):
poly = []
for i in range(Np):
x = random.randint(0, W)
y = random.randint(0, H)
poly.append( (x,y) )
polys.append( poly )
return polys
def makeRandomPens(num, cache):
pens = []
for i in range(num):
c = random.choice(colours)
t = random.randint(1, 4)
if not cache.has_key( (c, t) ):
cache[(c, t)] = wx.Pen(c, t)
pens.append( cache[(c, t)] )
return pens
def makeRandomBrushes(num, cache):
brushes = []
for i in range(num):
c = random.choice(colours)
if not cache.has_key(c):
cache[c] = wx.Brush(c)
brushes.append( cache[c] )
return brushes
def makeRandomColors(num):
colors = []
for i in range(num):
c = random.choice(colours)
colors.append(wx.NamedColour(c))
return colors
pencache = {}
brushcache = {}
points = None
lines = None
rectangles = None
polygons = None
text = None
pens = None
brushes = None
colors1 = None
colors2 = None
def Init(w, h, n):
global pencache
global brushcache
global points
global lines
global rectangles
global polygons
global text
global pens
global brushes
global colors1
global colors2
# make some lists of random shapes
points = makeRandomPoints(n, w, h)
try:
import Numeric
Apoints = Numeric.array(points)
except:
pass
lines = makeRandomLines(n, w, h)
rectangles = makeRandomRectangles(n, w, h)
polygons = makeRandomPolygons(n, w, h)
text = makeRandomText(n)
# make some random pens and brushes
pens = makeRandomPens(n, pencache)
brushes = makeRandomBrushes(n, brushcache)
# make some random color lists
colors1 = makeRandomColors(n)
colors2 = makeRandomColors(n)
def TestPoints(dc,log):
dc.BeginDrawing()
start = time.time()
dc.SetPen(wx.Pen("BLACK", 4))
dc.DrawPointList(points)
dc.DrawPointList(points, wx.Pen("RED", 2))
dc.DrawPointList(points, pens)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawPointList\n" % (time.time() - start))
def TestArrayPoints(dc,log):
try:
import Numeric
dc.BeginDrawing()
start = time.time()
dc.SetPen(wx.Pen("BLACK", 1))
for i in range(1):
dc.DrawPointList(Apoints)
#dc.DrawPointList(Apoints, wx.Pen("RED", 2))
#dc.DrawPointList(Apoints, pens)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawPointList an Numpy Array\n" % (time.time() - start))
except ImportError:
log.write("Couldn't import Numeric")
pass
def TestLines(dc,log):
dc.BeginDrawing()
start = time.time()
dc.SetPen(wx.Pen("BLACK", 2))
dc.DrawLineList(lines)
dc.DrawLineList(lines, wx.Pen("RED", 2))
dc.DrawLineList(lines, pens)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawLineList\n" % (time.time() - start))
def TestRectangles(dc,log):
dc.BeginDrawing()
start = time.time()
dc.SetPen( wx.Pen("BLACK",1) )
dc.SetBrush( wx.Brush("RED") )
dc.DrawRectangleList(rectangles)
dc.DrawRectangleList(rectangles,pens)
dc.DrawRectangleList(rectangles,pens[0],brushes)
dc.DrawRectangleList(rectangles,pens,brushes[0])
dc.DrawRectangleList(rectangles,None,brushes)
## for i in range(10):
## #dc.DrawRectangleList(rectangles,pens,brushes)
## dc.DrawRectangleList(rectangles)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawRectanglesList\n" % (time.time() - start))
def TestEllipses(dc,log):
dc.BeginDrawing()
start = time.time()
dc.SetPen( wx.Pen("BLACK",1) )
dc.SetBrush( wx.Brush("RED") )
dc.DrawEllipseList(rectangles)
dc.DrawEllipseList(rectangles,pens)
dc.DrawEllipseList(rectangles,pens[0],brushes)
dc.DrawEllipseList(rectangles,pens,brushes[0])
dc.DrawEllipseList(rectangles,None,brushes)
dc.DrawEllipseList(rectangles,pens,brushes)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawEllipsesList\n" % (time.time() - start))
def TestRectanglesArray(dc,log):
try:
import Numeric
Apoints = Numeric.array(rectangles)
dc.BeginDrawing()
start = time.time()
dc.SetPen(wx.Pen("BLACK", 1))
dc.DrawRectangleList(rectangles)
dc.DrawRectangleList(rectangles,pens)
dc.DrawRectangleList(rectangles,pens[0],brushes)
dc.DrawRectangleList(rectangles,pens,brushes[0])
dc.DrawRectangleList(rectangles,None,brushes)
## for i in range(10):
## #dc.DrawRectangleList(rectangles,pens,brushes)
## dc.DrawRectangleList(rectangles)
dc.EndDrawing()
log.write("DrawTime: %s seconds with DrawRectangleList and Numpy Array\n" % (time.time() - start))
except ImportError:
log.write("Couldn't import Numeric")
pass
def TestRectanglesLoop(dc,log):
dc.BeginDrawing()
start = time.time()
dc.DrawRectangleList(rectangles,pens,brushes)
log.write("DrawTime: %s seconds with DrawRectanglesList\n" % (time.time() - start))
start = time.time()
for i in range(len(rectangles)):
dc.SetPen( pens[i] )
dc.SetBrush( brushes[i] )
dc.DrawRectangle(rectangles[i][0],rectangles[i][1],rectangles[i][2],rectangles[i][3])
dc.EndDrawing()
log.write("DrawTime: %s seconds with Python loop\n" % (time.time() - start))
def TestPolygons(dc,log):
dc.BeginDrawing()
start = time.time()
dc.SetPen(wx.Pen("BLACK", 1))
dc.DrawPolygonList(polygons)
dc.DrawPolygonList(polygons,pens)
dc.DrawPolygonList(polygons,pens[0],brushes)
dc.DrawPolygonList(polygons,pens,brushes[0])
dc.DrawPolygonList(polygons,None,brushes)
log.write("DrawTime: %s seconds with DrawPolygonList\n" % (time.time() - start))
dc.EndDrawing()
def TestText(dc,log):
dc.BeginDrawing()
start = time.time()
# NOTE: you need to set BackgroundMode for the background colors to be used.
dc.SetBackgroundMode(wx.SOLID)
foreground = colors1
background = colors2
dc.DrawTextList(text, points, foreground, background)
log.write("DrawTime: %s seconds with DrawTextList\n" % (time.time() - start))
dc.EndDrawing()
class TestNB(wx.Notebook):
def __init__(self, parent, id, log):
style = wx.NB_BOTTOM
if wx.Platform == "__WXMAC__":
style = 0
wx.Notebook.__init__(self, parent, id, style=style)
self.log = log
# Initialize our various samples and add them to the notebook.
win = DrawPanel(self, TestEllipses, log)
self.AddPage(win, 'Ellipses')
win = DrawPanel(self, TestText, log)
self.AddPage(win, 'Text')
win = DrawPanel(self, TestPolygons, log)
self.AddPage(win, 'Polygons')
win = DrawPanel(self, TestPoints, log)
self.AddPage(win, 'Points')
win = DrawPanel(self, TestLines, log)
self.AddPage(win, 'Lines')
win = DrawPanel(self, TestRectangles, log)
self.AddPage(win, 'Rectangles')
# Class used for all the various sample pages; the mechanics are the same
# for each one with regards to the notebook. The only difference is
# the function we use to draw on it.
class DrawPanel(wx.Panel):
def __init__(self, parent, drawFun, log):
wx.Panel.__init__(self, parent, -1)
self.SetBackgroundColour(wx.WHITE)
self.log = log
self.drawFun = drawFun
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
dc.Clear()
self.drawFun(dc,self.log)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
w = nb.GetClientSize().width
h = nb.GetClientSize().height
if w < 600: w = 600
if h < 400: h = 400
Init(w, h, 200)
win = TestNB(nb, -1, log)
return win
#----------------------------------------------------------------------
overview = """\
Some methods have been added to wx.DC to help with optimization of
drawing routines. Currently they are:
<pre>
DrawPointList(sequence, pens=None)
</pre>
Where sequence is a tuple, list, whatever of 2 element tuples
(x, y) and pens is either None, a single pen or a list of pens.
<pre>
DrawLineList(sequence, pens=None)
</pre>
Where sequence is a tuple, list, whatever of 4 element tuples
(x1,y1, x2,y2) and pens is either None, a single pen or a list
of pens.
<pre>
DrawRectangleList(rectangles, pens=None, brushes=None)
</pre>
<pre>
DrawEllipseList(ellipses, pens=None, brushes=None)
</pre>
<pre>
DrawPolygonList(polygons, pens=None, brushes=None)
</pre>
<pre>
DrawTextList(textList, coords, foregrounds = None, backgrounds = None)
</pre>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

166
demo/DynamicSashWindow.py Normal file
View File

@@ -0,0 +1,166 @@
import wx
import wx.gizmos as gizmos
import wx.stc as stc
#----------------------------------------------------------------------
# This is an example of the complex view that manages its own scrollbars
# as described in the overview below.
class TestView(stc.StyledTextCtrl):
def __init__(self, parent, ID, log):
stc.StyledTextCtrl.__init__(self, parent, ID, style=wx.NO_BORDER)
self.dyn_sash = parent
self.log = log
self.SetupScrollBars()
self.SetMarginWidth(1,0)
self.StyleSetFont(stc.STC_STYLE_DEFAULT,
wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
self.Bind(gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnSplit)
self.Bind(gizmos.EVT_DYNAMIC_SASH_UNIFY, self.OnUnify)
#self.SetScrollWidth(500)
def SetupScrollBars(self):
# hook the scrollbars provided by the wxDynamicSashWindow
# to this view
v_bar = self.dyn_sash.GetVScrollBar(self)
h_bar = self.dyn_sash.GetHScrollBar(self)
v_bar.Bind(wx.EVT_SCROLL, self.OnSBScroll)
h_bar.Bind(wx.EVT_SCROLL, self.OnSBScroll)
v_bar.Bind(wx.EVT_SET_FOCUS, self.OnSBFocus)
h_bar.Bind(wx.EVT_SET_FOCUS, self.OnSBFocus)
# And set the wxStyledText to use these scrollbars instead
# of its built-in ones.
self.SetVScrollBar(v_bar)
self.SetHScrollBar(h_bar)
def __del__(self):
self.log.write("TestView.__del__\n")
def OnSplit(self, evt):
self.log.write("TestView.OnSplit\n");
newview = TestView(self.dyn_sash, -1, self.log)
newview.SetDocPointer(self.GetDocPointer()) # use the same document
self.SetupScrollBars()
def OnUnify(self, evt):
self.log.write("TestView.OnUnify\n");
self.SetupScrollBars()
def OnSBScroll(self, evt):
# redirect the scroll events from the dyn_sash's scrollbars to the STC
self.GetEventHandler().ProcessEvent(evt)
def OnSBFocus(self, evt):
# when the scrollbar gets the focus move it back to the STC
self.SetFocus()
sampleText="""\
You can drag the little tabs above the vertical scrollbar, or to the
left of the horizontal scrollbar to split this view, and you can
continue splitting the new views as much as you like. Try it and see.
In this case the views also share the same document so changes in one
are instantly seen in the others. This is a feature of the
StyledTextCtrl that is used for the view class in this sample.
"""
#----------------------------------------------------------------------
# This one is simpler, but doesn't do anything with the scrollbars
# except the default wxDynamicSashWindow behaviour
class SimpleView(wx.Panel):
def __init__(self, parent, ID, log):
wx.Panel.__init__(self, parent, ID)
self.dyn_sash = parent
self.log = log
self.SetBackgroundColour("LIGHT BLUE")
self.Bind(gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnSplit)
def OnSplit(self, evt):
v = SimpleView(self.dyn_sash, -1, self.log)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
## if wx.Platform == "__WXMAC__":
## from wx.lib.msgpanel import MessagePanel
## win = MessagePanel(nb, 'This demo currently fails on the Mac. The problem is being looked into...',
## 'Sorry', wx.ICON_WARNING)
## return win
if 1:
win = gizmos.DynamicSashWindow(nb, -1, style = wx.CLIP_CHILDREN
#| wxDS_MANAGE_SCROLLBARS
#| wxDS_DRAG_CORNER
)
win.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
view = TestView(win, -1, log)
view.SetText(sampleText)
else:
win = wx.DynamicSashWindow(nb, -1)
view = SimpleView(win, -1, log)
return win
#----------------------------------------------------------------------
overview = """\
<html><body>
<h2>DynamicSashWindow</h2>
<p>
wxDynamicSashWindow widgets manages the way other widgets are viewed.
When a wxDynamicSashWindow is first shown, it will contain one child
view, a viewport for that child, and a pair of scrollbars to allow the
user to navigate the child view area. Next to each scrollbar is a small
tab. By clicking on either tab and dragging to the appropriate spot, a
user can split the view area into two smaller views separated by a
draggable sash. Later, when the user wishes to reunify the two subviews,
the user simply drags the sash to the side of the window.
wxDynamicSashWindow will automatically reparent the appropriate child
view back up the window hierarchy, and the wxDynamicSashWindow will have
only one child view once again.
<p>
As an application developer, you will simply create a wxDynamicSashWindow
using either the Create() function or the more complex constructor
provided below, and then create a view window whose parent is the
wxDynamicSashWindow. The child should respond to
wxDynamicSashSplitEvents -- perhaps with an OnSplit() event handler -- by
constructing a new view window whose parent is also the
wxDynamicSashWindow. That's it! Now your users can dynamically split
and reunify the view you provided.
<p>
If you wish to handle the scrollbar events for your view, rather than
allowing wxDynamicSashWindow to do it for you, things are a bit more
complex. (You might want to handle scrollbar events yourself, if,
for instance, you wish to scroll a subwindow of the view you add to
your wxDynamicSashWindow object, rather than scrolling the whole view.)
In this case, you will need to construct your wxDynamicSashWindow without
the wxDS_MANAGE_SCROLLBARS style and you will need to use the
GetHScrollBar() and GetVScrollBar() methods to retrieve the scrollbar
controls and call SetEventHanler() on them to redirect the scrolling
events whenever your window is reparented by wxDyanmicSashWindow.
You will need to set the scrollbars' event handler at three times:
<p>
<ul>
<li> When your view is created
<li> When your view receives a wxDynamicSashSplitEvent
<li> When your view receives a wxDynamicSashUnifyEvent
</ul>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

97
demo/EditableListBox.py Normal file
View File

@@ -0,0 +1,97 @@
import wx
import wx.gizmos as gizmos
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
self.elb = gizmos.EditableListBox(
self, -1, "List of Stuff", (50,50), (250, 250)
)
#style=wx.EL_ALLOW_NEW | wx.EL_ALLOW_EDIT | wx.EL_ALLOW_DELETE)
self.elb.SetStrings(["This is a nifty ListBox widget",
"that is editable by the user.",
"",
"Use the buttons above to",
"manipulate items in the list",
"Or to add new ones.",
])
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
<html>
<body>
This class provides a composite control that lets the user easily enter and edit
a list of strings.
<p><b>Styles supported:</b><p>
<ul>
<li><b>EL_ALLOW_NEW</b> - Allow user to create new items.
<li><b>EL_ALLOW_EDIT</b> - Allow user to edit text in the control.
<li><b>EL_ALLOW_DELETE</b> - Allow user to delete text from the control.
</ul>
<p><b>Init:</b>
<pre>
EditableListBox(wxWindow *parent, wxWindowID id=-1,
const wxString& label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = EL_ALLOW_NEW | EL_ALLOW_EDIT | EL_ALLOW_DELETE,
const wxString& name = "editableListBox")
</pre>
<p><b>Methods:</b>
<ul>
<li><b>SetStrings(const wxArrayString& strings)</b> - Set an array of strings
into the control. <b>Note</b>: The wxPython method accepts a Python list instead
of an array of strings.
<li><b>void GetStrings(wxArrayString& strings)</b> - Retrieves an array
of strings from the control. The wxPython version returns a list of strings.
<li><b>GetListCtrl()</b> - Retrieves a reference to the actual list control
portion of the custom control.
<li><b>GetDelButton()</b> - Retrieves a reference to the BitmapButton that is used
as the 'delete' button in the control.
<li><b>GetNewButton()</b> - Retrieves a reference to the BitmapButton that is used
as the 'new' button in the control.
<li><b>GetUpButton()</b> - Retrieves a reference to the BitmapButton that is used
as the 'up' button in the control.
<li><b>GetDownButton()</b> - Retrieves a reference to the BitmapButton that is used
as the 'down' button in the control.
<li><b>GetEditButton()</b> - Retrieves a reference to the BitmapButton that is used
as the 'edit' button in the control.
</ul>
</body>
</html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

69
demo/Editor.py Normal file
View File

@@ -0,0 +1,69 @@
import wx
import wx.lib.editor as editor
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = wx.Panel(nb, -1)
ed = editor.Editor(win, -1, style=wx.SUNKEN_BORDER)
box = wx.BoxSizer(wx.VERTICAL)
box.Add(ed, 1, wx.ALL|wx.GROW, 1)
win.SetSizer(box)
win.SetAutoLayout(True)
ed.SetText(["",
"This is a simple text editor, the class name is",
"Editor. Type a few lines and try it out.",
"",
"It uses Windows-style key commands that can be overridden by subclassing.",
"Mouse select works. Here are the key commands:",
"",
"Cursor movement: Arrow keys or mouse",
"Beginning of line: Home",
"End of line: End",
"Beginning of buffer: Control-Home",
"End of the buffer: Control-End",
"Select text: Hold down Shift while moving the cursor",
"Copy: Control-Insert, Control-C",
"Cut: Shift-Delete, Control-X",
"Paste: Shift-Insert, Control-V",
""])
return win
#----------------------------------------------------------------------
overview = """
The Editor class implements a simple text editor using wxPython. You
can create a custom editor by subclassing Editor. Even though much of
the editor is implemented in Python, it runs surprisingly smoothly on
normal hardware with small files.
How to use it
-------------
The demo code (demo/Editor.py) shows how to use Editor as a simple text
box. Use the SetText() and GetText() methods to set or get text from
the component; these both use a list of strings.
The samples/FrogEdit directory has an example of a simple text editor
application that uses the Editor component.
Subclassing
-----------
To add or change functionality, you can subclass this
component. One example of this might be to change the key
Alt key commands. In that case you would (for example) override the
SetAltFuncs() method.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

290
demo/EventManager.py Normal file
View File

@@ -0,0 +1,290 @@
#---------------------------------------------------------------------------
# Name: EventManager.py
# Purpose: A module to demonstrate wxPython.lib.evtmgr.EventManager.
#
# Author: Robb Shecter (robb@acm.org)
#
# Created: 16-December-2002
# Copyright: (c) 2002 by Robb Shecter (robb@acm.org)
# Licence: wxWindows license
#---------------------------------------------------------------------------
import wx
import wx.lib.evtmgr as em
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
fsize = self.GetFont().GetPointSize()
f1 = wx.Font(fsize+0, wx.SWISS, wx.NORMAL, wx.NORMAL)
f2 = wx.Font(fsize+2, wx.SWISS, wx.NORMAL, wx.BOLD)
f3 = wx.Font(fsize+6, wx.SWISS, wx.NORMAL, wx.BOLD)
title1 = wx.StaticText(self, -1, 'EventManager')
title1.SetFont(f3)
txt = """\
This demo shows (1) basic uses and features of the EventManager, as well
as (2) how it helps with a real-world task: creating independent, object-
oriented components."""
message0 = wx.StaticText(self, -1, txt)
message0.SetFont(f1)
title2 = wx.StaticText(self, -1, 'Event Listeners')
title2.SetFont(f2)
txt = """\
These objects listen to motion events from the target window, using the ability
to register one event with multiple listeners. They also register for mouse events
on themselves to implement toggle-button functionality."""
message1 = wx.StaticText(self, -1, txt)
message1.SetFont(f1)
title3 = wx.StaticText(self, -1, 'Target Window')
title3.SetFont(f2)
txt = """\
A passive window that's used as an event generator. Move the mouse over it to
send events to the listeners above."""
message2 = wx.StaticText(self, -1, txt)
message2.SetFont(f1)
targetPanel = Tile(self, log, bgColor=wx.Colour(80,10,10), active=0)
buttonPanel = wx.Panel(self ,-1)
sizer = wx.BoxSizer(wx.HORIZONTAL)
target = targetPanel.tile
sizer.Add((0,0), 1)
for factor in [0.2, 0.3, 0.4, 0.5, 0.6, 0.7]:
sizer.Add(Tile(buttonPanel, log, factor-0.05, target), 0, wx.ALIGN_CENTER)
sizer.Add((0,0),1)
sizer.Add(Tile(buttonPanel, log, factor, target), 0, wx.ALIGN_CENTER)
sizer.Add((0,0),1)
buttonPanel.SetSizer(sizer)
sizer.Fit(buttonPanel)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(title1, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 6)
sizer.Add(message0, 0, wx.ALIGN_CENTER | wx.ALL, 6)
sizer.Add(title2, 0, wx.ALIGN_CENTER | wx.LEFT | wx.TOP | wx.RIGHT, 16)
sizer.Add(message1, 0, wx.ALIGN_CENTER | wx.ALL, 6)
sizer.Add(buttonPanel, 0, wx.EXPAND | wx.ALL, 16)
sizer.Add(title3, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 16)
sizer.Add(message2, 0, wx.ALIGN_CENTER | wx.ALL, 6)
sizer.Add(targetPanel, 2, wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, 16)
self.SetSizer(sizer)
class Tile(wx.Window):
"""
This outer class is responsible for changing
its border color in response to certain mouse
events over its contained 'InnerTile'.
"""
normal = wx.Colour(150,150,150)
active = wx.Colour(250,245,245)
hover = wx.Colour(210,220,210)
def __init__(self, parent, log, factor=1, thingToWatch=None, bgColor=None, active=1, size=(38,38), borderWidth=3):
wx.Window.__init__(self, parent, -1, size=size, style=wx.CLIP_CHILDREN)
self.tile = InnerTile(self, log, factor, thingToWatch, bgColor)
self.log = log
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.tile, 1, wx.EXPAND | wx.ALL, borderWidth)
self.SetSizer(sizer)
self.Layout()
em.eventManager.Register(self.doLayout, wx.EVT_SIZE, self)
self.SetBackgroundColour(Tile.normal)
if active:
# Register myself for mouse events over self.tile in order to
# create typical button/hyperlink visual effects.
em.eventManager.Register(self.setHover, wx.EVT_ENTER_WINDOW, self.tile)
em.eventManager.Register(self.setNormal, wx.EVT_LEAVE_WINDOW, self.tile)
em.eventManager.Register(self.setActive, wx.EVT_LEFT_DOWN, self.tile)
em.eventManager.Register(self.setHover, wx.EVT_LEFT_UP, self.tile)
def doLayout(self, event):
self.Layout()
def setHover(self, event):
self.SetBackgroundColour(Tile.hover)
self.Refresh()
def setActive(self, event):
self.SetBackgroundColour(Tile.active)
self.Refresh()
def setNormal(self, event):
self.SetBackgroundColour(Tile.normal)
self.Refresh()
class InnerTile(wx.Window):
IDLE_COLOR = wx.Colour( 80, 10, 10)
START_COLOR = wx.Colour(200, 70, 50)
FINAL_COLOR = wx.Colour( 20, 80,240)
OFF_COLOR = wx.Colour(185,190,185)
# Some pre-computation.
DELTAS = map(lambda a,b: b-a, START_COLOR.Get(), FINAL_COLOR.Get())
START_COLOR_TUPLE = START_COLOR.Get()
"""
This inner panel changes its color in reaction to mouse
events over the 'thingToWatch'.
"""
def __init__(self, parent, log, factor, thingToWatch=None, bgColor=None):
wx.Window.__init__(self, parent, -1)
self.SetMinSize((20,20))
self.log=log
if bgColor:
self.SetBackgroundColour(bgColor)
if thingToWatch:
self.factor = factor
self.thingToWatch = thingToWatch
self.state = 0
self.toggleOnOff()
# Watch for the mouse click to enable/disable myself.
em.eventManager.Register(self.toggleOnOff, wx.EVT_LEFT_UP, self)
def toggleOnOff(self, event=None):
# Implement being on or off by registering and
# de-registering self.makeColor() from the event manager.
if self.state:
em.eventManager.DeregisterListener(self.makeColor)
else:
em.eventManager.Register(self.makeColor, wx.EVT_MOTION, self.thingToWatch)
self.state = 1 - self.state
self.resetColor()
def resetColor(self, event=None):
if self.state:
self.setColor(InnerTile.IDLE_COLOR)
else:
self.setColor(InnerTile.OFF_COLOR)
def setColor(self, color):
self.SetBackgroundColour(color)
self.Refresh()
def makeColor(self, mouseEvent):
self.makeColorFromTuple(mouseEvent.GetPositionTuple())
def makeColorFromTuple(self, (x, y)):
MAX = 180.0
scaled = min((x + y) * self.factor, MAX) # In range [0..MAX]
percent = scaled / MAX
r = InnerTile.START_COLOR_TUPLE[0] + (InnerTile.DELTAS[0] * percent)
g = InnerTile.START_COLOR_TUPLE[1] + (InnerTile.DELTAS[1] * percent)
b = InnerTile.START_COLOR_TUPLE[2] + (InnerTile.DELTAS[2] * percent)
self.setColor(wx.Colour(int(r), int(g), int(b)))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>EventManager</h2>
<p> The goal of the EventManager is to make wxWindows events more
'Pythonic' (ie. object-oriented) and easier to work with, without
impacting performance. It offers these features:
<p>
<ul>
<li> Allows any number of listeners to register for a single
event. (In addition to the standard wxPython feature of a single
listener being able to respond to many events.)
<li> Makes it easy to disconnect and reconnect listeners. This
has the effect of reducing the need for case-based branching in
application code.
<li> Has an object-oriented API. Programmers register to get
events directly from the objects that generate them, instead of
using ID numbers.
</ul>
<h3>Usage</h3>
<p>The EventManager class has three public methods. First get a
reference to it:
<PRE>
from wxPython.lib.evtmgr import eventManager
</PRE>
<p>...and then invoke any of the following methods. These methods are
'safe'; duplicate registrations or de-registrations will have no
effect.
<p><b>Registering a listener:</b>
<PRE>
eventManager.Register(listener, event, event-source)
</PRE>
<p><b>De-registering by window:</b>
<PRE>
eventManager.DeregisterWindow(event-source)
</PRE>
<p><b>De-registering by listener:</b>
<PRE>
eventManager.DeregisterListener(listener)
</PRE>
<p><b>Simple Example:</b>
<PRE>
from wxPython.lib.evtmgr import eventManager
aButton = wxButton(somePanel, -1, 'Click me')
eventManager.Register(self.someMethod, EVT_BUTTON, aButton)
</PRE>
<p> See the demo code as well as the documentation in the source of
<tt>wxPython.lib.evtmgr</tt> for more details.
<p>
by Robb Shecter (robb@acm.org)
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

163
demo/ExpandoTextCtrl.py Normal file
View File

@@ -0,0 +1,163 @@
import wx
from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
#----------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, title="Test ExpandoTextCtrl")
self.log = log
self.pnl = p = wx.Panel(self)
self.eom = ExpandoTextCtrl(p, size=(250,-1),
value="This control will expand as you type")
self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.eom)
# create some buttons and sizers to use in testing some
# features and also the layout
vBtnSizer = wx.BoxSizer(wx.VERTICAL)
btn = wx.Button(p, -1, "Set MaxHeight")
self.Bind(wx.EVT_BUTTON, self.OnSetMaxHeight, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(p, -1, "Set Font")
self.Bind(wx.EVT_BUTTON, self.OnSetFont, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(p, -1, "Write Text")
self.Bind(wx.EVT_BUTTON, self.OnWriteText, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(p, -1, "Append Text")
self.Bind(wx.EVT_BUTTON, self.OnAppendText, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(p, -1, "Set Value")
self.Bind(wx.EVT_BUTTON, self.OnSetValue, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(p, -1, "Get Value")
self.Bind(wx.EVT_BUTTON, self.OnGetValue, btn)
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
for x in range(3):
btn = wx.Button(p, -1, " ")
vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5)
self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn)
hBtnSizer = wx.BoxSizer(wx.HORIZONTAL)
for x in range(3):
btn = wx.Button(p, -1, " ")
hBtnSizer.Add(btn, 0, wx.ALL, 5)
self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn)
sizer = wx.BoxSizer(wx.HORIZONTAL)
col1 = wx.BoxSizer(wx.VERTICAL)
col1.Add(self.eom, 0, wx.ALL, 10)
col1.Add(hBtnSizer)
sizer.Add(col1)
sizer.Add(vBtnSizer)
p.SetSizer(sizer)
# Put the panel in a sizer for the frame so we can use self.Fit()
frameSizer = wx.BoxSizer()
frameSizer.Add(p, 1, wx.EXPAND)
self.SetSizer(frameSizer)
self.Fit()
def OnRefit(self, evt):
# The Expando control will redo the layout of the
# sizer it belongs to, but sometimes this may not be
# enough, so it will send us this event so we can do any
# other layout adjustments needed. In this case we'll
# just resize the frame to fit the new needs of the sizer.
self.Fit()
def OnSetMaxHeight(self, evt):
mh = self.eom.GetMaxHeight()
dlg = wx.NumberEntryDialog(self, "", "Enter new max height:",
"MaxHeight", mh, -1, 1000)
if dlg.ShowModal() == wx.ID_OK:
self.eom.SetMaxHeight(dlg.GetValue())
dlg.Destroy()
def OnSetFont(self, evt):
dlg = wx.FontDialog(self, wx.FontData())
dlg.GetFontData().SetInitialFont(self.eom.GetFont())
if dlg.ShowModal() == wx.ID_OK:
self.eom.SetFont(dlg.GetFontData().GetChosenFont())
dlg.Destroy()
def OnWriteText(self, evt):
self.eom.WriteText("\nThis is a test... Only a test. If this had "
"been a real emergency you would have seen the "
"quick brown fox jump over the lazy dog.\n")
def OnAppendText(self, evt):
self.eom.AppendText("\nAppended text.")
def OnSetValue(self, evt):
self.eom.SetValue("A new value.")
def OnGetValue(self, evt):
self.log.write("-----------------\n" + self.eom.GetValue())
def OnOtherBtn(self, evt):
# just for testing...
#print self.eom.numLines,
self.eom._adjustCtrl()
#print self.eom.numLines
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, " Test ExpandoTextCtrl ", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
self.win = TestFrame(self, self.log)
self.win.Show(True)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>ExpandoTextCtrl</center></h2>
The ExpandoTextCtrl is a multi-line wx.TextCtrl that will
adjust its height on the fly as needed to accomodate the number of
lines needed to display the current content of the control. It is
assumed that the width of the control will be a fixed value and
that only the height will be adjusted automatically. If the
control is used in a sizer then the width should be set as part of
the initial or min size of the control.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

82
demo/FancyText.py Normal file
View File

@@ -0,0 +1,82 @@
import wx
import wx.lib.fancytext as fancytext
#----------------------------------------------------------------------
test_str = ('<font style="italic" family="swiss" color="red" weight="bold" >'
'some |<sup>23</sup> <angle/>text<sub>with <angle/> subscript</sub>'
'</font> some other text')
test_str2 = '<font family="swiss" color="dark green" size="40">big green text</font>'
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
w, h = fancytext.GetExtent(test_str, dc)
fancytext.RenderToDC(test_str, dc, 20, 20)
fancytext.RenderToDC(test_str2, dc, 20, 20 + h + 10)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb)
return win
#----------------------------------------------------------------------
overview = \
"""
<html>
<body>
<h1>FancyText -- <i>methods for rendering XML specified text</i></h1>
<p>This module exports four main methods::
<pre>
def GetExtent(str, dc=None, enclose=True)
def GetFullExtent(str, dc=None, enclose=True)
def RenderToBitmap(str, background=None, enclose=True)
def RenderToDC(str, dc, x, y, enclose=True)
</pre>
In all cases, 'str' is an XML string. Note that start and end tags
are only required if *enclose* is set to False. In this case the
text should be wrapped in FancyText tags.
<p>In addition, the module exports one class::
<pre>
class StaticFancyText(self, window, id, text, background, ...)
</pre>
This class works similar to StaticText except it interprets its text
as FancyText.
<p>The text can support<sup>superscripts</sup> and <sub>subscripts</sub>, text
in different <font size="+3">sizes</font>, <font color="blue">colors</font>,
<i>styles</i>, <b>weights</b> and
<font family="script">families</font>. It also supports a limited set of symbols,
currently <times/>, <infinity/>, <angle/> as well as greek letters in both
upper case (<Alpha/><Beta/>...<Omega/>) and lower case (<alpha/><beta/>...<omega/>).
</font></font>
The End
</body>
</html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

99
demo/FileBrowseButton.py Normal file
View File

@@ -0,0 +1,99 @@
""" Demonstrate filebrowsebutton module of the wxPython.lib Library.
14.1.2001 Bernhard Reiter <bernhard@intevation.de>
Added demo for DirBrowseButton and improved overview text.
"""
import wx
import wx.lib.filebrowsebutton as filebrowse
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, ID, log):
wx.Panel.__init__(self, parent, ID)
self.log = log
self.fbb = filebrowse.FileBrowseButton(
self, -1, size=(450, -1), changeCallback = self.fbbCallback
)
self.fbbh = filebrowse.FileBrowseButtonWithHistory(
self, -1, size=(450, -1), changeCallback = self.fbbhCallback
)
self.dbb = filebrowse.DirBrowseButton(
self, -1, size=(450, -1), changeCallback = self.dbbCallback
)
self.fbbh.callCallback = False
self.fbbh.SetHistory(['You', 'can', 'put', 'some', 'filenames', 'here'], 4)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.fbb, 0, wx.ALL, 5)
sizer.Add(self.fbbh, 0, wx.ALL, 5)
sizer.Add(self.dbb, 0, wx.ALL, 5)
box = wx.BoxSizer()
box.Add(sizer, 0, wx.ALL, 20)
self.SetSizer(box)
def fbbCallback(self, evt):
self.log.write('FileBrowseButton: %s\n' % evt.GetString())
def fbbhCallback(self, evt):
if hasattr(self, 'fbbh'):
value = evt.GetString()
if not value:
return
self.log.write('FileBrowseButtonWithHistory: %s\n' % value)
history = self.fbbh.GetHistory()
if value not in history:
history.append(value)
self.fbbh.SetHistory(history)
self.fbbh.GetHistoryControl().SetStringSelection(value)
def dbbCallback(self, evt):
self.log.write('DirBrowseButton: %s\n' % evt.GetString())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, -1, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>class FileBrowseButton:</h2>
<small><pre>
%s
</pre></small>
<h2>class FileBrowseButtonWithHistory(FileBrowseButton):</h2>
<small><pre>
%s
</pre></small>
<h2>class DirBrowseButton(FileBrowseButton):</h2>
<small><pre>
%s
</pre></small>
</body><</html>
""" % ( filebrowse.FileBrowseButton.__doc__,
filebrowse.FileBrowseButtonWithHistory.__doc__ ,
filebrowse.DirBrowseButton.__doc__
)
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

143
demo/FileDialog.py Normal file
View File

@@ -0,0 +1,143 @@
import os
import wx
#---------------------------------------------------------------------------
# This is how you pre-establish a file filter so that the dialog
# only shows the extension(s) you want it to.
wildcard = "Python source (*.py)|*.py|" \
"Compiled Python (*.pyc)|*.pyc|" \
"SPAM files (*.spam)|*.spam|" \
"Egg file (*.egg)|*.egg|" \
"All files (*.*)|*.*"
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show an OPEN FileDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
b = wx.Button(self, -1, "Create and Show a SAVE FileDialog", (50,90))
self.Bind(wx.EVT_BUTTON, self.OnButton2, b)
def OnButton(self, evt):
self.log.WriteText("CWD: %s\n" % os.getcwd())
# Create the dialog. In this case the current directory is forced as the starting
# directory for the dialog, and no default file name is forced. This can easilly
# be changed in your program. This is an 'open' dialog, and allows multitple
# file selections as well.
#
# Finally, if the directory is changed in the process of getting files, this
# dialog is set up to change the current working directory to the path chosen.
dlg = wx.FileDialog(
self, message="Choose a file",
defaultDir=os.getcwd(),
defaultFile="",
wildcard=wildcard,
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
)
# Show the dialog and retrieve the user response. If it is the OK response,
# process the data.
if dlg.ShowModal() == wx.ID_OK:
# This returns a Python list of files that were selected.
paths = dlg.GetPaths()
self.log.WriteText('You selected %d files:' % len(paths))
for path in paths:
self.log.WriteText(' %s\n' % path)
# Compare this with the debug above; did we change working dirs?
self.log.WriteText("CWD: %s\n" % os.getcwd())
# Destroy the dialog. Don't do this until you are done with it!
# BAD things can happen otherwise!
dlg.Destroy()
def OnButton2(self, evt):
self.log.WriteText("CWD: %s\n" % os.getcwd())
# Create the dialog. In this case the current directory is forced as the starting
# directory for the dialog, and no default file name is forced. This can easilly
# be changed in your program. This is an 'save' dialog.
#
# Unlike the 'open dialog' example found elsewhere, this example does NOT
# force the current working directory to change if the user chooses a different
# directory than the one initially set.
dlg = wx.FileDialog(
self, message="Save file as ...", defaultDir=os.getcwd(),
defaultFile="", wildcard=wildcard, style=wx.SAVE
)
# This sets the default filter that the user will initially see. Otherwise,
# the first filter in the list will be used by default.
dlg.SetFilterIndex(2)
# Show the dialog and retrieve the user response. If it is the OK response,
# process the data.
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.log.WriteText('You selected "%s"' % path)
# Normally, at this point you would save your data using the file and path
# data that the user provided to you, but since we didn't actually start
# with any data to work with, that would be difficult.
#
# The code to do so would be similar to this, assuming 'data' contains
# the data you want to save:
#
# fp = file(path, 'w') # Create file anew
# fp.write(data)
# fp.close()
#
# You might want to add some error checking :-)
#
# Note that the current working dir didn't change. This is good since
# that's the way we set it up.
self.log.WriteText("CWD: %s\n" % os.getcwd())
# Destroy the dialog. Don't do this until you are done with it!
# BAD things can happen otherwise!
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
This class provides the file selection dialog. It incorporates OS-native features
depending on the OS in use, and can be used both for open and save operations.
The files displayed can be filtered by setting up a wildcard filter, multiple files
can be selected (open only), and files can be forced in a read-only mode.
There are two ways to get the results back from the dialog. GetFiles() returns only
the file names themselves, in a Python list. GetPaths() returns the full path and
filenames combined as a Python list.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

143
demo/FileHistory.py Normal file
View File

@@ -0,0 +1,143 @@
import os
import wx
#----------------------------------------------------------------------
text = """\
Right-click on the panel above the line to get a menu. This menu will
be managed by a FileHistory object and so the files you select will
automatically be added to the end of the menu and will be selectable
the next time the menu is viewed. The filename selected, either via the
Open menu item, or from the history, will be displayed in the log
window below.
"""
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
box = wx.BoxSizer(wx.VERTICAL)
# Make and layout the controls
fs = self.GetFont().GetPointSize()
bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD)
nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL)
t = wx.StaticText(self, -1, "FileHistory")
t.SetFont(bf)
box.Add(t, 0, wx.CENTER|wx.ALL, 5)
box.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
box.Add((10,20))
t = wx.StaticText(self, -1, text)
t.SetFont(nf)
box.Add(t, 0, wx.CENTER|wx.ALL, 5)
self.SetSizer(box)
self.SetAutoLayout(True)
# Make a menu
self.menu = m = wx.Menu()
# Little know wx Fact #42: there are a number of pre-set IDs
# in the wx package, to be used for common controls such as those
# illustrated below. Neat, huh?
m.Append(wx.ID_NEW, "&New")
m.Append(wx.ID_OPEN, "&Open...")
m.Append(wx.ID_CLOSE, "&Close")
m.Append(wx.ID_SAVE, "&Save")
m.Append(wx.ID_SAVEAS, "Save &as...")
m.Enable(wx.ID_NEW, False)
m.Enable(wx.ID_CLOSE, False)
m.Enable(wx.ID_SAVE, False)
m.Enable(wx.ID_SAVEAS, False)
# and a file history
self.filehistory = wx.FileHistory()
self.filehistory.UseMenu(self.menu)
# and finally the event handler bindings
self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
self.Bind(wx.EVT_MENU, self.OnFileOpenDialog, id=wx.ID_OPEN)
self.Bind(
wx.EVT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9
)
self.Bind(wx.EVT_WINDOW_DESTROY, self.Cleanup)
def Cleanup(self, *args):
# A little extra cleanup is required for the FileHistory control
del self.filehistory
self.menu.Destroy()
def OnRightClick(self, evt):
self.PopupMenu(self.menu)
def OnFileOpenDialog(self, evt):
dlg = wx.FileDialog(self,
defaultDir = os.getcwd(),
wildcard = "All Files|*",
style = wx.OPEN | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.log.write("You selected %s\n" % path)
# add it to the history
self.filehistory.AddFileToHistory(path)
dlg.Destroy()
def OnFileHistory(self, evt):
# get the file based on the menu ID
fileNum = evt.GetId() - wx.ID_FILE1
path = self.filehistory.GetHistoryFile(fileNum)
self.log.write("You selected %s\n" % path)
# add it back to the history so it will be moved up the list
self.filehistory.AddFileToHistory(path)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h3>FileHistory</h3>
wxFileHistory encapsulates functionality to record the last few files
visited, and to allow the user to quickly load these files using the
list appended to a menu, such as the File menu.
<p>Note that this inclusion is not automatic; as illustrated in this example,
you must add files (and remove them) as deemed necessary within the framework
of your program.
<p>Note also the additional cleanup required for this class, namely trapping the
enclosing window's Destroy event and deleting the file history control and its
associated menu.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

121
demo/FindReplaceDialog.py Normal file
View File

@@ -0,0 +1,121 @@
# 11/17/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Updated for wx namespace
#
# 11/28/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o Changed the event binding slightly.
import wx
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
self.findData = wx.FindReplaceData()
self.fbtn = wx.Button(self, -1, "Show Find Dialog", (25, 50))
self.Bind(wx.EVT_BUTTON, self.OnShowFind, self.fbtn)
self.frbtn = wx.Button(self, -1, "Show Find && Replace Dialog", (25, 90))
self.Bind(wx.EVT_BUTTON, self.OnShowFindReplace, self.frbtn)
def BindFindEvents(self, win):
win.Bind(wx.EVT_FIND, self.OnFind)
win.Bind(wx.EVT_FIND_NEXT, self.OnFind)
win.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
win.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
win.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
def EnableButtons(self):
self.fbtn.Enable()
self.frbtn.Enable()
def DisableButtons(self):
self.fbtn.Disable()
self.frbtn.Disable()
def OnShowFind(self, evt):
self.DisableButtons()
dlg = wx.FindReplaceDialog(self, self.findData, "Find")
self.BindFindEvents(dlg)
dlg.Show(True)
def OnShowFindReplace(self, evt):
self.DisableButtons()
dlg = wx.FindReplaceDialog(self, self.findData, "Find & Replace", wx.FR_REPLACEDIALOG)
self.BindFindEvents(dlg)
dlg.Show(True)
def OnFind(self, evt):
#print repr(evt.GetFindString()), repr(self.findData.GetFindString())
map = {
wx.wxEVT_COMMAND_FIND : "FIND",
wx.wxEVT_COMMAND_FIND_NEXT : "FIND_NEXT",
wx.wxEVT_COMMAND_FIND_REPLACE : "REPLACE",
wx.wxEVT_COMMAND_FIND_REPLACE_ALL : "REPLACE_ALL",
}
et = evt.GetEventType()
if et in map:
evtType = map[et]
else:
evtType = "**Unknown Event Type**"
if et in [wx.wxEVT_COMMAND_FIND_REPLACE, wx.wxEVT_COMMAND_FIND_REPLACE_ALL]:
replaceTxt = "Replace text: %s" % evt.GetReplaceString()
else:
replaceTxt = ""
self.log.write("%s -- Find text: %s %s Flags: %d \n" %
(evtType, evt.GetFindString(), replaceTxt, evt.GetFlags()))
def OnFindClose(self, evt):
self.log.write("FindReplaceDialog closing...\n")
evt.GetDialog().Destroy()
self.EnableButtons()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
FindReplaceDialog is a standard modeless dialog which is used to allow the user
to search for some text (and possibly replace it with something else). The actual
searching is supposed to be done in the owner window which is the parent of this
dialog. Note that it means that unlike for the other standard dialogs this one
<u>must have a parent window</u>. Also note that there is no way to use this
dialog in a modal way; <b>it is always, by design and implementation, modeless</b>.
FileReplaceDialog requires the use of <b>FindReplaceData</b>. This holds the
data for the dialog. It is used to initialize the dialog with the default values
and will keep the last values from the dialog when it is closed. It is also
updated each time a FindDialogEvent is generated so instead of using the
FindDialogEvent methods you can also directly query this object. <b>Care must be
taken not to use this object after the dialog is destroyed.</b> The data within
will be invalid after the parent dialog is destroyed.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

145
demo/FloatBar.py Normal file
View File

@@ -0,0 +1,145 @@
#
# Please note that wx.lib.floatbar is not formally supported as
# part of wxPython. If it works, fine. If not, unfortunate.
# GTK users can use the wx.TB_DOCKABLE flag with a regular
# wx.ToolBar, but everyone else has to take their chances.
#
import wx
import wx.lib.floatbar
import images
class TestFloatBar(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(
self, parent, -1, 'Test ToolBar', wx.DefaultPosition, (500, 300)
)
self.log = log
win = wx.Window(self, -1)
win.SetBackgroundColour("WHITE")
wx.StaticText(
win, -1, "Drag the toolbar to float it,\n"
"Toggle the last tool to remove\nthe title.", (15,15)
)
tb = wx.lib.floatbar.FloatBar(self, -1)
self.SetToolBar(tb)
tb.SetFloatable(1)
tb.SetTitle("Floating!")
self.CreateStatusBar()
tsize = (16,16)
new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize)
open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize)
copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize)
paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize)
tb.AddSimpleTool(10, new_bmp, "New", "Long help for 'New'")
self.Bind(wx.EVT_TOOL, self.OnToolClick, id=10)
self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=10)
tb.AddSimpleTool(20, open_bmp, "Open")
self.Bind(wx.EVT_TOOL, self.OnToolClick, id=20)
self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=20)
tb.AddSeparator()
tb.AddSimpleTool(30, copy_bmp, "Copy")
self.Bind(wx.EVT_TOOL, self.OnToolClick, id=30)
self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=30)
tb.AddSimpleTool(40, paste_bmp, "Paste")
self.Bind(wx.EVT_TOOL, self.OnToolClick, id=40)
self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=40)
tb.AddSeparator()
tb.AddCheckTool(60, images.Tog1.GetBitmap(), images.Tog2.GetBitmap())
self.Bind(wx.EVT_TOOL, self.OnToolClick, id=60)
self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=60)
tb.Realize()
self.tb = tb
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseWindow(self, event):
self.Destroy()
def OnToolClick(self, event):
self.log.WriteText("tool %s clicked\n" % event.GetId())
if event.GetId() == 60:
print event.GetExtraLong(), event.IsChecked(), event.GetInt(), self.tb.GetToolState(60)
if event.GetExtraLong():
self.tb.SetTitle("")
else:
self.tb.SetTitle("Floating!")
def OnToolRClick(self, event):
self.log.WriteText("tool %s right-clicked\n" % event.GetId())
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Show the FloatBar sample", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
if wx.Platform == "__WXMAC__":
dlg = wx.MessageDialog(
self, 'FloatBar does not work well on this platform.',
'Sorry', wx.OK | wx.ICON_WARNING
)
dlg.ShowModal()
dlg.Destroy()
else:
win = TestFloatBar(self, self.log)
win.Show(True)
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
FloatBar is a subclass of wx.ToolBar, implemented in Python, which
can be detached from its frame.
Drag the toolbar with the mouse to make it float, and drag it back, or
close it to make the toolbar return to its original position.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

1960
demo/FloatCanvas.py Normal file

File diff suppressed because it is too large Load Diff

141
demo/FontDialog.py Normal file
View File

@@ -0,0 +1,141 @@
import wx
from wx.lib import stattext
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
btn = wx.Button(self, -1, "Select Font")
self.Bind(wx.EVT_BUTTON, self.OnSelectFont, btn)
self.sampleText = stattext.GenStaticText(self, -1, "Sample Text")
self.sampleText.SetBackgroundColour(wx.WHITE)
self.curFont = self.sampleText.GetFont()
self.curClr = wx.BLACK
fgs = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
fgs.AddGrowableCol(1)
fgs.AddGrowableRow(0)
fgs.Add(btn)
fgs.Add(self.sampleText, 0, wx.ADJUST_MINSIZE|wx.GROW)
fgs.Add((15,15)); fgs.Add((15,15)) # an empty row
fgs.Add(wx.StaticText(self, -1, "PointSize:"))
self.ps = wx.StaticText(self, -1, "")
font = self.ps.GetFont()
font.SetWeight(wx.BOLD)
self.ps.SetFont(font)
fgs.Add(self.ps, 0, wx.ADJUST_MINSIZE)
fgs.Add(wx.StaticText(self, -1, "Family:"))
self.family = wx.StaticText(self, -1, "")
self.family.SetFont(font)
fgs.Add(self.family, 0, wx.ADJUST_MINSIZE)
fgs.Add(wx.StaticText(self, -1, "Style:"))
self.style = wx.StaticText(self, -1, "")
self.style.SetFont(font)
fgs.Add(self.style, 0, wx.ADJUST_MINSIZE)
fgs.Add(wx.StaticText(self, -1, "Weight:"))
self.weight = wx.StaticText(self, -1, "")
self.weight.SetFont(font)
fgs.Add(self.weight, 0, wx.ADJUST_MINSIZE)
fgs.Add(wx.StaticText(self, -1, "Face:"))
self.face = wx.StaticText(self, -1, "")
self.face.SetFont(font)
fgs.Add(self.face, 0, wx.ADJUST_MINSIZE)
fgs.Add((15,15)); fgs.Add((15,15)) # an empty row
fgs.Add(wx.StaticText(self, -1, "wx.NativeFontInfo:"))
self.nfi = wx.StaticText(self, -1, "")
self.nfi.SetFont(font)
fgs.Add(self.nfi, 0, wx.ADJUST_MINSIZE)
# give it some border space
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(fgs, 0, wx.GROW|wx.ADJUST_MINSIZE|wx.ALL, 25)
self.SetSizer(sizer)
self.UpdateUI()
def UpdateUI(self):
self.sampleText.SetFont(self.curFont)
self.sampleText.SetForegroundColour(self.curClr)
self.ps.SetLabel(str(self.curFont.GetPointSize()))
self.family.SetLabel(self.curFont.GetFamilyString())
self.style.SetLabel(self.curFont.GetStyleString())
self.weight.SetLabel(self.curFont.GetWeightString())
self.face.SetLabel(self.curFont.GetFaceName())
self.nfi.SetLabel(self.curFont.GetNativeFontInfo().ToString())
self.Layout()
def OnSelectFont(self, evt):
data = wx.FontData()
data.EnableEffects(True)
data.SetColour(self.curClr) # set colour
data.SetInitialFont(self.curFont)
dlg = wx.FontDialog(self, data)
if dlg.ShowModal() == wx.ID_OK:
data = dlg.GetFontData()
font = data.GetChosenFont()
colour = data.GetColour()
self.log.WriteText('You selected: "%s", %d points, color %s\n' %
(font.GetFaceName(), font.GetPointSize(),
colour.Get()))
self.curFont = font
self.curClr = colour
self.UpdateUI()
# Don't destroy the dialog until you get everything you need from the
# dialog!
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
This class allows you to use the system font selection dialog
from within your program. Generally speaking, this allows you
to select a font by its name, font size, and weight, and
on some systems such things as strikethrough and underline.
As with other dialogs used in wxPython, it is important to
use the class' methods to extract the information you need
about the font <b>before</b> you destroy the dialog. Failure
to observe this almost always leads to a program failure of
some sort, often ugly.
This demo serves two purposes; it shows how to use the dialog
to GET font information from the user, but also shows how
to APPLY that information once you get it.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

80
demo/FontEnumerator.py Normal file
View File

@@ -0,0 +1,80 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
e = wx.FontEnumerator()
e.EnumerateFacenames()
list = e.GetFacenames()
list.sort()
s1 = wx.StaticText(self, -1, "Face names:")
self.lb1 = wx.ListBox(self, -1, wx.DefaultPosition, (200, 250),
list, wx.LB_SINGLE)
self.Bind(wx.EVT_LISTBOX, self.OnSelect, id=self.lb1.GetId())
self.txt = wx.StaticText(self, -1, "Sample text...", (285, 50))
row = wx.BoxSizer(wx.HORIZONTAL)
row.Add(s1, 0, wx.ALL, 5)
row.Add(self.lb1, 0, wx.ALL, 5)
row.Add(self.txt, 0, wx.ALL|wx.ADJUST_MINSIZE, 5)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(row, 0, wx.ALL, 30)
self.SetSizer(sizer)
self.Layout()
self.lb1.SetSelection(0)
self.OnSelect(None)
wx.FutureCall(300, self.SetTextSize)
def SetTextSize(self):
self.txt.SetSize(self.txt.GetBestSize())
def OnSelect(self, evt):
face = self.lb1.GetStringSelection()
font = wx.Font(28, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, face)
self.txt.SetLabel(face)
self.txt.SetFont(font)
if wx.Platform == "__WXMAC__": self.Refresh()
## st = font.GetNativeFontInfo().ToString()
## ni2 = wx.NativeFontInfo()
## ni2.FromString(st)
## font2 = wx.FontFromNativeInfo(ni2)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
wxFontEnumerator enumerates either all available fonts on the system or only
the ones with given attributes - either only fixed-width (suited for use in
programs such as terminal emulators and the like) or the fonts available in
the given encoding.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

84
demo/Frame.py Normal file
View File

@@ -0,0 +1,84 @@
import wx
#---------------------------------------------------------------------------
class MyFrame(wx.Frame):
def __init__(
self, parent, ID, title, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
):
wx.Frame.__init__(self, parent, ID, title, pos, size, style)
panel = wx.Panel(self, -1)
button = wx.Button(panel, 1003, "Close Me")
button.SetPosition((15, 15))
self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseMe(self, event):
self.Close(True)
def OnCloseWindow(self, event):
self.Destroy()
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a Frame", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
win = MyFrame(self, -1, "This is a wx.Frame", size=(350, 200),
style = wx.DEFAULT_FRAME_STYLE)
win.Show(True)
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
A Frame is a window whose size and position can (usually) be changed by
the user. It usually has thick borders and a title bar, and can optionally
contain a menu bar, toolbar and status bar. A frame can contain any window
that is not a Frame or Dialog. It is one of the most fundamental of the
wxWindows components.
A Frame that has a status bar and toolbar created via the
<code>CreateStatusBar</code> / <code>CreateToolBar</code> functions manages
these windows, and adjusts the value returned by <code>GetClientSize</code>
to reflect the remaining size available to application windows.
By itself, a Frame is not too useful, but with the addition of Panels and
other child objects, it encompasses the framework around which most user
interfaces are constructed.
If you plan on using Sizers and auto-layout features, be aware that the Frame
class lacks the ability to handle these features unless it contains a Panel.
The Panel has all the necessary functionality to both control the size of
child components, and also communicate that information in a useful way to
the Frame itself.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

60
demo/GIFAnimationCtrl.py Normal file
View File

@@ -0,0 +1,60 @@
import wx
from wx.animate import GIFAnimationCtrl
from Main import opj
GIFNames = [
'bitmaps/AG00178_.gif',
'bitmaps/BD13656_.gif',
'bitmaps/AG00185_.gif',
'bitmaps/AG00039_.gif',
'bitmaps/AG00183_.gif',
'bitmaps/AG00028_.gif',
]
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
for name in GIFNames:
ani = GIFAnimationCtrl(self, -1, opj(name))
ani.GetPlayer().UseBackgroundColour(True)
ani.Play()
sizer.Add(ani, 0, wx.ALL, 10)
border = wx.BoxSizer()
border.Add(sizer, 1, wx.EXPAND|wx.ALL, 20)
self.SetSizer(border)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.animate.GIFAnimationCtrl</center></h2>
wx.animate.GIFAnimationCtrl is like a wx.StaticBitmap but is able to
display an animation by extracing frames from a multi-images GIF file.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

290
demo/GLCanvas.py Normal file
View File

@@ -0,0 +1,290 @@
import wx
import sys
try:
from wx import glcanvas
haveGLCanvas = True
except ImportError:
haveGLCanvas = False
try:
# The Python OpenGL package can be found at
# http://PyOpenGL.sourceforge.net/
from OpenGL.GL import *
from OpenGL.GLUT import *
haveOpenGL = True
except ImportError:
haveOpenGL = False
#----------------------------------------------------------------------
buttonDefs = {
wx.NewId() : ('CubeCanvas', 'Cube'),
wx.NewId() : ('ConeCanvas', 'Cone'),
}
class ButtonPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
box = wx.BoxSizer(wx.VERTICAL)
box.Add((20, 30))
keys = buttonDefs.keys()
keys.sort()
for k in keys:
text = buttonDefs[k][1]
btn = wx.Button(self, k, text)
box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15)
self.Bind(wx.EVT_BUTTON, self.OnButton, btn)
#** Enable this to show putting a GLCanvas on the wx.Panel
if 1:
c = CubeCanvas(self)
c.SetMinSize((200, 200))
box.Add(c, 0, wx.ALIGN_CENTER|wx.ALL, 15)
self.SetAutoLayout(True)
self.SetSizer(box)
def OnButton(self, evt):
if not haveGLCanvas:
dlg = wx.MessageDialog(self,
'The GLCanvas class has not been included with this build of wxPython!',
'Sorry', wx.OK | wx.ICON_WARNING)
dlg.ShowModal()
dlg.Destroy()
elif not haveOpenGL:
dlg = wx.MessageDialog(self,
'The OpenGL package was not found. You can get it at\n'
'http://PyOpenGL.sourceforge.net/',
'Sorry', wx.OK | wx.ICON_WARNING)
dlg.ShowModal()
dlg.Destroy()
else:
canvasClassName = buttonDefs[evt.GetId()][0]
canvasClass = eval(canvasClassName)
frame = wx.Frame(None, -1, canvasClassName, size=(400,400))
canvas = canvasClass(frame)
frame.Show(True)
class MyCanvasBase(glcanvas.GLCanvas):
def __init__(self, parent):
glcanvas.GLCanvas.__init__(self, parent, -1)
self.init = False
self.context = glcanvas.GLContext(self)
# initial mouse position
self.lastx = self.x = 30
self.lasty = self.y = 30
self.size = None
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
def OnEraseBackground(self, event):
pass # Do nothing, to avoid flashing on MSW.
def OnSize(self, event):
wx.CallAfter(self.DoSetViewport)
event.Skip()
def DoSetViewport(self):
size = self.size = self.GetClientSize()
self.SetCurrent(self.context)
glViewport(0, 0, size.width, size.height)
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.SetCurrent(self.context)
if not self.init:
self.InitGL()
self.init = True
self.OnDraw()
def OnMouseDown(self, evt):
self.CaptureMouse()
self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
def OnMouseUp(self, evt):
self.ReleaseMouse()
def OnMouseMotion(self, evt):
if evt.Dragging() and evt.LeftIsDown():
self.lastx, self.lasty = self.x, self.y
self.x, self.y = evt.GetPosition()
self.Refresh(False)
class CubeCanvas(MyCanvasBase):
def InitGL(self):
# set viewing projection
glMatrixMode(GL_PROJECTION)
glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
# position viewer
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0, 0.0, -2.0)
# position object
glRotatef(self.y, 1.0, 0.0, 0.0)
glRotatef(self.x, 0.0, 1.0, 0.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
def OnDraw(self):
# clear color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# draw six faces of a cube
glBegin(GL_QUADS)
glNormal3f( 0.0, 0.0, 1.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5,-0.5, 0.5)
glVertex3f( 0.5,-0.5, 0.5)
glNormal3f( 0.0, 0.0,-1.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f(-0.5, 0.5,-0.5)
glVertex3f( 0.5, 0.5,-0.5)
glVertex3f( 0.5,-0.5,-0.5)
glNormal3f( 0.0, 1.0, 0.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f( 0.5, 0.5,-0.5)
glVertex3f(-0.5, 0.5,-0.5)
glVertex3f(-0.5, 0.5, 0.5)
glNormal3f( 0.0,-1.0, 0.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f( 0.5,-0.5,-0.5)
glVertex3f( 0.5,-0.5, 0.5)
glVertex3f(-0.5,-0.5, 0.5)
glNormal3f( 1.0, 0.0, 0.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f( 0.5,-0.5, 0.5)
glVertex3f( 0.5,-0.5,-0.5)
glVertex3f( 0.5, 0.5,-0.5)
glNormal3f(-1.0, 0.0, 0.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f(-0.5,-0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5,-0.5)
glEnd()
if self.size is None:
self.size = self.GetClientSize()
w, h = self.size
w = max(w, 1.0)
h = max(h, 1.0)
xScale = 180.0 / w
yScale = 180.0 / h
glRotatef((self.y - self.lasty) * yScale, 1.0, 0.0, 0.0);
glRotatef((self.x - self.lastx) * xScale, 0.0, 1.0, 0.0);
self.SwapBuffers()
class ConeCanvas(MyCanvasBase):
def InitGL( self ):
glMatrixMode(GL_PROJECTION)
# camera frustrum setup
glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
glMaterial(GL_FRONT, GL_AMBIENT, [0.2, 0.2, 0.2, 1.0])
glMaterial(GL_FRONT, GL_DIFFUSE, [0.8, 0.8, 0.8, 1.0])
glMaterial(GL_FRONT, GL_SPECULAR, [1.0, 0.0, 1.0, 1.0])
glMaterial(GL_FRONT, GL_SHININESS, 50.0)
glLight(GL_LIGHT0, GL_AMBIENT, [0.0, 1.0, 0.0, 1.0])
glLight(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0])
glLight(GL_LIGHT0, GL_SPECULAR, [1.0, 1.0, 1.0, 1.0])
glLight(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.2, 0.2, 0.2, 1.0])
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# position viewer
glMatrixMode(GL_MODELVIEW)
# position viewer
glTranslatef(0.0, 0.0, -2.0);
#
glutInit(sys.argv)
def OnDraw(self):
# clear color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# use a fresh transformation matrix
glPushMatrix()
# position object
#glTranslate(0.0, 0.0, -2.0)
glRotate(30.0, 1.0, 0.0, 0.0)
glRotate(30.0, 0.0, 1.0, 0.0)
glTranslate(0, -1, 0)
glRotate(250, 1, 0, 0)
glutSolidCone(0.5, 1, 30, 5)
glPopMatrix()
glRotatef((self.y - self.lasty), 0.0, 0.0, 1.0);
glRotatef((self.x - self.lastx), 1.0, 0.0, 0.0);
# push into visible buffer
self.SwapBuffers()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = ButtonPanel(nb, log)
return win
overview = """\
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
#----------------------------------------------------------------------

60
demo/Gauge.py Normal file
View File

@@ -0,0 +1,60 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
self.count = 0
wx.StaticText(self, -1, "This example shows the wx.Gauge control.", (45, 15))
self.g1 = wx.Gauge(self, -1, 50, (110, 50), (250, 25))
self.g2 = wx.Gauge(self, -1, 50, (110, 95), (250, 25))
self.Bind(wx.EVT_TIMER, self.TimerHandler)
self.timer = wx.Timer(self)
self.timer.Start(100)
def __del__(self):
self.timer.Stop()
def TimerHandler(self, event):
self.count = self.count + 1
if self.count >= 50:
self.count = 0
self.g1.SetValue(self.count)
self.g2.Pulse()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
A Gauge is a horizontal or vertical bar which shows a quantity in a graphical
fashion. It is often used to indicate progress through lengthy tasks, such as
file copying or data analysis.
When the Gauge is initialized, it's "complete" value is usually set; at any rate,
before using the Gauge, the maximum value of the control must be set. As the task
progresses, the Gauge is updated by the program via the <code>SetValue</code> method.
This control is for use within a GUI; there is a seperate ProgressDialog class
to present the same sort of control as a dialog to the user.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

184
demo/GenericButtons.py Normal file
View File

@@ -0,0 +1,184 @@
import wx
import wx.lib.buttons as buttons
import images
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
##self.SetBackgroundColour("sky blue")
sizer = wx.FlexGridSizer(cols=3, hgap=20, vgap=20)
# A regular button, selected as the default button
b = wx.Button(self, -1, "A real button")
b.SetDefault()
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
# Same thing, but NOT set as the default button
b = wx.Button(self, -1, "non-default")
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
sizer.Add((10,10))
# Plain old text button based off GenButton()
b = buttons.GenButton(self, -1, 'Hello')
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
# Plain old text button, disabled.
b = buttons.GenButton(self, -1, 'disabled')
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
b.Enable(False)
sizer.Add(b)
# This time, we let the botton be as big as it can be.
# Also, this one is fancier, with custom colors and bezel size.
b = buttons.GenButton(self, -1, 'bigger')
self.Bind(wx.EVT_BUTTON, self.OnBiggerButton, b)
b.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD, False))
b.SetBezelWidth(5)
b.SetMinSize(wx.DefaultSize)
b.SetBackgroundColour("Navy")
b.SetForegroundColour(wx.WHITE)
b.SetToolTipString("This is a BIG button...")
# let the sizer set best size
sizer.Add(b, flag=wx.ADJUST_MINSIZE)
# An image button
bmp = images.Test2.GetBitmap()
b = buttons.GenBitmapButton(self, -1, bmp)
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
# An image button, disabled.
bmp = images.Test2.GetBitmap()
b = buttons.GenBitmapButton(self, -1, bmp)
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
b.Enable(False)
# An image button, using a mask to get rid of the
# undesireable part of the image
b = buttons.GenBitmapButton(self, -1, None)
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
bmp = images.Bulb1.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapLabel(bmp)
bmp = images.Bulb2.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapSelected(bmp)
b.SetInitialSize()
sizer.Add(b)
# A toggle button
b = buttons.GenToggleButton(self, -1, "Toggle Button")
self.Bind(wx.EVT_BUTTON, self.OnToggleButton, b)
sizer.Add(b)
# An image toggle button
b = buttons.GenBitmapToggleButton(self, -1, None)
self.Bind(wx.EVT_BUTTON, self.OnToggleButton, b)
bmp = images.Bulb1.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapLabel(bmp)
bmp = images.Bulb2.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapSelected(bmp)
b.SetToggle(True)
b.SetInitialSize()
sizer.Add(b)
# A bitmap button with text.
b = buttons.GenBitmapTextButton(self, -1, None, "Bitmapped Text", size = (200, 45))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
bmp = images.Bulb1.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapLabel(bmp)
bmp = images.Bulb2.GetBitmap()
mask = wx.Mask(bmp, wx.BLUE)
bmp.SetMask(mask)
b.SetBitmapSelected(bmp)
b.SetUseFocusIndicator(False)
b.SetInitialSize()
sizer.Add(b)
# a flat text button
b = buttons.GenButton(self, -1, 'Flat buttons too!', style=wx.BORDER_NONE)
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b, flag=wx.ALIGN_CENTER_VERTICAL)
# A flat image button
bmp = images.Test2.GetBitmap()
bmp.SetMaskColour("blue")
b = buttons.GenBitmapButton(self, -1, bmp, style=wx.BORDER_NONE)
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
sizer.Add(b)
##b.SetBackgroundColour("sky blue")
##b.SetBackgroundColour("pink")
vbox = wx.BoxSizer(wx.VERTICAL)
sizer.Add(vbox)
b = buttons.ThemedGenButton(self, -1, 'Drawn with native renderer')
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
vbox.Add(b, 0, wx.ALL, 5)
b = buttons.ThemedGenToggleButton(self, -1, 'native renderered toggle')
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
vbox.Add(b, 0, wx.ALL, 5)
border = wx.BoxSizer(wx.VERTICAL)
border.Add(sizer, 0, wx.ALL, 25)
self.SetSizer(border)
def OnButton(self, event):
self.log.WriteText("Button Clicked: %d\n" % event.GetId())
def OnBiggerButton(self, event):
self.log.WriteText("Bigger Button Clicked: %d\n" % event.GetId())
b = event.GetEventObject()
txt = "big " + b.GetLabel()
b.SetLabel(txt)
self.GetSizer().Layout()
def OnToggleButton(self, event):
msg = (event.GetIsDown() and "on") or "off"
self.log.WriteText("Button %d Toggled: %s\n" % (event.GetId(), msg))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = buttons.__doc__
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

69
demo/GenericDirCtrl.py Normal file
View File

@@ -0,0 +1,69 @@
import wx
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
txt1 = wx.StaticText(self, -1, "style=0")
dir1 = wx.GenericDirCtrl(self, -1, size=(200,225), style=0)
txt2 = wx.StaticText(self, -1, "wx.DIRCTRL_DIR_ONLY")
dir2 = wx.GenericDirCtrl(self, -1, size=(200,225), style=wx.DIRCTRL_DIR_ONLY|wx.DIRCTRL_MULTIPLE)
txt3 = wx.StaticText(self, -1, "wx.DIRCTRL_SHOW_FILTERS")
dir3 = wx.GenericDirCtrl(self, -1, size=(200,225), style=wx.DIRCTRL_SHOW_FILTERS,
filter="All files (*.*)|*.*|Python files (*.py)|*.py")
sz = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
sz.Add((35, 35)) # some space above
sz.Add((35, 35))
sz.Add((35, 35))
sz.Add(txt1)
sz.Add(txt2)
sz.Add(txt3)
sz.Add(dir1, 0, wx.EXPAND)
sz.Add(dir2, 0, wx.EXPAND)
sz.Add(dir3, 0, wx.EXPAND)
sz.Add((35,35)) # some space below
sz.AddGrowableRow(2)
sz.AddGrowableCol(0)
sz.AddGrowableCol(1)
sz.AddGrowableCol(2)
self.SetSizer(sz)
self.SetAutoLayout(True)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
This control can be used to place a directory listing (with optional files)
on an arbitrary window. The control contains a TreeCtrl window representing
the directory hierarchy, and optionally, a Choice window containing a list
of filters.
The filters work in the same manner as in FileDialog.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

158
demo/GetMouseState.py Normal file
View File

@@ -0,0 +1,158 @@
import wx
#----------------------------------------------------------------------
class StaticText(wx.StaticText):
"""
A StaticText that only updates the label if it has changed, to
help reduce potential flicker since these controls would be
updated very frequently otherwise.
"""
def SetLabel(self, label):
if label <> self.GetLabel():
wx.StaticText.SetLabel(self, label)
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
sizer.Add((25,25))
sizer.Add(wx.StaticText(
self, -1,
"Mouse and modifier state can be polled with wx.GetMouseState"),
0, wx.CENTER|wx.ALL, 10)
sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.TOP, 10)
row = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(row, 0, wx.CENTER)
fgs = wx.FlexGridSizer(cols=2, hgap=5, vgap=10)
row.Add(fgs, 0, wx.ALL, 30)
lbl = StaticText(self, -1, "X pos:")
self.x = StaticText(self, -1, "00000")
fgs.Add(lbl)
fgs.Add(self.x)
lbl = StaticText(self, -1, "Y pos:")
self.y = StaticText(self, -1, "00000")
fgs.Add(lbl)
fgs.Add(self.y)
lbl = StaticText(self, -1, "Left down:")
self.lft = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.lft)
lbl = StaticText(self, -1, "Middle down:")
self.mid = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.mid)
lbl = StaticText(self, -1, "Right down:")
self.rgt = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.rgt)
lbl = StaticText(self, -1, "AUX1 down:")
self.aux1 = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.aux1)
lbl = StaticText(self, -1, "AUX2 down:")
self.aux2 = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.aux2)
fgs = wx.FlexGridSizer(cols=2, hgap=5, vgap=10)
row.Add(fgs, 0, wx.ALL, 30)
lbl = StaticText(self, -1, "Control down:")
self.ctrl = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.ctrl)
lbl = StaticText(self, -1, "Shift down:")
self.shft = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.shft)
lbl = StaticText(self, -1, "Alt down:")
self.alt = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.alt)
lbl = StaticText(self, -1, "Meta down:")
self.meta = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.meta)
lbl = StaticText(self, -1, "Cmd down:")
self.cmd = StaticText(self, -1, "False")
fgs.Add(lbl)
fgs.Add(self.cmd)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(100)
def OnTimer(self, evt):
ms = wx.GetMouseState()
self.x.SetLabel( str(ms.x) )
self.y.SetLabel( str(ms.y) )
self.lft.SetLabel( str(ms.leftIsDown) )
self.mid.SetLabel( str(ms.middleIsDown) )
self.rgt.SetLabel( str(ms.rightIsDown) )
self.aux1.SetLabel( str(ms.aux1IsDown) )
self.aux2.SetLabel( str(ms.aux2IsDown) )
self.ctrl.SetLabel( str(ms.controlDown) )
self.shft.SetLabel( str(ms.shiftDown) )
self.alt.SetLabel( str(ms.altDown) )
self.meta.SetLabel( str(ms.metaDown) )
self.cmd.SetLabel( str(ms.cmdDown) )
def ShutdownDemo(self):
self.timer.Stop()
del self.timer
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.GetMouseState</center></h2>
The mouse and modifier state can be polled with the wx.GetMouseState
function. It returns an instance of a wx.MouseState object that
contains the current position of the mouse pointer in screen
coordinates, as well as boolean values indicating the up/down status
of the mouse buttons and the modifier keys.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

219
demo/GraphicsContext.py Normal file
View File

@@ -0,0 +1,219 @@
import wx
import colorsys
from math import cos, sin, radians
from Main import opj
#----------------------------------------------------------------------
BASE = 80.0 # sizes used in shapes drawn below
BASE2 = BASE/2
BASE4 = BASE/4
USE_BUFFER = ('wxMSW' in wx.PlatformInfo) # use buffered drawing on Windows
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
if USE_BUFFER:
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, evt):
# When there is a size event then recreate the buffer to match
# the new size of the window.
self.InitBuffer()
evt.Skip()
def OnPaint(self, evt):
if USE_BUFFER:
# The buffer already contains our drawing, so no need to
# do anything else but create the buffered DC. When this
# method exits and dc is collected then the buffer will be
# blitted to the paint DC automagically
dc = wx.BufferedPaintDC(self, self._buffer)
else:
# Otherwise we need to draw our content to the paint DC at
# this time.
dc = wx.PaintDC(self)
gc = self.MakeGC(dc)
self.Draw(gc)
def InitBuffer(self):
sz = self.GetClientSize()
sz.width = max(1, sz.width)
sz.height = max(1, sz.height)
self._buffer = wx.EmptyBitmap(sz.width, sz.height, 32)
dc = wx.MemoryDC(self._buffer)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
gc = self.MakeGC(dc)
self.Draw(gc)
def MakeGC(self, dc):
try:
if False:
# If you want to force the use of Cairo instead of the
# native GraphicsContext backend then create the
# context like this. It works on Windows so far, (on
# wxGTK the Cairo context is already being used as the
# native default.)
gcr = wx.GraphicsRenderer.GetCairoRenderer
gc = gcr() and gcr().CreateContext(dc)
if gc is None:
wx.MessageBox("Unable to create Cairo Context.", "Oops")
gc = wx.GraphicsContext.Create(dc)
else:
# Otherwise, creating it this way will use the native
# backend, (GDI+ on Windows, CoreGraphics on Mac, or
# Cairo on GTK).
gc = wx.GraphicsContext.Create(dc)
except NotImplementedError:
dc.DrawText("This build of wxPython does not support the wx.GraphicsContext "
"family of classes.",
25, 25)
return None
return gc
def Draw(self, gc):
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.BOLD)
gc.SetFont(font)
# make a path that contains a circle and some lines, centered at 0,0
path = gc.CreatePath()
path.AddCircle(0, 0, BASE2)
path.MoveToPoint(0, -BASE2)
path.AddLineToPoint(0, BASE2)
path.MoveToPoint(-BASE2, 0)
path.AddLineToPoint(BASE2, 0)
path.CloseSubpath()
path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4)
# Now use that path to demonstrate various capbilites of the grpahics context
gc.PushState() # save current translation/scale/other state
gc.Translate(60, 75) # reposition the context origin
gc.SetPen(wx.Pen("navy", 1))
gc.SetBrush(wx.Brush("pink"))
# show the difference between stroking, filling and drawing
for label, PathFunc in [("StrokePath", gc.StrokePath),
("FillPath", gc.FillPath),
("DrawPath", gc.DrawPath)]:
w, h = gc.GetTextExtent(label)
gc.DrawText(label, -w/2, -BASE2-h-4)
PathFunc(path)
gc.Translate(2*BASE, 0)
gc.PopState() # restore saved state
gc.PushState() # save it again
gc.Translate(60, 200) # offset to the lower part of the window
gc.DrawText("Scale", 0, -BASE2)
gc.Translate(0, 20)
# for testing clipping
#gc.Clip(0, 0, 100, 100)
#rgn = wx.RegionFromPoints([ (0,0), (75,0), (75,25,), (100, 25),
# (100,100), (0,100), (0,0) ])
#gc.ClipRegion(rgn)
#gc.ResetClip()
gc.SetBrush(wx.Brush(wx.Colour(178, 34, 34, 128))) # 128 == half transparent
for cnt in range(8):
gc.Scale(1.08, 1.08) # increase scale by 8%
gc.Translate(5,5)
gc.DrawPath(path)
gc.PopState() # restore saved state
gc.PushState() # save it again
gc.Translate(400, 200)
gc.DrawText("Rotate", 0, -BASE2)
# Move the origin over to the next location
gc.Translate(0, 75)
# draw our path again, rotating it about the central point,
# and changing colors as we go
for angle in range(0, 360, 30):
gc.PushState() # save this new current state so we can
# pop back to it at the end of the loop
r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(float(angle)/360, 1, 1)]
gc.SetBrush(wx.Brush(wx.Colour(r, g, b, 64)))
gc.SetPen(wx.Pen(wx.Colour(r, g, b, 128)))
# use translate to artfully reposition each drawn path
gc.Translate(1.5 * BASE2 * cos(radians(angle)),
1.5 * BASE2 * sin(radians(angle)))
# use Rotate to rotate the path
gc.Rotate(radians(angle))
# now draw it
gc.DrawPath(path)
gc.PopState()
# Draw a bitmap with an alpha channel on top of the last group
bmp = wx.Bitmap(opj('bitmaps/toucan.png'))
bsz = bmp.GetSize()
gc.DrawBitmap(bmp,
#-bsz.width,
#-bsz.height/2,
-bsz.width/2.5,
-bsz.height/2.5,
bsz.width, bsz.height)
gc.PopState()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.GraphicsContext and wx.GraphicsPath</center></h2>
The new advanced 2D drawing API is implemented via the
wx.GraphicsContext and wx.GraphicsPath classes. They wrap GDI+ on
Windows, Cairo on wxGTK and CoreGraphics on OS X. They allow
path-based drawing with alpha-blending and anti-aliasing, and use a
floating point cooridnate system.
<p>When viewing this sample pay attention to how the rounded edges are
smoothed with anti-aliased drawing, and how the shapes on the lower
half of the window are partially transparent, allowing you to see what
was drawn before.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

265
demo/GraphicsGradient.py Normal file
View File

@@ -0,0 +1,265 @@
import wx
g = wx
# To test compatibility of gradients with the generic GraphicsContext classes
# uncomment this line
#import wx.lib.graphics as g
#----------------------------------------------------------------------
class GradientPanel(wx.Panel):
"""
This panel will be painted with the gradient brush created by the
rest of the sample.
"""
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.SetInitialSize((600,100))
# create a simple default brush we can use until a gradient
# brush is given to us
ctx = g.GraphicsContext.CreateMeasuringContext()
self.brush = ctx.CreateBrush(wx.Brush('white'))
def DrawWithBrush(self, brush):
self.brush = brush
self.Refresh()
def OnPaint(self, evt):
dc = wx.PaintDC(self)
gc = g.GraphicsContext.Create(dc)
gc.SetBrush(self.brush)
gc.SetPen(wx.Pen('black', 1))
w, h = gc.GetSize()
gc.DrawRectangle(0,0,w,h)
class GradientStopPanel(wx.Panel):
"""
Contains the controls for editing each gradient stop. (Colour,
alpha and relative position.)
"""
def __init__(self, parent, posVal, colour=wx.BLACK, alpha=wx.ALPHA_OPAQUE):
wx.Panel.__init__(self, parent)
# make some widgets
self.pos = wx.SpinCtrlDouble(self, value='%2f' % posVal, size=(65,-1),
min=0.0, max=1.0, initial=posVal, inc=0.01)
self.pos.SetToolTipString(
"A value between 0 and 1 representing the distance between (x1,y1) "
"and (x2,y2) for this gradient stop.")
self.colour = wx.ColourPickerCtrl(self, col=colour)
self.colour.SetToolTipString("The colour for this gradient stop")
self.minusBtn = wx.Button(self, -1, " - ", style=wx.BU_EXACTFIT)
self.minusBtn.SetToolTipString("Remove this gradient stop")
# put them in a sizer
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.pos, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.colour, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 10)
sizer.Add(self.minusBtn, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 25)
border = wx.BoxSizer()
border.Add(sizer, 1, wx.EXPAND|wx.ALL, 4)
self.SetSizer(border)
self.Bind(wx.EVT_BUTTON, self.OnMinusButton, self.minusBtn)
def OnMinusButton(self, evt):
wx.CallAfter(self.Parent.RemoveStop, self)
class TestPanel(wx.Panel):
"""
The main panel for this sample
"""
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
# make the panel that will display the gradient
self.gpanel = GradientPanel(self)
# and the other widgets for collecting data about the gradient
label1 = wx.StaticText(self, -1, "Geometry")
label1.SetFont(wx.FFont(15, wx.SWISS, wx.FONTFLAG_BOLD))
x1 = 0
x2 = self.gpanel.Size.width
y0 = self.gpanel.Size.height / 2
self.x1 = wx.TextCtrl(self, value=str(x1), size=(50,-1))
self.y1 = wx.TextCtrl(self, value=str(y0), size=(50,-1))
self.x2 = wx.TextCtrl(self, value=str(x2), size=(50,-1))
self.y2 = wx.TextCtrl(self, value=str(y0), size=(50,-1))
label2 = wx.StaticText(self, -1, "Stops")
label2.SetFont(wx.FFont(15, wx.SWISS, wx.FONTFLAG_BOLD))
firstStop = GradientStopPanel(self, 0.0)
lastStop = GradientStopPanel(self, 1.0, wx.WHITE)
self.stops = [firstStop, lastStop]
addStopBtn = wx.Button(self, -1, " + ", style=wx.BU_EXACTFIT)
# bind some events
self.Bind(wx.EVT_BUTTON, self.OnAddStop, addStopBtn)
self.Bind(wx.EVT_SPINCTRLDOUBLE, self.OnPositionUpdated)
self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged)
self.Bind(wx.EVT_TEXT, self.OnGeometryChanged)
# do the layout
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.gpanel)
sizer.Add((1,15))
sizer.Add(label1)
sizer.Add((1, 5))
fgs = wx.FlexGridSizer(cols=11, hgap=5, vgap=5)
fgs.AddMany([ (wx.StaticText(self, -1, "x1:"), 0, wx.ALIGN_CENTER_VERTICAL),
self.x1,
((5,1)),
(wx.StaticText(self, -1, "y1:"), 0, wx.ALIGN_CENTER_VERTICAL),
self.y1] )
fgs.Add((40,1))
fgs.AddMany([ (wx.StaticText(self, -1, "x2:"), 0, wx.ALIGN_CENTER_VERTICAL),
self.x2,
((5,1)),
(wx.StaticText(self, -1, "y2:"), 0, wx.ALIGN_CENTER_VERTICAL),
self.y2] )
sizer.Add(fgs, 0, wx.LEFT, 25)
sizer.Add((1,15))
sizer.Add(label2)
sizer.Add((1, 5))
self.stopSizer = wx.BoxSizer(wx.VERTICAL)
self.stopSizer.Add(firstStop)
self.stopSizer.Add(lastStop)
self.stopSizer.Add(addStopBtn, 0, wx.TOP, 10)
sizer.Add(self.stopSizer, 0, wx.LEFT, 25)
border = wx.BoxSizer()
border.Add(sizer, 1, wx.EXPAND|wx.ALL, 15)
self.SetSizer(border)
self.SetLimits()
self.UpdateBrush()
def RemoveStop(self, stop):
self.stops.remove(stop)
stop.Destroy()
self.Layout()
self.SetLimits()
self.UpdateBrush()
def OnAddStop(self, evt):
newstop = GradientStopPanel(self, 1.0)
self.stopSizer.Insert(len(self.stops), newstop)
self.stops.append(newstop)
self.Layout()
self.SetLimits()
self.UpdateBrush()
def OnPositionUpdated(self, evt):
# called when any of the spinctrls in the nested panels are updated
self.SetLimits()
self.UpdateBrush()
def OnColourChanged(self, evt):
# called when any of the color pickers are updated
self.UpdateBrush()
def OnGeometryChanged(self, evt):
# called for changes to x1,y1 or x2,y2
self.UpdateBrush()
def SetLimits(self):
# Tweak the panels in self.stops to set limits on the allowed
# positions, and to disable those that should not be changed or
# removed.
first = self.stops[0]
last = self.stops[-1]
first.pos.Disable()
first.minusBtn.Disable()
last.pos.Disable()
last.minusBtn.Disable()
for idx in range(1, len(self.stops)-1):
prev = self.stops[idx-1]
next = self.stops[idx+1]
stop = self.stops[idx]
stop.pos.SetMin(prev.pos.GetValue())
stop.pos.SetMax(next.pos.GetValue())
stop.pos.Enable()
stop.minusBtn.Enable()
def UpdateBrush(self):
"""
This is where the magic happens. We convert all the values from the
widgets on this panel into a collection of gradient stops and then
create a brush from them, and finally, ask the display panel to
repaint itself with that new brush.
"""
def floatOrZero(value):
try:
return float(value)
except ValueError:
return 0.0
x1 = floatOrZero(self.x1.Value)
y1 = floatOrZero(self.y1.Value)
x2 = floatOrZero(self.x2.Value)
y2 = floatOrZero(self.y2.Value)
gstops = g.GraphicsGradientStops()
gstops.SetStartColour(self.stops[0].colour.GetColour())
gstops.SetEndColour(self.stops[-1].colour.GetColour())
for s in self.stops[1:-1]:
gs = g.GraphicsGradientStop(
s.colour.GetColour(), s.pos.GetValue())
gstops.Add(gs)
ctx = g.GraphicsContext.CreateMeasuringContext()
brush = ctx.CreateLinearGradientBrush(x1,y1, x2,y2, gstops)
self.gpanel.DrawWithBrush(brush)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center> Gradients on a GraphicsContext </center></h2>
Multi-stop gradients can be used as fills in a wx.GraphicsContext.
This sample shows how to use the GraphicsGradientStops class to
accomplish this and allows the user to experiment with gradients.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

96
demo/Grid.py Normal file
View File

@@ -0,0 +1,96 @@
import wx
#---------------------------------------------------------------------------
buttonDefs = {
814 : ('GridSimple', ' Simple wx.Grid, catching all events '),
815 : ('GridStdEdRend', ' wx.Grid showing Editors and Renderers '),
818 : ('GridHugeTable', ' A wx.Grid with a HUGE table (100 MILLION cells!) '),
817 : ('GridCustTable', ' wx.Grid using a custom Table, with non-string data '),
819 : ('GridEnterHandler',' Remapping keys to behave differently '),
820 : ('GridCustEditor', ' Shows how to create a custom Cell Editor '),
821 : ('GridDragable', ' A wx.Grid with dragable rows and columns '),
822 : ('GridDragAndDrop', ' Shows how to make a grid a drop target for files'),
}
class ButtonPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
self.log = log
box = wx.BoxSizer(wx.VERTICAL)
box.Add((20, 20))
keys = buttonDefs.keys()
keys.sort()
for k in keys:
text = buttonDefs[k][1]
btn = wx.Button(self, k, text)
box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 10)
self.Bind(wx.EVT_BUTTON, self.OnButton, btn)
self.SetSizer(box)
box.Fit(self)
def OnButton(self, evt):
modName = buttonDefs[evt.GetId()][0]
module = __import__(modName)
frame = module.TestFrame(None, self.log)
frame.Show(True)
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = ButtonPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
<html><body>
<h2>wx.grid.Grid</h2>
This demo shows various ways of using the wx.grid.Grid class.
<p>
You can look at the sources for these samples to learn a lot about how
the new classes work.
<p><ol>
<li><a href="GridSimple.py">GridSimple.py</a> A simple grid that shows
how to catch all the various events.
<p>
<li><a href="GridStdEdRend.py">GridStdEdRend.py</a> A grid that
uses non-default Cell Editors and Cell Renderers.
<p>
<li><a href="GridHugeTable.py">GridHugeTable.py</a> A grid that
uses a non-default Grid Table. This table is read-only and simply
generates on the fly a unique string for each cell.
<p>
<li><a href="GridCustTable.py">GridCustTable.py</a> This grid
shows how to deal with tables that have non-string data, and how Cell
Editors and Cell Renderers are automatically chosen based on the data
type.
<p>
<li><a href="GridEnterHandler.py">GridEnterHandler.py</a>This one
changes how the ENTER key works, moving the current cell left to right
and wrapping around to the next row when needed.
</ol>
<p>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

171
demo/GridBagSizer.py Normal file
View File

@@ -0,0 +1,171 @@
import wx # This module uses the new wx namespace
#----------------------------------------------------------------------
gbsDescription = """\
The wx.GridBagSizer is similar to the wx.FlexGridSizer except the items are explicitly positioned
in a virtual cell of the layout grid, and column or row spanning is allowed. For example, this
static text is positioned at (0,0) and it spans 7 columns.
"""
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "wx.GridBagSizer")
p = wx.Panel(self, -1, style = wx.TAB_TRAVERSAL
| wx.CLIP_CHILDREN
| wx.FULL_REPAINT_ON_RESIZE
)
p.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
gbs = self.gbs = wx.GridBagSizer(5, 5)
gbs.Add( wx.StaticText(p, -1, gbsDescription),
(0,0), (1,7), wx.ALIGN_CENTER | wx.ALL, 5)
gbs.Add( wx.TextCtrl(p, -1, "pos(1,0)"), (1,0) )
gbs.Add( wx.TextCtrl(p, -1, "pos(1,1)"), (1,1) )
gbs.Add( wx.TextCtrl(p, -1, "pos(2,0)"), (2,0) )
gbs.Add( wx.TextCtrl(p, -1, "pos(2,1)"), (2,1) )
gbs.Add( wx.TextCtrl(p, -1, "pos(3,2), span(1,2)\nthis row and col are growable", style=wx.TE_MULTILINE),
(3,2), (1,2), flag=wx.EXPAND )
gbs.Add( wx.TextCtrl(p, -1, "pos(4,3), span(3,1)", style=wx.TE_MULTILINE),
(4,3), (3,1), wx.EXPAND)
gbs.Add( wx.TextCtrl(p, -1, "pos(5,4)"), (5,4), flag=wx.EXPAND )
gbs.Add( wx.TextCtrl(p, -1, "pos(6,5)"), (6,5), flag=wx.EXPAND )
gbs.Add( wx.TextCtrl(p, -1, "pos(7,6)"), (7,6) )
moveBtn1 = wx.Button(p, -1, "Move this to (3,6)")
moveBtn2 = wx.Button(p, -1, "Move this to (3,6)");
gbs.Add( moveBtn1, (10,2) )
gbs.Add( moveBtn2, (10,3) )
hideBtn = wx.Button(p, -1, "Hide this item -->")
gbs.Add(hideBtn, (12, 3))
hideTxt = wx.TextCtrl(p, -1, "pos(12,4), size(150, -1)", size = (150,-1))
gbs.Add( hideTxt, (12,4) )
showBtn = wx.Button(p, -1, "<-- Show it again")
gbs.Add(showBtn, (12, 5))
showBtn.Disable()
self.hideBtn = hideBtn
self.showBtn = showBtn
self.hideTxt = hideTxt
self.Bind(wx.EVT_BUTTON, self.OnHideButton, hideBtn)
self.Bind(wx.EVT_BUTTON, self.OnShowButton, showBtn)
self.Bind(wx.EVT_BUTTON, self.OnMoveButton, moveBtn1)
self.Bind(wx.EVT_BUTTON, self.OnMoveButton, moveBtn2)
# Add a spacer at the end to ensure some extra space at the bottom
gbs.Add((10,10), (14,7))
gbs.AddGrowableRow(3)
gbs.AddGrowableCol(2)
box = wx.BoxSizer()
box.Add(gbs, 1, wx.ALL|wx.EXPAND, 10)
p.SetSizer(box)
self.SetClientSize(p.GetBestSize())
def OnHideButton(self, evt):
self.gbs.Hide(self.hideTxt)
self.hideBtn.Disable()
self.showBtn.Enable()
self.gbs.Layout()
def OnShowButton(self, evt):
self.gbs.Show(self.hideTxt)
self.hideBtn.Enable()
self.showBtn.Disable()
self.gbs.Layout()
def OnMoveButton(self, evt):
btn = evt.GetEventObject()
curPos = self.gbs.GetItemPosition(btn)
# if it's already at the "other" spot then move it back
if curPos == (3,6):
self.gbs.SetItemPosition(btn, self.lastPos)
btn.SetLabel("Move this to (3,6)")
else:
if self.gbs.CheckForIntersectionPos( (3,6), (1,1) ):
wx.MessageBox("""\
wx.GridBagSizer will not allow items to be in the same cell as
another item, so this operation will fail. You will also get an
assert when compiled in debug mode.""",
"Warning", wx.OK | wx.ICON_INFORMATION)
try:
if self.gbs.SetItemPosition(btn, (3,6)):
self.lastPos = curPos
btn.SetLabel("Move it back")
except wx.PyAssertionError:
pass
self.gbs.Layout()
def OnLeftDown(self, evt):
pt = evt.GetPosition()
item = self.gbs.FindItemAtPoint(pt)
if item is None:
print "no item at", `pt`
else:
print "item found: ", `item.GetPos()`, "--", `item.GetSpan()`
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Show the GridBagSizer sample", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
win = TestFrame()
win.Show(True)
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.GridBagSizer</center></h2>
The wx.GridBagSizer is more or less a port of the the RowColSizer (that
has been in the wxPython.lib package for quite some time) to C++. It
allows items to be placed at specific layout grid cells, and items can
span across more than one row or column.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

243
demo/GridCustEditor.py Normal file
View File

@@ -0,0 +1,243 @@
import string
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
class MyCellEditor(gridlib.PyGridCellEditor):
"""
This is a sample GridCellEditor that shows you how to make your own custom
grid editors. All the methods that can be overridden are shown here. The
ones that must be overridden are marked with "*Must Override*" in the
docstring.
"""
def __init__(self, log):
self.log = log
self.log.write("MyCellEditor ctor\n")
gridlib.PyGridCellEditor.__init__(self)
def Create(self, parent, id, evtHandler):
"""
Called to create the control, which must derive from wx.Control.
*Must Override*
"""
self.log.write("MyCellEditor: Create\n")
self._tc = wx.TextCtrl(parent, id, "")
self._tc.SetInsertionPoint(0)
self.SetControl(self._tc)
if evtHandler:
self._tc.PushEventHandler(evtHandler)
def SetSize(self, rect):
"""
Called to position/size the edit control within the cell rectangle.
If you don't fill the cell (the rect) then be sure to override
PaintBackground and do something meaningful there.
"""
self.log.write("MyCellEditor: SetSize %s\n" % rect)
self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2,
wx.SIZE_ALLOW_MINUS_ONE)
def Show(self, show, attr):
"""
Show or hide the edit control. You can use the attr (if not None)
to set colours or fonts for the control.
"""
self.log.write("MyCellEditor: Show(self, %s, %s)\n" % (show, attr))
super(MyCellEditor, self).Show(show, attr)
def PaintBackground(self, rect, attr):
"""
Draws the part of the cell not occupied by the edit control. The
base class version just fills it with background colour from the
attribute. In this class the edit control fills the whole cell so
don't do anything at all in order to reduce flicker.
"""
self.log.write("MyCellEditor: PaintBackground\n")
def BeginEdit(self, row, col, grid):
"""
Fetch the value from the table and prepare the edit control
to begin editing. Set the focus to the edit control.
*Must Override*
"""
self.log.write("MyCellEditor: BeginEdit (%d,%d)\n" % (row, col))
self.startValue = grid.GetTable().GetValue(row, col)
self._tc.SetValue(self.startValue)
self._tc.SetInsertionPointEnd()
self._tc.SetFocus()
# For this example, select the text
self._tc.SetSelection(0, self._tc.GetLastPosition())
def EndEdit(self, row, col, grid, oldVal):
"""
End editing the cell. This function must check if the current
value of the editing control is valid and different from the
original value (available as oldval in its string form.) If
it has not changed then simply return None, otherwise return
the value in its string form.
*Must Override*
"""
self.log.write("MyCellEditor: EndEdit (%s)\n" % oldVal)
val = self._tc.GetValue()
if val != oldVal: #self.startValue:
return val
else:
return None
def ApplyEdit(self, row, col, grid):
"""
This function should save the value of the control into the
grid or grid table. It is called only after EndEdit() returns
a non-None value.
*Must Override*
"""
self.log.write("MyCellEditor: ApplyEdit (%d,%d)\n" % (row, col))
val = self._tc.GetValue()
grid.GetTable().SetValue(row, col, val) # update the table
self.startValue = ''
self._tc.SetValue('')
def Reset(self):
"""
Reset the value in the control back to its starting value.
*Must Override*
"""
self.log.write("MyCellEditor: Reset\n")
self._tc.SetValue(self.startValue)
self._tc.SetInsertionPointEnd()
def IsAcceptedKey(self, evt):
"""
Return True to allow the given key to start editing: the base class
version only checks that the event has no modifiers. F2 is special
and will always start the editor.
"""
self.log.write("MyCellEditor: IsAcceptedKey: %d\n" % (evt.GetKeyCode()))
## We can ask the base class to do it
#return super(MyCellEditor, self).IsAcceptedKey(evt)
# or do it ourselves
return (not (evt.ControlDown() or evt.AltDown()) and
evt.GetKeyCode() != wx.WXK_SHIFT)
def StartingKey(self, evt):
"""
If the editor is enabled by pressing keys on the grid, this will be
called to let the editor do something about that first key if desired.
"""
self.log.write("MyCellEditor: StartingKey %d\n" % evt.GetKeyCode())
key = evt.GetKeyCode()
ch = None
if key in [ wx.WXK_NUMPAD0, wx.WXK_NUMPAD1, wx.WXK_NUMPAD2, wx.WXK_NUMPAD3,
wx.WXK_NUMPAD4, wx.WXK_NUMPAD5, wx.WXK_NUMPAD6, wx.WXK_NUMPAD7,
wx.WXK_NUMPAD8, wx.WXK_NUMPAD9
]:
ch = ch = chr(ord('0') + key - wx.WXK_NUMPAD0)
elif key < 256 and key >= 0 and chr(key) in string.printable:
ch = chr(key)
if ch is not None:
# For this example, replace the text. Normally we would append it.
#self._tc.AppendText(ch)
self._tc.SetValue(ch)
self._tc.SetInsertionPointEnd()
else:
evt.Skip()
def StartingClick(self):
"""
If the editor is enabled by clicking on the cell, this method will be
called to allow the editor to simulate the click on the control if
needed.
"""
self.log.write("MyCellEditor: StartingClick\n")
def Destroy(self):
"""final cleanup"""
self.log.write("MyCellEditor: Destroy\n")
super(MyCellEditor, self).Destroy()
def Clone(self):
"""
Create a new object which is the copy of this one
*Must Override*
"""
self.log.write("MyCellEditor: Clone\n")
return MyCellEditor(self.log)
#---------------------------------------------------------------------------
class GridEditorTest(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
self.log = log
self.CreateGrid(10, 3)
# Somebody changed the grid so the type registry takes precedence
# over the default attribute set for editors and renderers, so we
# have to set null handlers for the type registry before the
# default editor will get used otherwise...
#self.RegisterDataType(wxGRID_VALUE_STRING, None, None)
#self.SetDefaultEditor(MyCellEditor(self.log))
# Or we could just do it like this:
#self.RegisterDataType(wx.GRID_VALUE_STRING,
# wx.GridCellStringRenderer(),
# MyCellEditor(self.log))
# )
# but for this example, we'll just set the custom editor on one cell
self.SetCellEditor(1, 0, MyCellEditor(self.log))
self.SetCellValue(1, 0, "Try to edit this box")
# and on a column
attr = gridlib.GridCellAttr()
attr.SetEditor(MyCellEditor(self.log))
self.SetColAttr(2, attr)
self.SetCellValue(1, 2, "or any in this column")
self.SetColSize(0, 150)
self.SetColSize(1, 150)
self.SetColSize(2, 150)
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Custom Grid Cell Editor Test",
size=(640,480))
grid = GridEditorTest(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()

173
demo/GridCustTable.py Normal file
View File

@@ -0,0 +1,173 @@
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
class CustomDataTable(gridlib.PyGridTableBase):
def __init__(self, log):
gridlib.PyGridTableBase.__init__(self)
self.log = log
self.colLabels = ['ID', 'Description', 'Severity', 'Priority', 'Platform',
'Opened?', 'Fixed?', 'Tested?', 'TestFloat']
self.dataTypes = [gridlib.GRID_VALUE_NUMBER,
gridlib.GRID_VALUE_STRING,
gridlib.GRID_VALUE_CHOICE + ':only in a million years!,wish list,minor,normal,major,critical',
gridlib.GRID_VALUE_NUMBER + ':1,5',
gridlib.GRID_VALUE_CHOICE + ':all,MSW,GTK,other',
gridlib.GRID_VALUE_BOOL,
gridlib.GRID_VALUE_BOOL,
gridlib.GRID_VALUE_BOOL,
gridlib.GRID_VALUE_FLOAT + ':6,2',
]
self.data = [
[1010, "The foo doesn't bar", "major", 1, 'MSW', 1, 1, 1, 1.12],
[1011, "I've got a wicket in my wocket", "wish list", 2, 'other', 0, 0, 0, 1.50],
[1012, "Rectangle() returns a triangle", "critical", 5, 'all', 0, 0, 0, 1.56]
]
#--------------------------------------------------
# required methods for the wxPyGridTableBase interface
def GetNumberRows(self):
return len(self.data) + 1
def GetNumberCols(self):
return len(self.data[0])
def IsEmptyCell(self, row, col):
try:
return not self.data[row][col]
except IndexError:
return True
# Get/Set values in the table. The Python version of these
# methods can handle any data-type, (as long as the Editor and
# Renderer understands the type too,) not just strings as in the
# C++ version.
def GetValue(self, row, col):
try:
return self.data[row][col]
except IndexError:
return ''
def SetValue(self, row, col, value):
def innerSetValue(row, col, value):
try:
self.data[row][col] = value
except IndexError:
# add a new row
self.data.append([''] * self.GetNumberCols())
innerSetValue(row, col, value)
# tell the grid we've added a row
msg = gridlib.GridTableMessage(self, # The table
gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it
1 # how many
)
self.GetView().ProcessTableMessage(msg)
innerSetValue(row, col, value)
#--------------------------------------------------
# Some optional methods
# Called when the grid needs to display labels
def GetColLabelValue(self, col):
return self.colLabels[col]
# Called to determine the kind of editor/renderer to use by
# default, doesn't necessarily have to be the same type used
# natively by the editor/renderer if they know how to convert.
def GetTypeName(self, row, col):
return self.dataTypes[col]
# Called to determine how the data can be fetched and stored by the
# editor and renderer. This allows you to enforce some type-safety
# in the grid.
def CanGetValueAs(self, row, col, typeName):
colType = self.dataTypes[col].split(':')[0]
if typeName == colType:
return True
else:
return False
def CanSetValueAs(self, row, col, typeName):
return self.CanGetValueAs(row, col, typeName)
#---------------------------------------------------------------------------
class CustTableGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
table = CustomDataTable(log)
# The second parameter means that the grid is to take ownership of the
# table and will destroy it when done. Otherwise you would need to keep
# a reference to it and call it's Destroy method later.
self.SetTable(table, True)
self.SetRowLabelSize(0)
self.SetMargins(0,0)
self.AutoSizeColumns(False)
gridlib.EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick)
# I do this because I don't like the default behaviour of not starting the
# cell editor on double clicks, but only a second click.
def OnLeftDClick(self, evt):
if self.CanEnableCellControl():
self.EnableCellEditControl()
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(
self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480)
)
p = wx.Panel(self, -1, style=0)
grid = CustTableGrid(p, log)
b = wx.Button(p, -1, "Another Control...")
b.SetDefault()
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
b.Bind(wx.EVT_SET_FOCUS, self.OnButtonFocus)
bs = wx.BoxSizer(wx.VERTICAL)
bs.Add(grid, 1, wx.GROW|wx.ALL, 5)
bs.Add(b)
p.SetSizer(bs)
def OnButton(self, evt):
print "button selected"
def OnButtonFocus(self, evt):
print "button focus"
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

99
demo/GridDragAndDrop.py Normal file
View File

@@ -0,0 +1,99 @@
"""
Example showing how to make a grid a drop target for files.
"""
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
# Set VIRTUAL to 1 to use a virtual grid
VIRTUAL = 1
#---------------------------------------------------------------------------
class GridFileDropTarget(wx.FileDropTarget):
def __init__(self, grid):
wx.FileDropTarget.__init__(self)
self.grid = grid
def OnDropFiles(self, x, y, filenames):
# the x,y coordinates here are Unscrolled coordinates. They must be changed
# to scrolled coordinates.
x, y = self.grid.CalcUnscrolledPosition(x, y)
# now we need to get the row and column from the grid
col = self.grid.XToCol(x)
row = self.grid.YToRow(y)
if row > -1 and col > -1:
self.grid.SetCellValue(row, col, filenames[0])
self.grid.AutoSizeColumn(col)
self.grid.Refresh()
class FooTable(gridlib.PyGridTableBase):
def __init__(self):
gridlib.PyGridTableBase.__init__(self)
self.dropTargets = {(0,0):"Drag",
(1,0):"A",
(2,0):"File",
(3,0):"To",
(4,0):"A",
(5,0):"Cell"}
def GetNumberCols(self):
return 100
def GetNumberRows(self):
return 100
def GetValue(self, row, col):
return self.dropTargets.get((row, col), "")
class SimpleGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
self.log = log
self.moveTo = None
if VIRTUAL:
self.table = FooTable()
self.SetTable(self.table)
else:
self.CreateGrid(25, 25)
# set the drag and drop target
dropTarget = GridFileDropTarget(self)
self.SetDropTarget(dropTarget)
self.EnableDragRowSize()
self.EnableDragColSize()
def SetCellValue(self, row, col, value):
if VIRTUAL:
self.table.dropTargets[row, col] = value
else:
gridlib.Grid.SetCellValue(self, row, col, value)
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "DragAndDrop Grid", size=(640,480))
grid = SimpleGrid(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

205
demo/GridDragable.py Normal file
View File

@@ -0,0 +1,205 @@
import wx
import wx.grid as gridlib
import wx.lib.gridmovers as gridmovers
#---------------------------------------------------------------------------
class CustomDataTable(gridlib.PyGridTableBase):
def __init__(self, log):
gridlib.PyGridTableBase.__init__(self)
self.log = log
self.identifiers = ['id','ds','sv','pr','pl','op','fx','ts']
self.rowLabels = ['Row1','Row2','Row3']
self.colLabels = {'id':'ID','ds':'Description','sv':'Severity',
'pr':'Priority','pl':'Platform','op':'Opened?',
'fx':'Fixed?','ts':'Tested?'}
self.data = [{'id':1010,
'ds':"The foo doesn't bar",
'sv':"major",
'pr':1,
'pl':'MSW',
'op':1,
'fx':1,
'ts':1
},
{'id':1011,
'ds':"I've got a wicket in my wocket",
'sv':"wish list",
'pr':2,
'pl':'other',
'op':0,
'fx':0,
'ts':0
},
{'id':1012,
'ds':"Rectangle() returns a triangle",
'sv':"critical",
'pr':5,
'pl':'all',
'op':0,
'fx':0,
'ts':0
}
]
#--------------------------------------------------
# required methods for the wxPyGridTableBase interface
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(self.identifiers)
def IsEmptyCell(self, row, col):
id = self.identifiers[col]
return not self.data[row][id]
def GetValue(self, row, col):
id = self.identifiers[col]
return self.data[row][id]
def SetValue(self, row, col, value):
id = self.identifiers[col]
self.data[row][id] = value
#--------------------------------------------------
# Some optional methods
# Called when the grid needs to display column labels
def GetColLabelValue(self, col):
id = self.identifiers[col]
return self.colLabels[id]
# Called when the grid needs to display row labels
def GetRowLabelValue(self,row):
return self.rowLabels[row]
#--------------------------------------------------
# Methods added for demo purposes.
# The physical moving of the cols/rows is left to the implementer.
# Because of the dynamic nature of a wxGrid the physical moving of
# columns differs from implementation to implementation
# Move the column
def MoveColumn(self,frm,to):
grid = self.GetView()
if grid:
# Move the identifiers
old = self.identifiers[frm]
del self.identifiers[frm]
if to > frm:
self.identifiers.insert(to-1,old)
else:
self.identifiers.insert(to,old)
# Notify the grid
grid.BeginBatch()
msg = gridlib.GridTableMessage(
self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1
)
grid.ProcessTableMessage(msg)
msg = gridlib.GridTableMessage(
self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1
)
grid.ProcessTableMessage(msg)
grid.EndBatch()
# Move the row
def MoveRow(self,frm,to):
grid = self.GetView()
if grid:
# Move the rowLabels and data rows
oldLabel = self.rowLabels[frm]
oldData = self.data[frm]
del self.rowLabels[frm]
del self.data[frm]
if to > frm:
self.rowLabels.insert(to-1,oldLabel)
self.data.insert(to-1,oldData)
else:
self.rowLabels.insert(to,oldLabel)
self.data.insert(to,oldData)
# Notify the grid
grid.BeginBatch()
msg = gridlib.GridTableMessage(
self, gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1
)
grid.ProcessTableMessage(msg)
msg = gridlib.GridTableMessage(
self, gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1
)
grid.ProcessTableMessage(msg)
grid.EndBatch()
#---------------------------------------------------------------------------
class DragableGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
table = CustomDataTable(log)
# The second parameter means that the grid is to take ownership of the
# table and will destroy it when done. Otherwise you would need to keep
# a reference to it and call it's Destroy method later.
self.SetTable(table, True)
# Enable Column moving
gridmovers.GridColMover(self)
self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.OnColMove, self)
# Enable Row moving
gridmovers.GridRowMover(self)
self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self)
# Event method called when a column move needs to take place
def OnColMove(self,evt):
frm = evt.GetMoveColumn() # Column being moved
to = evt.GetBeforeColumn() # Before which column to insert
self.GetTable().MoveColumn(frm,to)
# Event method called when a row move needs to take place
def OnRowMove(self,evt):
frm = evt.GetMoveRow() # Row being moved
to = evt.GetBeforeRow() # Before which row to insert
self.GetTable().MoveRow(frm,to)
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480))
grid = DragableGrid(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

65
demo/GridEnterHandler.py Normal file
View File

@@ -0,0 +1,65 @@
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
class NewEnterHandlingGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
self.log = log
self.CreateGrid(20, 6)
self.SetCellValue(0, 0, "Enter moves to the right")
self.SetCellValue(0, 5, "Enter wraps to next row")
self.SetColSize(0, 150)
self.SetColSize(5, 150)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
def OnKeyDown(self, evt):
if evt.GetKeyCode() != wx.WXK_RETURN:
evt.Skip()
return
if evt.ControlDown(): # the edit control needs this key
evt.Skip()
return
self.DisableCellEditControl()
success = self.MoveCursorRight(evt.ShiftDown())
if not success:
newRow = self.GetGridCursorRow() + 1
if newRow < self.GetTable().GetNumberRows():
self.SetGridCursor(newRow, 0)
self.MakeCellVisible(newRow, 0)
else:
# this would be a good place to add a new row if your app
# needs to do that
pass
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Simple Grid Demo", size=(640,480))
grid = NewEnterHandlingGrid(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

87
demo/GridHugeTable.py Normal file
View File

@@ -0,0 +1,87 @@
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
class HugeTable(gridlib.PyGridTableBase):
def __init__(self, log):
gridlib.PyGridTableBase.__init__(self)
self.log = log
self.odd=gridlib.GridCellAttr()
self.odd.SetBackgroundColour("sky blue")
self.even=gridlib.GridCellAttr()
self.even.SetBackgroundColour("sea green")
def GetAttr(self, row, col, kind):
attr = [self.even, self.odd][row % 2]
attr.IncRef()
return attr
# This is all it takes to make a custom data table to plug into a
# wxGrid. There are many more methods that can be overridden, but
# the ones shown below are the required ones. This table simply
# provides strings containing the row and column values.
def GetNumberRows(self):
return 10000
def GetNumberCols(self):
return 10000
def IsEmptyCell(self, row, col):
return False
def GetValue(self, row, col):
return str( (row, col) )
def SetValue(self, row, col, value):
self.log.write('SetValue(%d, %d, "%s") ignored.\n' % (row, col, value))
#---------------------------------------------------------------------------
class HugeTableGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
table = HugeTable(log)
# The second parameter means that the grid is to take ownership of the
# table and will destroy it when done. Otherwise you would need to keep
# a reference to it and call it's Destroy method later.
self.SetTable(table, True)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnRightDown)
def OnRightDown(self, event):
print "hello"
print self.GetSelectedRows()
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Huge (virtual) Table Demo", size=(640,480))
grid = HugeTableGrid(self, log)
grid.SetReadOnly(5,5, True)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

112
demo/GridLabelRenderer.py Normal file
View File

@@ -0,0 +1,112 @@
import wx
import wx.grid as grid
import wx.lib.mixins.gridlabelrenderer as glr
#----------------------------------------------------------------------
class MyGrid(grid.Grid, glr.GridWithLabelRenderersMixin):
def __init__(self, *args, **kw):
grid.Grid.__init__(self, *args, **kw)
glr.GridWithLabelRenderersMixin.__init__(self)
class MyRowLabelRenderer(glr.GridLabelRenderer):
def __init__(self, bgcolor):
self._bgcolor = bgcolor
def Draw(self, grid, dc, rect, row):
dc.SetBrush(wx.Brush(self._bgcolor))
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleRect(rect)
hAlign, vAlign = grid.GetRowLabelAlignment()
text = grid.GetRowLabelValue(row)
self.DrawBorder(grid, dc, rect)
self.DrawText(grid, dc, rect, text, hAlign, vAlign)
class MyColLabelRenderer(glr.GridLabelRenderer):
def __init__(self, bgcolor):
self._bgcolor = bgcolor
def Draw(self, grid, dc, rect, col):
dc.SetBrush(wx.Brush(self._bgcolor))
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleRect(rect)
hAlign, vAlign = grid.GetColLabelAlignment()
text = grid.GetColLabelValue(col)
self.DrawBorder(grid, dc, rect)
self.DrawText(grid, dc, rect, text, hAlign, vAlign)
class MyCornerLabelRenderer(glr.GridLabelRenderer):
def __init__(self):
import images
self._bmp = images.Smiles.getBitmap()
def Draw(self, grid, dc, rect, rc):
x = rect.left + (rect.width - self._bmp.GetWidth()) / 2
y = rect.top + (rect.height - self._bmp.GetHeight()) / 2
dc.DrawBitmap(self._bmp, x, y, True)
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
ROWS = 27
COLS = 15
g = MyGrid(self, size=(100,100))
g.CreateGrid(ROWS, COLS)
g.SetCornerLabelRenderer(MyCornerLabelRenderer())
for row in range(0, ROWS, 3):
g.SetRowLabelRenderer(row+0, MyRowLabelRenderer('#ffe0e0'))
g.SetRowLabelRenderer(row+1, MyRowLabelRenderer('#e0ffe0'))
g.SetRowLabelRenderer(row+2, MyRowLabelRenderer('#e0e0ff'))
for col in range(0, COLS, 3):
g.SetColLabelRenderer(col+0, MyColLabelRenderer('#e0ffe0'))
g.SetColLabelRenderer(col+1, MyColLabelRenderer('#e0e0ff'))
g.SetColLabelRenderer(col+2, MyColLabelRenderer('#ffe0e0'))
self.Sizer = wx.BoxSizer()
self.Sizer.Add(g, 1, wx.EXPAND)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>GridLabelRenderer</h2>
The <tt>wx.lib.mixins.gridlabelrenderer</tt> module provides a mixin
class for wx.grid.Grid that enables it to have plugin renderers that
work like the normal cell renderers do. If desired you can specify a
different renderer for each row or col label, and even for the little
corner label in the upper left corner of the grid. When each of those
labels needs to be drawn the mixin calls the render's Draw method with
the dc and rectangle, allowing your renderer class do do just about
anything that it wants.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

269
demo/GridSimple.py Normal file
View File

@@ -0,0 +1,269 @@
import wx
import wx.grid as gridlib
#import wx.lib.mixins.grid as mixins
#---------------------------------------------------------------------------
class SimpleGrid(gridlib.Grid): ##, mixins.GridAutoEditMixin):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
##mixins.GridAutoEditMixin.__init__(self)
self.log = log
self.moveTo = None
self.Bind(wx.EVT_IDLE, self.OnIdle)
self.CreateGrid(25, 25)#, gridlib.Grid.SelectRows)
##self.EnableEditing(False)
# simple cell formatting
self.SetColSize(3, 200)
self.SetRowSize(4, 45)
self.SetCellValue(0, 0, "First cell")
self.SetCellValue(1, 1, "Another cell")
self.SetCellValue(2, 2, "Yet another cell")
self.SetCellValue(3, 3, "This cell is read-only")
self.SetCellFont(0, 0, wx.Font(12, wx.ROMAN, wx.ITALIC, wx.NORMAL))
self.SetCellTextColour(1, 1, wx.RED)
self.SetCellBackgroundColour(2, 2, wx.CYAN)
self.SetReadOnly(3, 3, True)
self.SetCellEditor(5, 0, gridlib.GridCellNumberEditor(1,1000))
self.SetCellValue(5, 0, "123")
self.SetCellEditor(6, 0, gridlib.GridCellFloatEditor())
self.SetCellValue(6, 0, "123.34")
self.SetCellEditor(7, 0, gridlib.GridCellNumberEditor())
self.SetCellValue(6, 3, "You can veto editing this cell")
#self.SetRowLabelSize(0)
#self.SetColLabelSize(0)
# attribute objects let you keep a set of formatting values
# in one spot, and reuse them if needed
attr = gridlib.GridCellAttr()
attr.SetTextColour(wx.BLACK)
attr.SetBackgroundColour(wx.RED)
attr.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
# you can set cell attributes for the whole row (or column)
self.SetRowAttr(5, attr)
self.SetColLabelValue(0, "Custom")
self.SetColLabelValue(1, "column")
self.SetColLabelValue(2, "labels")
self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_BOTTOM)
#self.SetDefaultCellOverflow(False)
#r = gridlib.GridCellAutoWrapStringRenderer()
#self.SetCellRenderer(9, 1, r)
# overflow cells
self.SetCellValue( 9, 1, "This default cell will overflow into neighboring cells, but not if you turn overflow off.");
self.SetCellSize(11, 1, 3, 3);
self.SetCellAlignment(11, 1, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE);
self.SetCellValue(11, 1, "This cell is set to span 3 rows and 3 columns");
editor = gridlib.GridCellTextEditor()
editor.SetParameters('10')
self.SetCellEditor(0, 4, editor)
self.SetCellValue(0, 4, "Limited text")
renderer = gridlib.GridCellAutoWrapStringRenderer()
self.SetCellRenderer(15,0, renderer)
self.SetCellValue(15,0, "The text in this cell will be rendered with word-wrapping")
# test all the events
self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnCellLeftClick)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnCellLeftDClick)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_DCLICK, self.OnCellRightDClick)
self.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.OnLabelLeftClick)
self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClick)
self.Bind(gridlib.EVT_GRID_LABEL_LEFT_DCLICK, self.OnLabelLeftDClick)
self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_DCLICK, self.OnLabelRightDClick)
self.Bind(gridlib.EVT_GRID_COL_SORT, self.OnGridColSort)
self.Bind(gridlib.EVT_GRID_ROW_SIZE, self.OnRowSize)
self.Bind(gridlib.EVT_GRID_COL_SIZE, self.OnColSize)
self.Bind(gridlib.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.OnCellChange)
self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.OnSelectCell)
self.Bind(gridlib.EVT_GRID_EDITOR_SHOWN, self.OnEditorShown)
self.Bind(gridlib.EVT_GRID_EDITOR_HIDDEN, self.OnEditorHidden)
self.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.OnEditorCreated)
def OnCellLeftClick(self, evt):
self.log.write("OnCellLeftClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnCellRightClick(self, evt):
self.log.write("OnCellRightClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnCellLeftDClick(self, evt):
self.log.write("OnCellLeftDClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnCellRightDClick(self, evt):
self.log.write("OnCellRightDClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnLabelLeftClick(self, evt):
self.log.write("OnLabelLeftClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnLabelRightClick(self, evt):
self.log.write("OnLabelRightClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnLabelLeftDClick(self, evt):
self.log.write("OnLabelLeftDClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnLabelRightDClick(self, evt):
self.log.write("OnLabelRightDClick: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnGridColSort(self, evt):
self.log.write("OnGridColSort: %s %s" % (evt.GetCol(), self.GetSortingColumn()))
self.SetSortingColumn(evt.GetCol())
def OnRowSize(self, evt):
self.log.write("OnRowSize: row %d, %s\n" %
(evt.GetRowOrCol(), evt.GetPosition()))
evt.Skip()
def OnColSize(self, evt):
self.log.write("OnColSize: col %d, %s\n" %
(evt.GetRowOrCol(), evt.GetPosition()))
evt.Skip()
def OnRangeSelect(self, evt):
if evt.Selecting():
msg = 'Selected'
else:
msg = 'Deselected'
self.log.write("OnRangeSelect: %s top-left %s, bottom-right %s\n" %
(msg, evt.GetTopLeftCoords(), evt.GetBottomRightCoords()))
evt.Skip()
def OnCellChange(self, evt):
self.log.write("OnCellChange: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
# Show how to stay in a cell that has bad data. We can't just
# call SetGridCursor here since we are nested inside one so it
# won't have any effect. Instead, set coordinates to move to in
# idle time.
value = self.GetCellValue(evt.GetRow(), evt.GetCol())
if value == 'no good':
self.moveTo = evt.GetRow(), evt.GetCol()
def OnIdle(self, evt):
if self.moveTo != None:
self.SetGridCursor(self.moveTo[0], self.moveTo[1])
self.moveTo = None
evt.Skip()
def OnSelectCell(self, evt):
if evt.Selecting():
msg = 'Selected'
else:
msg = 'Deselected'
self.log.write("OnSelectCell: %s (%d,%d) %s\n" %
(msg, evt.GetRow(), evt.GetCol(), evt.GetPosition()))
# Another way to stay in a cell that has a bad value...
row = self.GetGridCursorRow()
col = self.GetGridCursorCol()
if self.IsCellEditControlEnabled():
self.HideCellEditControl()
self.DisableCellEditControl()
value = self.GetCellValue(row, col)
if value == 'no good 2':
return # cancels the cell selection
evt.Skip()
def OnEditorShown(self, evt):
if evt.GetRow() == 6 and evt.GetCol() == 3 and \
wx.MessageBox("Are you sure you wish to edit this cell?",
"Checking", wx.YES_NO) == wx.NO:
evt.Veto()
return
self.log.write("OnEditorShown: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnEditorHidden(self, evt):
if evt.GetRow() == 6 and evt.GetCol() == 3 and \
wx.MessageBox("Are you sure you wish to finish editing this cell?",
"Checking", wx.YES_NO) == wx.NO:
evt.Veto()
return
self.log.write("OnEditorHidden: (%d,%d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetPosition()))
evt.Skip()
def OnEditorCreated(self, evt):
self.log.write("OnEditorCreated: (%d, %d) %s\n" %
(evt.GetRow(), evt.GetCol(), evt.GetControl()))
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Simple Grid Demo", size=(640,480))
self.grid = SimpleGrid(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
from wx.lib.mixins.inspection import InspectableApp
app = InspectableApp(False)
frame = TestFrame(None, sys.stdout)
frame.Show(True)
#import wx.lib.inspection
#wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
#---------------------------------------------------------------------------

184
demo/GridStdEdRend.py Normal file
View File

@@ -0,0 +1,184 @@
import random
import wx
import wx.grid as gridlib
#---------------------------------------------------------------------------
class MyCustomRenderer(gridlib.PyGridCellRenderer):
def __init__(self):
gridlib.PyGridCellRenderer.__init__(self)
def Draw(self, grid, attr, dc, rect, row, col, isSelected):
dc.SetBackgroundMode(wx.SOLID)
dc.SetBrush(wx.Brush(wx.BLACK, wx.SOLID))
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleRect(rect)
dc.SetBackgroundMode(wx.TRANSPARENT)
dc.SetFont(attr.GetFont())
text = grid.GetCellValue(row, col)
colors = ["RED", "WHITE", "SKY BLUE"]
x = rect.x + 1
y = rect.y + 1
for ch in text:
dc.SetTextForeground(random.choice(colors))
dc.DrawText(ch, x, y)
w, h = dc.GetTextExtent(ch)
x = x + w
if x > rect.right - 5:
break
def GetBestSize(self, grid, attr, dc, row, col):
text = grid.GetCellValue(row, col)
dc.SetFont(attr.GetFont())
w, h = dc.GetTextExtent(text)
return wx.Size(w, h)
def Clone(self):
return MyCustomRenderer()
#---------------------------------------------------------------------------
rendererDemoData = [
('GridCellStringRenderer\n(the default)', 'this is a text value', gridlib.GridCellStringRenderer, ()),
('GridCellNumberRenderer', '12345', gridlib.GridCellNumberRenderer, ()),
('GridCellFloatRenderer', '1234.5678', gridlib.GridCellFloatRenderer, (6,2)),
('GridCellBoolRenderer', '1', gridlib.GridCellBoolRenderer, ()),
('MyCustomRenderer', 'This is my renderer', MyCustomRenderer, ()),
]
editorDemoData = [
('GridCellTextEditor\n(the default)', 'Here is some more text', gridlib.GridCellTextEditor, ()),
('GridCellNumberEditor\nwith min,max', '101', gridlib.GridCellNumberEditor, (5, 10005)),
('GridCellNumberEditor\nwithout bounds', '101', gridlib.GridCellNumberEditor, ()),
('GridCellFloatEditor', '1234.5678', gridlib.GridCellFloatEditor, ()),
('GridCellBoolEditor', '1', gridlib.GridCellBoolEditor, ()),
('GridCellChoiceEditor', 'one', gridlib.GridCellChoiceEditor, (['one', 'two', 'three', 'four',
'kick', 'Microsoft', 'out the',
'door'], False)),
]
comboDemoData = [
('GridCellNumberRenderer\nGridCellNumberEditor', '20792', gridlib.GridCellNumberRenderer, gridlib.GridCellNumberEditor),
('GridCellBoolRenderer\nGridCellBoolEditor', '1', gridlib.GridCellBoolRenderer, gridlib.GridCellBoolEditor),
]
class EditorsAndRenderersGrid(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
self.log = log
self.CreateGrid(25, 8)
renCol = 1
edCol = 4
self.SetCellValue(0, renCol, '''\
Cell Renderers are used to draw
the contents of the cell when they
need to be refreshed. Different
types of Renderers can be plugged in
to different cells in the grid, it can
even be automatically determined based
on the type of data in the cell.
''')
self.SetCellValue(0, edCol, '''\
Cell Editors are used when the
value of the cell is edited by
the user. An editor class is
wrapped around a an object
derived from wxControl and it
implements some methods required
to integrate with the grid.
''')
self.SetCellValue(16, renCol, '''\
Here are some combinations of Editors and
Renderers used together.
''')
row = 2
for label, value, renderClass, args in rendererDemoData:
renderer = renderClass(*args)
self.SetCellValue(row, renCol, label)
self.SetCellValue(row, renCol+1, value)
self.SetCellRenderer(row, renCol+1, renderer)
row = row + 2
row = 2
for label, value, editorClass, args in editorDemoData:
editor = editorClass(*args)
self.SetCellValue(row, edCol, label)
self.SetCellValue(row, edCol+1, value)
self.SetCellEditor(row, edCol+1, editor)
row = row + 2
row = 18
for label, value, renClass, edClass in comboDemoData:
self.SetCellValue(row, renCol, label)
self.SetCellValue(row, renCol+1, value)
editor = edClass()
renderer = renClass()
self.SetCellEditor(row, renCol+1, editor)
self.SetCellRenderer(row, renCol+1, renderer)
row = row + 2
font = self.GetFont()
font.SetWeight(wx.BOLD)
attr = gridlib.GridCellAttr()
attr.SetFont(font)
attr.SetBackgroundColour(wx.LIGHT_GREY)
attr.SetReadOnly(True)
attr.SetAlignment(wx.RIGHT, -1)
self.SetColAttr(renCol, attr)
attr.IncRef()
self.SetColAttr(edCol, attr)
# There is a bug in wxGTK for this method...
self.AutoSizeColumns(True)
self.AutoSizeRows(True)
self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnLeftDClick)
# I do this because I don't like the default behaviour of not starting the
# cell editor on double clicks, but only a second click.
def OnLeftDClick(self, evt):
if self.CanEnableCellControl():
self.EnableCellEditControl()
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Editors and Renderers Demo", size=(640,480))
grid = EditorsAndRenderersGrid(self, log)
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
#---------------------------------------------------------------------------

497
demo/Grid_MegaExample.py Normal file
View File

@@ -0,0 +1,497 @@
import wx
import wx.grid as Grid
import images
#---------------------------------------------------------------------------
class MegaTable(Grid.PyGridTableBase):
"""
A custom wx.Grid Table using user supplied data
"""
def __init__(self, data, colnames, plugins):
"""data is a list of the form
[(rowname, dictionary),
dictionary.get(colname, None) returns the data for column
colname
"""
# The base class must be initialized *first*
Grid.PyGridTableBase.__init__(self)
self.data = data
self.colnames = colnames
self.plugins = plugins or {}
# XXX
# we need to store the row length and column length to
# see if the table has changed size
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
def GetNumberCols(self):
return len(self.colnames)
def GetNumberRows(self):
return len(self.data)
def GetColLabelValue(self, col):
return self.colnames[col]
def GetRowLabelValue(self, row):
return "row %03d" % int(self.data[row][0])
def GetValue(self, row, col):
return str(self.data[row][1].get(self.GetColLabelValue(col), ""))
def GetRawValue(self, row, col):
return self.data[row][1].get(self.GetColLabelValue(col), "")
def SetValue(self, row, col, value):
self.data[row][1][self.GetColLabelValue(col)] = value
def ResetView(self, grid):
"""
(Grid) -> Reset the grid view. Call this to
update the grid if rows and columns have been added or deleted
"""
grid.BeginBatch()
for current, new, delmsg, addmsg in [
(self._rows, self.GetNumberRows(), Grid.GRIDTABLE_NOTIFY_ROWS_DELETED, Grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
(self._cols, self.GetNumberCols(), Grid.GRIDTABLE_NOTIFY_COLS_DELETED, Grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
]:
if new < current:
msg = Grid.GridTableMessage(self,delmsg,new,current-new)
grid.ProcessTableMessage(msg)
elif new > current:
msg = Grid.GridTableMessage(self,addmsg,new-current)
grid.ProcessTableMessage(msg)
self.UpdateValues(grid)
grid.EndBatch()
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
# update the column rendering plugins
self._updateColAttrs(grid)
# update the scrollbars and the displayed part of the grid
grid.AdjustScrollbars()
grid.ForceRefresh()
def UpdateValues(self, grid):
"""Update all displayed values"""
# This sends an event to the grid table to update all of the values
msg = Grid.GridTableMessage(self, Grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
grid.ProcessTableMessage(msg)
def _updateColAttrs(self, grid):
"""
wx.Grid -> update the column attributes to add the
appropriate renderer given the column name. (renderers
are stored in the self.plugins dictionary)
Otherwise default to the default renderer.
"""
col = 0
for colname in self.colnames:
attr = Grid.GridCellAttr()
if colname in self.plugins:
renderer = self.plugins[colname](self)
if renderer.colSize:
grid.SetColSize(col, renderer.colSize)
if renderer.rowSize:
grid.SetDefaultRowSize(renderer.rowSize)
attr.SetReadOnly(True)
attr.SetRenderer(renderer)
grid.SetColAttr(col, attr)
col += 1
# ------------------------------------------------------
# begin the added code to manipulate the table (non wx related)
def AppendRow(self, row):
#print 'append'
entry = {}
for name in self.colnames:
entry[name] = "Appended_%i"%row
# XXX Hack
# entry["A"] can only be between 1..4
entry["A"] = random.choice(range(4))
self.data.insert(row, ["Append_%i"%row, entry])
def DeleteCols(self, cols):
"""
cols -> delete the columns from the dataset
cols hold the column indices
"""
# we'll cheat here and just remove the name from the
# list of column names. The data will remain but
# it won't be shown
deleteCount = 0
cols = cols[:]
cols.sort()
for i in cols:
self.colnames.pop(i-deleteCount)
# we need to advance the delete count
# to make sure we delete the right columns
deleteCount += 1
if not len(self.colnames):
self.data = []
def DeleteRows(self, rows):
"""
rows -> delete the rows from the dataset
rows hold the row indices
"""
deleteCount = 0
rows = rows[:]
rows.sort()
for i in rows:
self.data.pop(i-deleteCount)
# we need to advance the delete count
# to make sure we delete the right rows
deleteCount += 1
def SortColumn(self, col):
"""
col -> sort the data based on the column indexed by col
"""
name = self.colnames[col]
_data = []
for row in self.data:
rowname, entry = row
_data.append((entry.get(name, None), row))
_data.sort()
self.data = []
for sortvalue, row in _data:
self.data.append(row)
# end table manipulation code
# ----------------------------------------------------------
# --------------------------------------------------------------------
# Sample wx.Grid renderers
class MegaImageRenderer(Grid.PyGridCellRenderer):
def __init__(self, table):
"""
Image Renderer Test. This just places an image in a cell
based on the row index. There are N choices and the
choice is made by choice[row%N]
"""
Grid.PyGridCellRenderer.__init__(self)
self.table = table
self._choices = [images.Smiles.GetBitmap,
images.Mondrian.GetBitmap,
images.WXPdemo.GetBitmap,
]
self.colSize = None
self.rowSize = None
def Draw(self, grid, attr, dc, rect, row, col, isSelected):
choice = self.table.GetRawValue(row, col)
bmp = self._choices[ choice % len(self._choices)]()
image = wx.MemoryDC()
image.SelectObject(bmp)
# clear the background
dc.SetBackgroundMode(wx.SOLID)
if isSelected:
dc.SetBrush(wx.Brush(wx.BLUE, wx.SOLID))
dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID))
else:
dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
dc.SetPen(wx.Pen(wx.WHITE, 1, wx.SOLID))
dc.DrawRectangleRect(rect)
# copy the image but only to the size of the grid cell
width, height = bmp.GetWidth(), bmp.GetHeight()
if width > rect.width-2:
width = rect.width-2
if height > rect.height-2:
height = rect.height-2
dc.Blit(rect.x+1, rect.y+1, width, height,
image,
0, 0, wx.COPY, True)
class MegaFontRenderer(Grid.PyGridCellRenderer):
def __init__(self, table, color="blue", font="ARIAL", fontsize=8):
"""Render data in the specified color and font and fontsize"""
Grid.PyGridCellRenderer.__init__(self)
self.table = table
self.color = color
self.font = wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, font)
self.selectedBrush = wx.Brush("blue", wx.SOLID)
self.normalBrush = wx.Brush(wx.WHITE, wx.SOLID)
self.colSize = None
self.rowSize = 50
def Draw(self, grid, attr, dc, rect, row, col, isSelected):
# Here we draw text in a grid cell using various fonts
# and colors. We have to set the clipping region on
# the grid's DC, otherwise the text will spill over
# to the next cell
dc.SetClippingRect(rect)
# clear the background
dc.SetBackgroundMode(wx.SOLID)
if isSelected:
dc.SetBrush(wx.Brush(wx.BLUE, wx.SOLID))
dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID))
else:
dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
dc.SetPen(wx.Pen(wx.WHITE, 1, wx.SOLID))
dc.DrawRectangleRect(rect)
text = self.table.GetValue(row, col)
dc.SetBackgroundMode(wx.SOLID)
# change the text background based on whether the grid is selected
# or not
if isSelected:
dc.SetBrush(self.selectedBrush)
dc.SetTextBackground("blue")
else:
dc.SetBrush(self.normalBrush)
dc.SetTextBackground("white")
dc.SetTextForeground(self.color)
dc.SetFont(self.font)
dc.DrawText(text, rect.x+1, rect.y+1)
# Okay, now for the advanced class :)
# Let's add three dots "..."
# to indicate that that there is more text to be read
# when the text is larger than the grid cell
width, height = dc.GetTextExtent(text)
if width > rect.width-2:
width, height = dc.GetTextExtent("...")
x = rect.x+1 + rect.width-2 - width
dc.DrawRectangle(x, rect.y+1, width+1, height)
dc.DrawText("...", x, rect.y+1)
dc.DestroyClippingRegion()
# --------------------------------------------------------------------
# Sample Grid using a specialized table and renderers that can
# be plugged in based on column names
class MegaGrid(Grid.Grid):
def __init__(self, parent, data, colnames, plugins=None):
"""parent, data, colnames, plugins=None
Initialize a grid using the data defined in data and colnames
(see MegaTable for a description of the data format)
plugins is a dictionary of columnName -> column renderers.
"""
# The base class must be initialized *first*
Grid.Grid.__init__(self, parent, -1)
self._table = MegaTable(data, colnames, plugins)
self.SetTable(self._table)
self._plugins = plugins
self.Bind(Grid.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClicked)
def Reset(self):
"""reset the view based on the data in the table. Call
this when rows are added or destroyed"""
self._table.ResetView(self)
def OnLabelRightClicked(self, evt):
# Did we click on a row or a column?
row, col = evt.GetRow(), evt.GetCol()
if row == -1: self.colPopup(col, evt)
elif col == -1: self.rowPopup(row, evt)
def rowPopup(self, row, evt):
"""(row, evt) -> display a popup menu when a row label is right clicked"""
appendID = wx.NewId()
deleteID = wx.NewId()
x = self.GetRowSize(row)/2
if not self.GetSelectedRows():
self.SelectRow(row)
menu = wx.Menu()
xo, yo = evt.GetPosition()
menu.Append(appendID, "Append Row")
menu.Append(deleteID, "Delete Row(s)")
def append(event, self=self, row=row):
self._table.AppendRow(row)
self.Reset()
def delete(event, self=self, row=row):
rows = self.GetSelectedRows()
self._table.DeleteRows(rows)
self.Reset()
self.Bind(wx.EVT_MENU, append, id=appendID)
self.Bind(wx.EVT_MENU, delete, id=deleteID)
self.PopupMenu(menu)
menu.Destroy()
return
def colPopup(self, col, evt):
"""(col, evt) -> display a popup menu when a column label is
right clicked"""
x = self.GetColSize(col)/2
menu = wx.Menu()
id1 = wx.NewId()
sortID = wx.NewId()
xo, yo = evt.GetPosition()
self.SelectCol(col)
cols = self.GetSelectedCols()
self.Refresh()
menu.Append(id1, "Delete Col(s)")
menu.Append(sortID, "Sort Column")
def delete(event, self=self, col=col):
cols = self.GetSelectedCols()
self._table.DeleteCols(cols)
self.Reset()
def sort(event, self=self, col=col):
self._table.SortColumn(col)
self.Reset()
self.Bind(wx.EVT_MENU, delete, id=id1)
if len(cols) == 1:
self.Bind(wx.EVT_MENU, sort, id=sortID)
self.PopupMenu(menu)
menu.Destroy()
return
# -----------------------------------------------------------------
# Test data
# data is in the form
# [rowname, dictionary]
# where dictionary.get(colname, None) -> returns the value for the cell
#
# the colname must also be supplied
import random
colnames = ["Row", "This", "Is", "A", "Test"]
data = []
for row in range(1000):
d = {}
for name in ["This", "Test", "Is"]:
d[name] = random.random()
d["Row"] = len(data)
# XXX
# the "A" column can only be between one and 4
d["A"] = random.choice(range(4))
data.append((str(row), d))
class MegaFontRendererFactory:
def __init__(self, color, font, fontsize):
"""
(color, font, fontsize) -> set of a factory to generate
renderers when called.
func = MegaFontRenderFactory(color, font, fontsize)
renderer = func(table)
"""
self.color = color
self.font = font
self.fontsize = fontsize
def __call__(self, table):
return MegaFontRenderer(table, self.color, self.font, self.fontsize)
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, plugins={"This":MegaFontRendererFactory("red", "ARIAL", 8),
"A":MegaImageRenderer,
"Test":MegaFontRendererFactory("orange", "TIMES", 24),}):
wx.Frame.__init__(self, parent, -1,
"Test Frame", size=(640,480))
grid = MegaGrid(self, data, colnames, plugins)
grid.Reset()
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Show the MegaGrid", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
win = TestFrame(self)
win.Show(True)
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
overview = """Mega Grid Example
This example attempts to show many examples and tricks of
using a virtual grid object. Hopefully the source isn't too jumbled.
Features:
<ol>
<li>Uses a virtual grid
<li>Columns and rows have popup menus (right click on labels)
<li>Columns and rows can be deleted (i.e. table can be
resized)
<li>Dynamic renderers. Renderers are plugins based on
column header name. Shows a simple Font Renderer and
an Image Renderer.
</ol>
Look for 'XXX' in the code to indicate some workarounds for non-obvious
behavior and various hacks.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

154
demo/HTML2_WebView.py Normal file
View File

@@ -0,0 +1,154 @@
import wx
import wx.html2 as webview
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log, frame=None):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.current = "http://wxPython.org"
self.frame = frame
if frame:
self.titleBase = frame.GetTitle()
sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
self.wv = webview.WebView.New(self)
self.Bind(webview.EVT_WEB_VIEW_NAVIGATING, self.OnWebViewNavigating, self.wv)
self.Bind(webview.EVT_WEB_VIEW_LOADED, self.OnWebViewLoaded, self.wv)
btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn)
btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn)
btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)
txt = wx.StaticText(self, -1, "Location:")
btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2)
self.location = wx.ComboBox(
self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER)
self.location.AppendItems(['http://wxPython.org',
'http://wxwidgets.org',
'http://google.com'])
self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location)
self.location.Bind(wx.EVT_TEXT_ENTER, self.OnLocationEnter)
btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2)
sizer.Add(btnSizer, 0, wx.EXPAND)
sizer.Add(self.wv, 1, wx.EXPAND)
self.SetSizer(sizer)
self.wv.LoadURL(self.current)
def ShutdownDemo(self):
# put the frame title back
if self.frame:
self.frame.SetTitle(self.titleBase)
# WebView events
def OnWebViewNavigating(self, evt):
# this event happens prior to trying to get a resource
if evt.GetURL() == 'http://www.microsoft.com/':
if wx.MessageBox("Are you sure you want to visit Microsoft?",
style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO:
# This is how you can cancel loading a page.
evt.Veto()
def OnWebViewLoaded(self, evt):
# The full document has loaded
self.current = evt.GetURL()
self.location.SetValue(self.current)
# Control bar events
def OnLocationSelect(self, evt):
url = self.location.GetStringSelection()
self.log.write('OnLocationSelect: %s\n' % url)
self.wv.LoadURL(url)
def OnLocationEnter(self, evt):
url = self.location.GetValue()
self.location.Append(url)
self.wv.LoadURL(url)
def OnOpenButton(self, event):
dlg = wx.TextEntryDialog(self, "Open Location",
"Enter a full URL or local path",
self.current, wx.OK|wx.CANCEL)
dlg.CentreOnParent()
if dlg.ShowModal() == wx.ID_OK:
self.current = dlg.GetValue()
self.wv.LoadURL(self.current)
dlg.Destroy()
def OnPrevPageButton(self, event):
self.wv.GoBack()
def OnNextPageButton(self, event):
self.wv.GoForward()
def OnCheckCanGoBack(self, event):
event.Enable(self.wv.CanGoBack())
def OnCheckCanGoForward(self, event):
event.Enable(self.wv.CanGoForward())
def OnStopButton(self, evt):
self.wv.Stop()
def OnRefreshPageButton(self, evt):
self.wv.Reload()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>DemoName</center></h2>
Say something nice here
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

224
demo/HtmlWindow.py Normal file
View File

@@ -0,0 +1,224 @@
import os
import sys
import wx
import wx.html as html
import wx.lib.wxpTag
from Main import opj
#----------------------------------------------------------------------
# This shows how to catch the OnLinkClicked non-event. (It's a virtual
# method in the C++ code...)
class MyHtmlWindow(html.HtmlWindow):
def __init__(self, parent, id, log):
html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.log = log
if "gtk2" in wx.PlatformInfo:
self.SetStandardFonts()
def OnLinkClicked(self, linkinfo):
self.log.WriteText('OnLinkClicked: %s\n' % linkinfo.GetHref())
super(MyHtmlWindow, self).OnLinkClicked(linkinfo)
def OnSetTitle(self, title):
self.log.WriteText('OnSetTitle: %s\n' % title)
super(MyHtmlWindow, self).OnSetTitle(title)
def OnCellMouseHover(self, cell, x, y):
self.log.WriteText('OnCellMouseHover: %s, (%d %d)\n' % (cell, x, y))
super(MyHtmlWindow, self).OnCellMouseHover(cell, x, y)
def OnCellClicked(self, cell, x, y, evt):
self.log.WriteText('OnCellClicked: %s, (%d %d)\n' % (cell, x, y))
if isinstance(cell, html.HtmlWordCell):
sel = html.HtmlSelection()
self.log.WriteText(' %s\n' % cell.ConvertToText(sel))
super(MyHtmlWindow, self).OnCellClicked(cell, x, y, evt)
# This filter doesn't really do anything but show how to use filters
class MyHtmlFilter(html.HtmlFilter):
def __init__(self, log):
html.HtmlFilter.__init__(self)
self.log = log
# This method decides if this filter is able to read the file
def CanRead(self, fsfile):
self.log.write("CanRead: %s\n" % fsfile.GetMimeType())
return False
# If CanRead returns True then this method is called to actually
# read the file and return the contents.
def ReadFile(self, fsfile):
return ""
class TestHtmlPanel(wx.Panel):
def __init__(self, parent, frame, log):
wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.log = log
self.frame = frame
self.cwd = os.path.split(sys.argv[0])[0]
if not self.cwd:
self.cwd = os.getcwd()
if frame:
self.titleBase = frame.GetTitle()
html.HtmlWindow_AddFilter(MyHtmlFilter(log))
self.html = MyHtmlWindow(self, -1, log)
self.html.SetRelatedFrame(frame, self.titleBase + " -- %s")
self.html.SetRelatedStatusBar(0)
self.printer = html.HtmlEasyPrinting()
self.box = wx.BoxSizer(wx.VERTICAL)
self.box.Add(self.html, 1, wx.GROW)
subbox = wx.BoxSizer(wx.HORIZONTAL)
btn = wx.Button(self, -1, "Load File")
self.Bind(wx.EVT_BUTTON, self.OnLoadFile, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "Load URL")
self.Bind(wx.EVT_BUTTON, self.OnLoadURL, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "With Widgets")
self.Bind(wx.EVT_BUTTON, self.OnWithWidgets, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "Back")
self.Bind(wx.EVT_BUTTON, self.OnBack, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "Forward")
self.Bind(wx.EVT_BUTTON, self.OnForward, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "Print")
self.Bind(wx.EVT_BUTTON, self.OnPrint, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
btn = wx.Button(self, -1, "View Source")
self.Bind(wx.EVT_BUTTON, self.OnViewSource, btn)
subbox.Add(btn, 1, wx.GROW | wx.ALL, 2)
self.box.Add(subbox, 0, wx.GROW)
self.SetSizer(self.box)
self.SetAutoLayout(True)
# A button with this ID is created on the widget test page.
self.Bind(wx.EVT_BUTTON, self.OnOk, id=wx.ID_OK)
self.OnShowDefault(None)
def ShutdownDemo(self):
# put the frame title back
if self.frame:
self.frame.SetTitle(self.titleBase)
def OnShowDefault(self, event):
name = os.path.join(self.cwd, opj('data/test.htm'))
self.html.LoadPage(name)
def OnLoadFile(self, event):
dlg = wx.FileDialog(self, style=wx.OPEN,
wildcard='HTML Files|*.htm;*.html', )
if dlg.ShowModal():
path = dlg.GetPath()
self.html.LoadPage(path)
dlg.Destroy()
def OnLoadURL(self, event):
dlg = wx.TextEntryDialog(self, "Enter a URL")
if dlg.ShowModal():
url = dlg.GetValue()
self.html.LoadPage(url)
dlg.Destroy()
def OnWithWidgets(self, event):
os.chdir(self.cwd)
name = os.path.join(self.cwd, opj('data/widgetTest.htm'))
self.html.LoadPage(name)
def OnOk(self, event):
self.log.WriteText("It works!\n")
def OnBack(self, event):
if not self.html.HistoryBack():
wx.MessageBox("No more items in history!")
def OnForward(self, event):
if not self.html.HistoryForward():
wx.MessageBox("No more items in history!")
def OnViewSource(self, event):
import wx.lib.dialogs
source = self.html.GetParser().GetSource()
dlg = wx.lib.dialogs.ScrolledMessageDialog(self, source, 'HTML Source')
dlg.ShowModal()
dlg.Destroy()
def OnPrint(self, event):
self.printer.GetPrintData().SetPaperId(wx.PAPER_LETTER)
self.printer.PrintFile(self.html.GetOpenedPage())
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestHtmlPanel(nb, frame, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2>wx.HtmlWindow</h2>
<p>wx.HtmlWindow is capable of parsing and rendering most
simple HTML tags.
<p>It is not intended to be a high-end HTML browser. If you're
looking for something like that see the IEHtmlWin class, which
wraps the core MSIE HTML viewer.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

234
demo/I18N.py Normal file
View File

@@ -0,0 +1,234 @@
#Boa:FramePanel:LanguageSelectPanel
import os, sys
import wx
from wx.lib import langlistctrl
from Main import opj
# Normally you would just set _ to be a reference to the
# wx.GetTranslation function, and then wrap all you literal strings in
# _() function calls. Then everytime you use one of your literals, it
# would first pass through the translation function and try to load a
# translated version of the string from the current message catalogs.
# For this example, since we are changinb language on the fly, and
# since we are only translating the label for one widget, we'll not do
# it the automatic way and we'll be more explicit. See the setup in
# __init__() and the translation done in updateLanguage() below.
_ = wx.GetTranslation
exampleStrings = [
'the quick brown fox jumps over the lazy dog', # demo string
'Tip of the Day', # wx built in translation
'Warning', # wx built in translation
]
[wxID_LANGUAGESELECTPANEL, wxID_LANGUAGESELECTPANELENGLISHBASECH,
wxID_LANGUAGESELECTPANELLANGCTRLCONTAINER,
wxID_LANGUAGESELECTPANELLANGFILTERRB, wxID_LANGUAGESELECTPANELSTATICLINE1,
wxID_LANGUAGESELECTPANELSTATICTEXT1, wxID_LANGUAGESELECTPANELSTATICTEXT2,
wxID_LANGUAGESELECTPANELSTATICTEXT3, wxID_LANGUAGESELECTPANELTRANSLATEDST,
] = [wx.NewId() for _init_ctrls in range(9)]
class LanguageSelectPanel(wx.Panel):
def _init_coll_boxSizer3_Items(self, parent):
# generated method, don't edit
parent.AddWindow(self.langCtrlContainer, 1, border=0, flag=wx.GROW)
parent.AddSpacer(wx.Size(8, 8), border=0, flag=0)
parent.AddWindow(self.langFilterRB, 0, border=0, flag=0)
def _init_coll_flexGridSizer1_Growables(self, parent):
# generated method, don't edit
parent.AddGrowableRow(1)
parent.AddGrowableCol(0)
def _init_coll_boxSizer1_Items(self, parent):
# generated method, don't edit
parent.AddWindow(self.staticText1, 0, border=8, flag=wx.ALL)
parent.AddSizer(self.boxSizer3, 1, border=8, flag=wx.ALL | wx.GROW)
parent.AddSizer(self.boxSizer2, 0, border=8, flag=wx.GROW | wx.ALL)
def _init_coll_boxSizer2_Items(self, parent):
# generated method, don't edit
parent.AddWindow(self.staticText2, 0, border=8, flag=wx.ALL)
parent.AddWindow(self.englishBaseCh, 0, border=8, flag=wx.GROW | wx.ALL)
parent.AddWindow(self.staticLine1, 0, border=8, flag=wx.GROW | wx.ALL)
parent.AddWindow(self.staticText3, 0, border=8, flag=wx.ALL)
parent.AddWindow(self.translatedST, 0, border=8, flag=wx.GROW | wx.ALL)
def _init_sizers(self):
# generated method, don't edit
self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL)
self.flexGridSizer1 = wx.FlexGridSizer(cols=2, hgap=8, rows=0, vgap=8)
self.boxSizer3 = wx.BoxSizer(orient=wx.HORIZONTAL)
self.boxSizer2 = wx.BoxSizer(orient=wx.VERTICAL)
self._init_coll_boxSizer1_Items(self.boxSizer1)
self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
self._init_coll_boxSizer3_Items(self.boxSizer3)
self._init_coll_boxSizer2_Items(self.boxSizer2)
self.SetSizer(self.boxSizer1)
def _init_ctrls(self, prnt):
# generated method, don't edit
wx.Panel.__init__(self, id=wxID_LANGUAGESELECTPANEL,
name='LanguageSelectPanel', parent=prnt,
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE)
self.staticText1 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT1,
label='Choose a language that will be used for example translation.',
name='staticText1', parent=self, style=0)
self.langCtrlContainer = wx.Panel(id=wxID_LANGUAGESELECTPANELLANGCTRLCONTAINER,
name='langCtrlContainer', parent=self, style=wx.TAB_TRAVERSAL)
self.langCtrlContainer.SetBackgroundColour(wx.Colour(255, 255, 255))
self.langCtrlContainer.Bind(wx.EVT_SIZE, self.OnLangCtrlContainerSize)
self.langFilterRB = wx.RadioBox(choices=['Translated example languages',
'Available languages on your system', 'All languages'],
id=wxID_LANGUAGESELECTPANELLANGFILTERRB, label='Filter',
majorDimension=1, name='langFilterRB', parent=self,
style=wx.RA_SPECIFY_COLS)
self.langFilterRB.Bind(wx.EVT_RADIOBOX, self.OnLangFilterRBRadiobox,
id=wxID_LANGUAGESELECTPANELLANGFILTERRB)
self.staticText2 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT2,
label='English Text:', name='staticText2', parent=self,
style=0)
self.staticText3 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT3,
label='Translated Text:', name='staticText3', parent=self,
style=0)
self.englishBaseCh = wx.Choice(choices=self.choices,
id=wxID_LANGUAGESELECTPANELENGLISHBASECH, name='englishBaseCh',
parent=self, style=0)
self.englishBaseCh.Bind(wx.EVT_CHOICE, self.OnLangSelectAndTranslate,
id=wxID_LANGUAGESELECTPANELENGLISHBASECH)
self.staticLine1 = wx.StaticLine(id=wxID_LANGUAGESELECTPANELSTATICLINE1,
name='staticLine1', parent=self, style=0)
self.translatedST = wx.StaticText(id=wxID_LANGUAGESELECTPANELTRANSLATEDST,
label='', name='translatedST', parent=self, style=0)
self._init_sizers()
def __init__(self, parent, log):
self.choices = []
self.choices = exampleStrings
self._init_ctrls(parent)
self.log = log
lang = wx.LANGUAGE_DEFAULT
filter = 'demo'
langs = (wx.LANGUAGE_AFRIKAANS, wx.LANGUAGE_ENGLISH, wx.LANGUAGE_DEFAULT,
wx.LANGUAGE_SPANISH, wx.LANGUAGE_GERMAN, wx.LANGUAGE_ITALIAN,
wx.LANGUAGE_FRENCH)
# usually you would define wx.Locale in your wx.App.OnInit class.
# for the demo we just define it in this module
self.locale = None
wx.Locale.AddCatalogLookupPathPrefix(opj('data/locale'))
self.updateLanguage(wx.LANGUAGE_DEFAULT)
self.filterMap = {'demo': langlistctrl.LC_ONLY,
'available': langlistctrl.LC_AVAILABLE,
'all': langlistctrl.LC_ALL}
self.filterIdxMap = {0: 'demo',
1: 'available',
2: 'all'}
self.langs = langs
self.langCtrl = langlistctrl.LanguageListCtrl(self.langCtrlContainer, -1,
filter=self.filterMap[filter], only=langs, select=lang)
self.langCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnLangSelectAndTranslate)
self.langCtrl.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnClearTranslatedText)
self.OnLangCtrlContainerSize()
self.englishBaseCh.Select(0)
self.OnLangSelectAndTranslate()
def updateLanguage(self, lang):
# Make *sure* any existing locale is deleted before the new
# one is created. The old C++ object needs to be deleted
# before the new one is created, and if we just assign a new
# instance to the old Python variable, the old C++ locale will
# not be destroyed soon enough, likely causing a crash.
if self.locale:
assert sys.getrefcount(self.locale) <= 2
del self.locale
# create a locale object for this language
self.locale = wx.Locale(lang)
if self.locale.IsOk():
self.locale.AddCatalog('wxpydemo')
else:
self.locale = None
def translateExample(self):
self.translatedST.SetLabel(_(self.englishBaseCh.GetStringSelection()))
def OnLangCtrlContainerSize(self, event=None):
if event: event.Skip()
self.langCtrl.SetSize(self.langCtrlContainer.GetSize())
def OnLangFilterRBRadiobox(self, event):
self.langCtrl.SetUpFilter(
self.filterMap[self.filterIdxMap[self.langFilterRB.GetSelection()]],
self.langs)
def OnLangSelectAndTranslate(self, event=None):
lang = self.langCtrl.GetLanguage()
if lang is not None:
# set to the selected language
self.updateLanguage(lang)
self.translateExample()
# set back to default
self.updateLanguage(wx.LANGUAGE_DEFAULT)
def OnClearTranslatedText(self, event):
self.translatedST.SetLabel('')
def runTest(frame, nb, log):
win = LanguageSelectPanel(nb, log)
return win
#-------------------------------------------------------------------------------
overview = """<html><body>
<h2>Internationalization (I18N)</h2>
<p>
This demo demonstrates how to setup and use the wx.Locale object to translate text.
<p>
It also shows the langlistctrl.LanguageListCtrl that can be used to display
languages with their associated countries flags, e.g. for setting the language
in your application.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])])

90
demo/Image.py Normal file
View File

@@ -0,0 +1,90 @@
import wx
from Main import opj
#----------------------------------------------------------------------
def runTest(frame, nb, log):
bmp = wx.Image(opj('bitmaps/image.bmp'), wx.BITMAP_TYPE_BMP).ConvertToBitmap()
gif = wx.Image(opj('bitmaps/image.gif'), wx.BITMAP_TYPE_GIF).ConvertToBitmap()
png = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap()
jpg = wx.Image(opj('bitmaps/image.jpg'), wx.BITMAP_TYPE_JPEG).ConvertToBitmap()
panel = wx.Panel(nb, -1)
pos = 10
wx.StaticBitmap(panel, -1, bmp, (10, pos))
pos = pos + bmp.GetHeight() + 10
wx.StaticBitmap(panel, -1, gif, (10, pos))
pos = pos + gif.GetHeight() + 10
wx.StaticBitmap(panel, -1, png, (10, pos))
pos = pos + png.GetHeight() + 10
wx.StaticBitmap(panel, -1, jpg, (10, pos))
greyscale = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToGreyscale().ConvertToBitmap()
disabled = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToDisabled().ConvertToBitmap()
mono = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToMono(0,255,255).ConvertToBitmap()
pos = 10
wx.StaticBitmap(panel, -1, greyscale, (320, pos))
pos = pos + greyscale.GetHeight() + 10
wx.StaticBitmap(panel, -1, disabled, (320, pos))
pos = pos + disabled.GetHeight() + 10
wx.StaticBitmap(panel, -1, mono, (320, pos))
return panel
#----------------------------------------------------------------------
overview = """\
<html>
<body>
This class encapsulates a platform-independent image. An image can be created
from data, or using <code>wxBitmap.ConvertToImage</code>. An image can be loaded from
a file in a variety of formats, and is extensible to new formats via image
format handlers. Functions are available to set and get image bits, so it can
be used for basic image manipulation.
<p>The following image handlers are available.
<p>
<table>
<tr><td width=25%>wxBMPHandler</td> <td>For loading and saving, always installed.</td></tr>
<tr><td>wxPNGHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxJPEGHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxGIFHandler</td> <td>Only for loading, due to legal issues.</td> </tr>
<tr><td>wxPCXHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxPNMHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxTIFFHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxIFFHandler</td> <td>For loading only.</td> </tr>
<tr><td>wxXPMHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxICOHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxCURHandler</td> <td>For loading and saving.</td> </tr>
<tr><td>wxANIHandler</td> <td>For loading only.</td> </tr>
</table>
<p>When saving in PCX format, wxPCXHandler will count the number of different
colours in the image; if there are 256 or less colours, it will save as 8 bit,
else it will save as 24 bit.
<p>Loading PNMs only works for ASCII or raw RGB images. When saving in PNM format,
wxPNMHandler will always save as raw RGB.
</body>
</html>"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

86
demo/ImageAlpha.py Normal file
View File

@@ -0,0 +1,86 @@
import wx # This module uses the new wx namespace
from Main import opj
#----------------------------------------------------------------------
msg = "Some text will appear mixed in the image's shadow..."
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
dc.SetBackground(wx.Brush("WHITE"))
dc.Clear()
dc.SetFont(wx.Font(16, wx.SWISS, wx.NORMAL, wx.BOLD, True))
dc.DrawText("Bitmap alpha blending (on all ports but gtk+ 1.2)",
25,25)
bmp = wx.Bitmap(opj('bitmaps/toucan.png'))
if "gtk1" in wx.PlatformInfo:
# Try to make up for lack of alpha support in wxGTK (gtk+
# 1.2) by converting the alpha blending into a
# transparency mask.
# first convert to a wx.Image
img = bmp.ConvertToImage()
# Then convert the alpha channel to a mask, specifying the
# threshold below which alpha will be made fully
# transparent
img.ConvertAlphaToMask(220)
# convert back to a wx.Bitmap
bmp = img.ConvertToBitmap()
dc.DrawBitmap(bmp, 25,100, True)
dc.SetFont(self.GetFont())
y = 75
for line in range(10):
y += dc.GetCharHeight() + 5
dc.DrawText(msg, 200, y)
dc.DrawBitmap(bmp, 250,100, True)
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>Images with Alpha</center></h2>
wxMSW and wxMac now support alpha channels of supported image
types, and will properly blend that channel when drawing a
bitmap. It is not supported yet on wxGTK, (if you would like to
change that please submit a patch!)
<p>On wxGTK this demo turns the alpha channel into a 1-bit mask, so
yes, it looks like crap. Please help us fix it!
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

68
demo/ImageBrowser.py Normal file
View File

@@ -0,0 +1,68 @@
#----------------------------------------------------------------------------
# Name: ImageBrowser.py
# Purpose: Image Selection dialog for wxPython demo
#
# Author: Lorne White (email: lorne.white@telusplanet.net)
#
# Version 0.5
# Date: Feb 26, 2001
# Licence: wxWindows license
#----------------------------------------------------------------------------
import os
import wx
import wx.lib.imagebrowser as ib
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show an ImageDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
# get current working directory
dir = os.getcwd()
# set the initial directory for the demo bitmaps
initial_dir = os.path.join(dir, 'bitmaps')
# open the image browser dialog
dlg = ib.ImageDialog(self, initial_dir)
dlg.Centre()
if dlg.ShowModal() == wx.ID_OK:
# show the selected file
self.log.WriteText("You Selected File: " + dlg.GetFile())
else:
self.log.WriteText("You pressed Cancel\n")
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

46
demo/ImageFromStream.py Normal file
View File

@@ -0,0 +1,46 @@
import cStringIO
import wx
from Main import opj
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent, -1)
data = open(opj('bitmaps/image.png'), "rb").read()
stream = cStringIO.StringIO(data)
bmp = wx.BitmapFromImage( wx.ImageFromStream( stream ))
wx.StaticText(
self, -1, "This image was loaded from a Python file-like object:",
(15, 15)
)
wx.StaticBitmap(self, -1, bmp, (15, 45))#, (bmp.GetWidth(), bmp.GetHeight()))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """\
At long last there is finally a way to load any supported image type
directly from any Python file-like object, such as a memory buffer
using StringIO. """
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

98
demo/Img2PyArtProvider.py Normal file
View File

@@ -0,0 +1,98 @@
import wx
from wx.lib.art import flagart, img2pyartprov
FlagArtProvider = None
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
title = wx.StaticText(self, -1, "Img2PyArtProvider")
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
sizer.Add((20,20))
box = wx.BoxSizer(wx.HORIZONTAL)
ch = wx.ComboBox(self, -1, 'BLANK', choices=flagart.index,
style=wx.CB_DROPDOWN|wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnSelectCountry, ch)
box.Add(ch, 0, wx.ALIGN_CENTER_VERTICAL)
box.Add((50,10))
bmp = wx.EmptyBitmap(32,22)
self.bmpFlag = wx.StaticBitmap(self, -1, bmp)
box.Add(self.bmpFlag, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(box, 0, wx.CENTER|wx.ALL, 10)
self.country = 'BLANK'
global FlagArtProvider
if FlagArtProvider is None:
FlagArtProvider = img2pyartprov.Img2PyArtProvider(flagart,
artIdPrefix='wx.ART_')
wx.ArtProvider.Push(FlagArtProvider)
self.getArt()
def OnSelectCountry(self, evt):
self.log.write("OnSelectCountry\n")
self.country = evt.GetString()
self.getArt()
def getArt(self):
bmp = wx.ArtProvider.GetBitmap('wx.ART_'+self.country, wx.ART_OTHER, (32,22))
if not bmp.Ok():
bmp = wx.EmptyBitmap(32,22)
self.clearBmp(bmp)
self.bmpFlag.SetBitmap(bmp)
def clearBmp(self, bmp):
dc = wx.MemoryDC()
dc.SelectObject(bmp)
dc.SetBackground(wx.Brush("white"))
dc.Clear()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>Img2PyArtProvider</center></h2>
Img2PyArtProvider is an ArtProvider class that publishes images from
modules generated by img2py.
<p>
This sample shows how to access the flag images in wx.lib.art.flagart
via the ArtProvider.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

125
demo/InfoBar.py Normal file
View File

@@ -0,0 +1,125 @@
import wx
#----------------------------------------------------------------------
flags = [ (wx.ICON_NONE, "ICON_NONE"),
(wx.ICON_INFORMATION, "ICON_INFORMATION"),
(wx.ICON_QUESTION, "ICON_QUESTION"),
(wx.ICON_WARNING, "ICON_WARNING"),
(wx.ICON_ERROR, "ICON_ERROR")
]
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
# Create the InfoBar. It starts out in a hidden state so it
# won't be visible until we need it.
self.info = wx.InfoBar(self)
panel = wx.Panel(self)
self.message = wx.TextCtrl(panel, -1, "Hello World", size=(250,-1))
self.flags = wx.Choice(panel, choices=[f[1] for f in flags])
self.flags.SetSelection(1) # wx.ICON_INFORMATION is the default
smBtn = wx.Button(panel, -1, "Show Message")
dmBtn = wx.Button(panel, -1, "Dismiss")
addBtn = wx.Button(panel, -1, "Add Button")
fgs = wx.FlexGridSizer(cols=3, vgap=10, hgap=10)
fgs.Add(wx.StaticText(panel, -1, "Message:"), 0,
wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
fgs.Add(self.message)
fgs.Add(self.flags)
fgs.AddSpacer(5)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(smBtn, 0, wx.RIGHT, 5)
hbox.Add(dmBtn)
fgs.Add(hbox)
fgs.AddSpacer(5)
fgs.AddSpacer(5)
fgs.Add(addBtn)
panel.Sizer = wx.BoxSizer(wx.VERTICAL)
text = """\
An info bar is a transient window shown at top or bottom of its parent window
to display non-critical information to the user."""
panel.Sizer.Add(wx.StaticText(panel, -1, text), 0, wx.TOP|wx.LEFT, 25)
panel.Sizer.Add(fgs, 1, wx.EXPAND|wx.ALL, 25)
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.info, 0, wx.EXPAND)
self.Sizer.Add(panel, 1, wx.EXPAND)
self.Bind(wx.EVT_BUTTON, self.OnShowMessage, smBtn)
self.Bind(wx.EVT_BUTTON, self.OnDismiss, dmBtn)
self.Bind(wx.EVT_BUTTON, self.OnAddButton, addBtn)
def OnShowMessage(self, evt):
msg = self.message.GetValue()
flag = flags[self.flags.GetSelection()][0]
self.info.ShowMessage(msg, flag)
def OnDismiss(self, evt):
self.info.Dismiss()
def OnAddButton(self, evt):
btnId = wx.NewId()
self.info.AddButton(btnId, "new button")
self.info.Bind(wx.EVT_BUTTON, self.OnButtonClicked, id=btnId)
def OnButtonClicked(self, evt):
wx.MessageBox("New button clicked")
# Calling evt.Skip() will allow the default handler to run
# which will dismiss the info bar. If you don't want it to be
# dismissed for a particular button then then don't call
# Skip().
evt.Skip()
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>wx.InfoBar</center></h2>
An info bar is a transient window shown at top or bottom of its parent
window to display non-critical information to the user.
<p>This class provides another way to show messages to the user,
intermediate between message boxes and status bar messages. The
message boxes are modal and thus interrupt the users work flow and
should be used sparingly for this reason. However status bar messages
are often too easy not to notice at all. An info bar provides a way to
present the messages which has a much higher chance to be noticed by
the user but without being annoying.
<p>Info bar may show an icon (on the left), text message and, optionally,
buttons allowing the user to react to the information presented. It
always has a close button at the right allowing the user to dismiss it
so it isn't necessary to provide a button just to close it.
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

342
demo/IntCtrl.py Normal file
View File

@@ -0,0 +1,342 @@
import wx
import wx.lib.intctrl
#----------------------------------------------------------------------
class TestPanel( wx.Panel ):
def __init__( self, parent, log ):
wx.Panel.__init__( self, parent, -1 )
self.log = log
panel = wx.Panel( self, -1 )
self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" )
self.min = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) )
self.min.Enable( False )
self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" )
self.max = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) )
self.max.Enable( False )
self.limit_target = wx.CheckBox( panel, -1, "Limit control" )
self.allow_none = wx.CheckBox( panel, -1, "Allow empty control" )
self.allow_long = wx.CheckBox( panel, -1, "Allow long integers" )
label = wx.StaticText( panel, -1, "Resulting integer control:" )
self.target_ctl = wx.lib.intctrl.IntCtrl( panel )
grid = wx.FlexGridSizer( cols=2 )
grid.Add( self.set_min, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
grid.Add( self.min, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add(self.set_max, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
grid.Add( self.max, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( self.limit_target, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( self.allow_none, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( self.allow_long, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 )
grid.Add( label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
grid.Add( self.target_ctl, 0, wx.ALIGN_LEFT|wx.ALL, 5 )
outer_box = wx.BoxSizer( wx.VERTICAL )
outer_box.Add( grid, 0, wx.ALIGN_CENTRE|wx.ALL, 20 )
panel.SetAutoLayout( True )
panel.SetSizer( outer_box )
outer_box.Fit( panel )
panel.Move( (50,50) )
self.panel = panel
self.Bind(wx.EVT_CHECKBOX, self.OnSetMin, self.set_min)
self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max)
self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_target)
self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none)
self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowLong, self.allow_long)
self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.min)
self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.max)
self.Bind(wx.lib.intctrl.EVT_INT, self.OnTargetChange, self.target_ctl)
def OnSetMin( self, event ):
self.min.Enable( self.set_min.GetValue() )
self.SetTargetMinMax()
def OnSetMax( self, event ):
self.max.Enable( self.set_max.GetValue() )
self.SetTargetMinMax()
def SetTargetMinMax( self, event=None ):
min = max = None
self.target_ctl.SetLimited( self.limit_target.GetValue() )
if self.set_min.GetValue():
min = self.min.GetValue()
if self.set_max.GetValue():
max = self.max.GetValue()
cur_min, cur_max = self.target_ctl.GetBounds()
if min != cur_min and not self.target_ctl.SetMin( min ):
self.log.write( "min (%d) > current max (%d) -- bound not set\n" % ( min, self.target_ctl.GetMax() ) )
self.min.SetForegroundColour( wx.RED )
else:
self.min.SetForegroundColour( wx.BLACK )
self.min.Refresh()
if max != cur_max and not self.target_ctl.SetMax( max ):
self.log.write( "max (%d) < current min (%d) -- bound not set\n" % ( max, self.target_ctl.GetMin() ) )
self.max.SetForegroundColour( wx.RED )
else:
self.max.SetForegroundColour( wx.BLACK )
self.max.Refresh()
if min != cur_min or max != cur_max:
new_min, new_max = self.target_ctl.GetBounds()
self.log.write( "current min, max: (%s, %s)\n" % ( str(new_min), str(new_max) ) )
def OnSetAllowNone( self, event ):
self.target_ctl.SetNoneAllowed( self.allow_none.GetValue() )
def OnSetAllowLong( self, event ):
self.target_ctl.SetLongAllowed( self.allow_long.GetValue() )
def OnTargetChange( self, event ):
ctl = event.GetEventObject()
value = ctl.GetValue()
ib_str = [ " (out of bounds)", "" ]
self.log.write( "integer value = %s%s\n" % ( str(value), ib_str[ ctl.IsInBounds(value) ] ) )
#----------------------------------------------------------------------
def runTest( frame, nb, log ):
win = TestPanel( nb, log )
return win
#----------------------------------------------------------------------
overview = """<html><body>
<P>
<B>IntCtrl</B> provides a control that takes and returns integers as
value, and provides bounds support and optional value limiting.
<P>
<P>
Here's the API for IntCtrl:
<DL><PRE>
<B>IntCtrl</B>(
parent, id = -1,
<B>value</B> = 0,
<B>min</B> = None,
<B>max</B> = None,
<B>limited</B> = False,
<B>allow_none</B> = False,
<B>allow_long</B> = False,
<B>default_color</B> = wxBLACK,
<B>oob_color</B> = wxRED,
pos = wxDefaultPosition,
size = wxDefaultSize,
style = 0,
name = "integer")
</PRE>
<UL>
<DT><B>value</B>
<DD>If no initial value is set, the default will be zero, or
the minimum value, if specified. If an illegal string is specified,
a ValueError will result. (You can always later set the initial
value with SetValue() after instantiation of the control.)
<BR>
<DL><B>min</B>
<DD>The minimum value that the control should allow. This can be
adjusted with SetMin(). If the control is not limited, any value
below this bound will be colored with the current out-of-bounds color.
<BR>
<DT><B>max</B>
<DD>The maximum value that the control should allow. This can be
adjusted with SetMax(). If the control is not limited, any value
above this bound will be colored with the current out-of-bounds color.
<BR>
<DT><B>limited</B>
<DD>Boolean indicating whether the control prevents values from
exceeding the currently set minimum and maximum values (bounds).
If <I>False</I> and bounds are set, out-of-bounds values will
be colored with the current out-of-bounds color.
<BR>
<DT><B>allow_none</B>
<DD>Boolean indicating whether or not the control is allowed to be
empty, representing a value of <I>None</I> for the control.
<BR>
<DT><B>allow_long</B>
<DD>Boolean indicating whether or not the control is allowed to hold
and return a value of type long as well as int. If False, the
control will be implicitly limited to have a value such that
-sys.maxint-1 &lt;= n &lt;= sys.maxint.
<BR>
<DT><B>default_color</B>
<DD>Color value used for in-bounds values of the control.
<BR>
<DT><B>oob_color</B>
<DD>Color value used for out-of-bounds values of the control
when the bounds are set but the control is not limited.
</UL>
<BR>
<BR>
<DT><B>EVT_INT(win, id, func)</B>
<DD>Respond to a wxEVT_COMMAND_INT_UPDATED event, generated when the
value changes. Notice that this event will always be sent when the
control's contents changes - whether this is due to user input or
comes from the program itself (for example, if SetValue() is called.)
<BR>
<BR>
<DT><B>SetValue(int)</B>
<DD>Sets the value of the control to the integer value specified.
The resulting actual value of the control may be altered to
conform with the bounds set on the control if limited,
or colored if not limited but the value is out-of-bounds.
A ValueError exception will be raised if an invalid value
is specified.
<BR>
<DT><B>GetValue()</B>
<DD>Retrieves the integer value from the control. The value
retrieved will be sized as an int if possible or a long,
if necessary.
<BR>
<BR>
<DT><B>SetMin(min=None)</B>
<DD>Sets the expected minimum value, or lower bound, of the control.
(The lower bound will only be enforced if the control is
configured to limit its values to the set bounds.)
If a value of <I>None</I> is provided, then the control will have
no explicit lower bound. If the value specified is greater than
the current lower bound, then the function returns 0 and the
lower bound will not change from its current setting. On success,
the function returns 1.
<DT><DD>If successful and the current value is
lower than the new lower bound, if the control is limited, the
value will be automatically adjusted to the new minimum value;
if not limited, the value in the control will be colored with
the current out-of-bounds color.
<BR>
<DT><B>GetMin()</B>
<DD>Gets the current lower bound value for the control.
It will return None if no lower bound is currently specified.
<BR>
<BR>
<DT><B>SetMax(max=None)</B>
<DD>Sets the expected maximum value, or upper bound, of the control.
(The upper bound will only be enforced if the control is
configured to limit its values to the set bounds.)
If a value of <I>None</I> is provided, then the control will
have no explicit upper bound. If the value specified is less
than the current lower bound, then the function returns 0 and
the maximum will not change from its current setting. On success,
the function returns 1.
<DT><DD>If successful and the current value
is greater than the new upper bound, if the control is limited
the value will be automatically adjusted to the new maximum value;
if not limited, the value in the control will be colored with the
current out-of-bounds color.
<BR>
<DT><B>GetMax()</B>
<DD>Gets the current upper bound value for the control.
It will return None if no upper bound is currently specified.
<BR>
<BR>
<DT><B>SetBounds(min=None,max=None)</B>
<DD>This function is a convenience function for setting the min and max
values at the same time. The function only applies the maximum bound
if setting the minimum bound is successful, and returns True
only if both operations succeed. <B><I>Note:</I></B> leaving out an argument
will remove the corresponding bound.
<DT><B>GetBounds()</B>
<DD>This function returns a two-tuple (min,max), indicating the
current bounds of the control. Each value can be None if
that bound is not set.
<BR>
<BR>
<DT><B>IsInBounds(value=None)</B>
<DD>Returns <I>True</I> if no value is specified and the current value
of the control falls within the current bounds. This function can also
be called with a value to see if that value would fall within the current
bounds of the given control.
<BR>
<BR>
<DT><B>SetLimited(bool)</B>
<DD>If called with a value of True, this function will cause the control
to limit the value to fall within the bounds currently specified.
If the control's value currently exceeds the bounds, it will then
be limited accordingly.
If called with a value of 0, this function will disable value
limiting, but coloring of out-of-bounds values will still take
place if bounds have been set for the control.
<DT><B>IsLimited()</B>
<DD>Returns <I>True</I> if the control is currently limiting the
value to fall within the current bounds.
<BR>
<BR>
<DT><B>SetNoneAllowed(bool)</B>
<DD>If called with a value of True, this function will cause the control
to allow the value to be empty, representing a value of None.
If called with a value of false, this function will prevent the value
from being None. If the value of the control is currently None,
ie. the control is empty, then the value will be changed to that
of the lower bound of the control, or 0 if no lower bound is set.
<DT><B>IsNoneAllowed()</B>
<DD>Returns <I>True</I> if the control currently allows its
value to be None.
<BR>
<BR>
<DT><B>SetLongAllowed(bool)</B>
<DD>If called with a value of True, this function will cause the
control to allow the value to be a long. If called with a value
of False, and the value of the control is currently a long value,
the value of the control will be adjusted to fall within the
size of an integer type, at either the sys.maxint or -sys.maxint-1,
for positive and negative values, respectively.
<DT><B>IsLongAllowed()</B>
<DD>Returns <I>True</I> if the control currently allows its
value to be of type long.
<BR>
<BR>
<DT><B>SetColors(default_color=wxBLACK, oob_color=wxRED)</B>
<DD>Tells the control what colors to use for normal and out-of-bounds
values. If the value currently exceeds the bounds, it will be
recolored accordingly.
<DT><B>GetColors()</B>
<DD>Returns a tuple of <I>(default_color, oob_color)</I> indicating
the current color settings for the control.
<BR>
<BR>
<DT><B>Cut()</B>
<DD>Will allow cuts to the clipboard of the text portion of the value,
leaving the value of zero if the entire contents are "cut."
<DT><B>Paste()</B>
<DD>Will paste the contents of the clipboard to the selected portion
of the value; if the resulting string does not represent a legal
value, a ValueError will result. If the result is out-of bounds,
it will either be adjusted or colored as appropriate.
</DL>
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

92
demo/ItemsPicker.py Normal file
View File

@@ -0,0 +1,92 @@
import wx
from wx.lib.itemspicker import ItemsPicker, \
EVT_IP_SELECTION_CHANGED, \
IP_SORT_CHOICES, IP_SORT_SELECTED,\
IP_REMOVE_FROM_CHOICES
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
sizer = wx.BoxSizer(wx.HORIZONTAL)
box = wx.StaticBox(self,-1,"ItemPicker styles")
boxSizer = wx.StaticBoxSizer(box,wx.VERTICAL)
self.sortChoices = wx.CheckBox(self,-1,'IP_SORT_CHOICES')
boxSizer.Add(self.sortChoices)
self.sortSelected = wx.CheckBox(self,-1,'IP_SORT_SELECTED')
boxSizer.Add(self.sortSelected)
self.removeFromChoices = wx.CheckBox(self,-1,'IP_REMOVE_FROM_CHOICES')
boxSizer.Add(self.removeFromChoices)
sizer.Add(boxSizer,0,wx.ALL,10)
b = wx.Button(self,-1,"Go")
b.Bind(wx.EVT_BUTTON,self.Go)
sizer.Add(b,0,wx.ALL,10)
self.SetSizer(sizer)
def Go(self,e):
style = 0
if self.sortChoices.GetValue():
style |= IP_SORT_CHOICES
if self.sortSelected.GetValue():
style |= IP_SORT_SELECTED
if self.removeFromChoices.GetValue():
style |= IP_REMOVE_FROM_CHOICES
d = ItemsPickerDialog(self, style, self.log)
d.ShowModal()
class ItemsPickerDialog(wx.Dialog):
def __init__(self,parent, style, log):
wx.Dialog.__init__(self,parent)
self.log = log
sizer =wx.BoxSizer(wx.VERTICAL)
b = wx.Button(self, -1, "Add Item")
b.Bind(wx.EVT_BUTTON, self.OnAdd)
sizer.Add(b, 0, wx.ALL, 5)
self.ip = ItemsPicker(self,-1,
['ThisIsItem3','ThisIsItem2','ThisIsItem1'],
'Stuff:', 'Selected stuff:',ipStyle = style)
self.ip.Bind(EVT_IP_SELECTION_CHANGED, self.OnSelectionChange)
self.ip._source.SetMinSize((-1,150))
sizer.Add(self.ip, 0, wx.ALL, 10)
self.SetSizer(sizer)
self.itemCount = 3
self.Fit()
def OnAdd(self,e):
items = self.ip.GetItems()
self.itemCount += 1
newItem = "item%d" % self.itemCount
self.ip.SetItems(items + [newItem])
def OnSelectionChange(self, e):
self.log.write("EVT_IP_SELECTION_CHANGED %s\n" % \
",".join(e.GetItems()))
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#----------------------------------------------------------------------
overview = """<html><body>
<h2><center>ItemsPicker </center></h2>
ItemsPicker is a widget that allows the user to choose a set of picked
items out of a given list
</body></html>
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])

Some files were not shown because too many files have changed in this diff Show More