Added masked edit controls (wxPython.lib.maskededit) by Jeff Childers

and Will Sadkin.  Updated wxTimeCtrl to use MaskedEdit.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@20321 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2003-04-23 21:25:23 +00:00
parent 376b7bd99e
commit 5dc5e70e20
6 changed files with 6499 additions and 767 deletions

View File

@@ -46,6 +46,10 @@ Toolbars on wxMac can now have controls on them.
Added wxPython.lib.analogclock module based on samples that were Added wxPython.lib.analogclock module based on samples that were
passed back and forth on wxPython-users a while back. passed back and forth on wxPython-users a while back.
Added masked edit controls (wxPython.lib.maskededit) by Jeff Childers
and Will Sadkin. Updated wxTimeCtrl to use MaskedEdit.

View File

@@ -31,6 +31,7 @@ _treeList = [
'NewNamespace', 'NewNamespace',
'PopupMenu', 'PopupMenu',
'AnalogClockWindow', 'AnalogClockWindow',
'MaskedEditControls',
]), ]),
# managed windows == things with a (optional) caption you can close # managed windows == things with a (optional) caption you can close
@@ -111,6 +112,7 @@ _treeList = [
'FancyText', 'FancyText',
'FileBrowseButton', 'FileBrowseButton',
'GenericButtons', 'GenericButtons',
'MaskedEditControls',
'PyShell', 'PyShell',
'PyCrust', 'PyCrust',
'SplitTree', 'SplitTree',

View File

@@ -0,0 +1,527 @@
from wxPython.wx import *
from wxPython.lib.maskededit import Field, wxMaskedTextCtrl, wxMaskedComboBox, wxIpAddrCtrl, states, months
from wxPython.lib.maskededit import __doc__ as overviewdoc
from wxPython.lib.scrolledpanel import wxScrolledPanel
import string
class demoMixin:
"""
Centralized routines common to demo pages, to remove repetition.
"""
def labelGeneralTable(self, sizer):
description = wxStaticText( self, -1, "Description", )
mask = wxStaticText( self, -1, "Mask Value" )
formatcode = wxStaticText( self, -1, "Format" )
regex = wxStaticText( self, -1, "Regexp\nValidator(opt.)" )
ctrl = wxStaticText( self, -1, "wxMaskedEdit Ctrl" )
description.SetFont( wxFont(9, wxSWISS, wxNORMAL, wxBOLD))
mask.SetFont( wxFont(9, wxSWISS, wxNORMAL, wxBOLD))
formatcode.SetFont( wxFont(9, wxSWISS, wxNORMAL, wxBOLD) )
regex.SetFont( wxFont(9, wxSWISS, wxNORMAL, wxBOLD))
ctrl.SetFont( wxFont(9, wxSWISS, wxNORMAL, wxBOLD))
sizer.Add(description)
sizer.Add(mask)
sizer.Add(formatcode)
sizer.Add(regex)
sizer.Add(ctrl)
def layoutGeneralTable(self, controls, sizer):
for control in controls:
sizer.Add( wxStaticText( self, -1, control[0]) )
sizer.Add( wxStaticText( self, -1, control[1]) )
sizer.Add( wxStaticText( self, -1, control[3]) )
sizer.Add( wxStaticText( self, -1, control[4]) )
if control in controls:
newControl = wxMaskedTextCtrl( self, -1, "",
mask = control[1],
excludeChars = control[2],
formatcodes = control[3],
includeChars = "",
validRegex = control[4],
validRange = control[5],
choices = control[6],
choiceRequired = True,
defaultValue = control[7],
demo = True,
name = control[0])
self.editList.append(newControl)
sizer.Add(newControl)
def changeControlParams(self, event, parameter, checked_value, notchecked_value):
if event.Checked(): value = checked_value
else: value = notchecked_value
kwargs = {parameter: value}
for control in self.editList:
control.SetMaskParameters(**kwargs)
control.Refresh()
self.Refresh()
#----------------------------------------------------------------------------
class demoPage1(wxScrolledPanel, demoMixin):
def __init__(self, parent, log):
wxScrolledPanel.__init__(self, parent, -1)
self.sizer = wxBoxSizer( wxVERTICAL )
self.editList = []
label = wxStaticText( self, -1, """\
Here are some basic wxMaskedTextCtrls to give you an idea of what you can do
with this control. Note that all controls have been auto-sized by including
F in the format code.
Try entering nonsensical or partial values in validated fields to see what
happens. Note that the State and Last Name fields are list-limited (valid
last names are: Smith, Jones, Williams). Signs on numbers can be toggled
with the minus key.
""")
label.SetForegroundColour( "Blue" )
header = wxBoxSizer( wxHORIZONTAL )
header.Add( label, 0, flag=wxALIGN_LEFT|wxALL, border = 5 )
highlight = wxCheckBox( self, -1, "Highlight Empty" )
disallow = wxCheckBox( self, -1, "Disallow Empty" )
showFill = wxCheckBox( self, -1, "change fillChar" )
vbox = wxBoxSizer( wxVERTICAL )
vbox.Add( highlight, 0, wxALIGN_LEFT|wxALL, 5 )
vbox.Add( disallow, 0, wxALIGN_LEFT|wxALL, 5 )
vbox.Add( showFill, 0, wxALIGN_LEFT|wxALL, 5 )
header.AddSpacer(15, 0)
header.Add(vbox, 0, flag=wxALIGN_LEFT|wxALL, border=5 )
EVT_CHECKBOX( self, highlight.GetId(), self.onHighlightEmpty )
EVT_CHECKBOX( self, disallow.GetId(), self.onDisallowEmpty )
EVT_CHECKBOX( self, showFill.GetId(), self.onShowFill )
grid = wxFlexGridSizer( 0, 5, vgap=10, hgap=10 )
self.labelGeneralTable(grid)
# The following list is of the controls for the demo. Feel free to play around with
# the options!
controls = [
#description mask excl format regexp range,list,initial
("Phone No", "(###) ###-#### x:###", "", 'F^-', "^\(\d{3}\) \d{3}-\d{4}", '','',''),
("Social Sec#", "###-##-####", "", 'F', "\d{3}-\d{2}-\d{4}", '','',''),
("Full Name", "C{14}", "", 'F_', '^[A-Z][a-zA-Z]+ [A-Z][a-zA-Z]+', '','',''),
("Last Name Only", "C{14}", "", 'F {list}', '^[A-Z][a-zA-Z]+', '',('Smith','Jones','Williams'),''),
("Zip plus 4", "#{5}-#{4}", "", 'F', "\d{5}-(\s{4}|\d{4})", '','',''),
("Customer No", "\CAA-###", "", 'F!', "C[A-Z]{2}-\d{3}", '','',''),
("Invoice Total", "#{9}.##", "", 'F-_,', "", '','',''),
]
self.layoutGeneralTable(controls, grid)
self.sizer.Add( header, 0, flag=wxALIGN_LEFT|wxALL, border=5 )
self.sizer.Add( grid, 0, flag= wxALIGN_LEFT|wxLEFT, border=5 )
self.SetSizer(self.sizer)
self.SetupScrolling()
self.SetAutoLayout(1)
def onDisallowEmpty( self, event ):
""" Set emptyInvalid parameter on/off """
self.changeControlParams( event, "emptyInvalid", True, False )
def onHighlightEmpty( self, event ):
""" Highlight empty values"""
self.changeControlParams( event, "emptyBackgroundColor", "Blue", "White" )
def onShowFill( self, event ):
""" Set fillChar parameter to '?' or ' ' """
self.changeControlParams( event, "fillChar", '?', ' ' )
class demoPage2(wxScrolledPanel, demoMixin):
def __init__(self, parent, log):
self.log = log
wxScrolledPanel.__init__(self, parent, -1)
self.sizer = wxBoxSizer( wxVERTICAL )
self.editList = []
label = wxStaticText( self, -1, """\
Here wxMaskedTextCtrls that have default values. The states
control has a list of valid values, and the unsigned integer
has a legal range specified.
""")
label.SetForegroundColour( "Blue" )
requireValid = wxCheckBox( self, -1, "Require Valid Value" )
EVT_CHECKBOX( self, requireValid.GetId(), self.onRequireValid )
header = wxBoxSizer( wxHORIZONTAL )
header.Add( label, 0, flag=wxALIGN_LEFT|wxALL, border = 5)
header.AddSpacer(75, 0)
header.Add( requireValid, 0, flag=wxALIGN_LEFT|wxALL, border=10 )
grid = wxFlexGridSizer( 0, 5, vgap=10, hgap=10 )
self.labelGeneralTable( grid )
controls = [
#description mask excl format regexp range,list,initial
("U.S. State (2 char)", "AA", "", 'F!_', "[A-Z]{2}", '',states, states[0]),
("Integer (signed)", "#{6}", "", 'F-_R', "", '','', '0 '),
("Integer (unsigned)\n(1-399)","######", "", 'F_', "", (1,399),'', '1 '),
("Float (signed)", "#{6}.#{9}", "", 'F-_R', "", '','', '000000.000000000'),
("Date (MDY) + Time", "##/##/#### ##:##:## AM", 'BCDEFGHIJKLMNOQRSTUVWXYZ','DF!',"", '','', wxDateTime_Now().Format("%m/%d/%Y %I:%M:%S %p")),
]
self.layoutGeneralTable( controls, grid )
self.sizer.Add( header, 0, flag=wxALIGN_LEFT|wxALL, border=5 )
self.sizer.Add( grid, 0, flag=wxALIGN_LEFT|wxALL, border=5 )
self.SetSizer( self.sizer )
self.SetAutoLayout( 1 )
self.SetupScrolling()
def onRequireValid( self, event ):
""" Set validRequired parameter on/off """
self.changeControlParams( event, "validRequired", True, False )
class demoPage3( wxScrolledPanel, demoMixin ):
def __init__( self, parent, log ):
self.log = log
wxScrolledPanel.__init__( self, parent, -1 )
self.sizer = wxBoxSizer( wxVERTICAL )
label = wxStaticText( self, -1, """\
All these controls have been created by passing a single parameter, the autoformat code.
The class contains an internal dictionary of types and formats (autoformats).
To see a great example of validations in action, try entering a bad email address,
then tab out.""")
label.SetForegroundColour( "Blue" )
self.sizer.Add( label, 0, wxALIGN_LEFT|wxALL, 5 )
description = wxStaticText( self, -1, "Description")
autofmt = wxStaticText( self, -1, "AutoFormat Code")
ctrl = wxStaticText( self, -1, "wxMaskedEdit Control")
description.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
autofmt.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
ctrl.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
grid = wxFlexGridSizer( 0, 3, vgap=10, hgap=5 )
grid.Add( description, 0, wxALIGN_LEFT )
grid.Add( autofmt, 0, wxALIGN_LEFT )
grid.Add( ctrl, 0, wxALIGN_LEFT )
controls = [
#description autoformat code
("Phone No w/opt. ext","USPHONEFULLEXT"),
("Phone No only", "USPHONEFULL"),
("US Date + Time","USDATETIMEMMDDYYYY/HHMMSS"),
("US Date + Time\n(without seconds)","USDATETIMEMMDDYYYY/HHMM"),
("US Date + Military Time","USDATEMILTIMEMMDDYYYY/HHMMSS"),
("US Date + Military Time\n(without seconds)","USDATEMILTIMEMMDDYYYY/HHMM"),
("US Date MMDDYYYY","USDATEMMDDYYYY/"),
("Time", "TIMEHHMMSS"),
("Time\n(without seconds)", "TIMEHHMM"),
("Military Time", "MILTIMEHHMMSS"),
("Military Time\n(without seconds)", "MILTIMEHHMM"),
("European Date", "EUDATEYYYYMMDD/"),
("Social Sec#","USSOCIALSEC"),
("Credit Card","CREDITCARD"),
("Expiration MM/YY","EXPDATEMMYY"),
("Percentage","PERCENT"),
("Person's Age","AGE"),
("US State", "USSTATE"),
("US Zip Code","USZIP"),
("US Zip+4","USZIPPLUS4"),
("Age", "AGE"),
("Email Address","EMAIL"),
]
for control in controls:
grid.Add( wxStaticText( self, -1, control[0]), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, control[1]), 0, wxALIGN_LEFT )
grid.Add( wxMaskedTextCtrl( self, -1, "",
autoformat = control[1],
demo = True,
name = control[1]),
0, wxALIGN_LEFT )
self.sizer.Add( grid, 0, wxALIGN_LEFT|wxALL, border=5 )
self.SetSizer( self.sizer )
self.SetAutoLayout( 1 )
self.SetupScrolling()
class demoPage4( wxScrolledPanel, demoMixin ):
def __init__( self, parent, log ):
self.log = log
wxScrolledPanel.__init__( self, parent, -1 )
self.sizer = wxBoxSizer( wxVERTICAL )
label = wxStaticText( self, -1, """\
These controls have field-specific choice lists and allow autocompletion.
Down arrow or Page Down in an uncompleted field with an auto-completable field will attempt
to auto-complete a field if it has a choice list.
Page Down and Shift-Down arrow will also auto-complete, or cycle through the complete list.
Page Up and Shift-Up arrow will similarly cycle backwards through the list.
""")
label.SetForegroundColour( "Blue" )
self.sizer.Add( label, 0, wxALIGN_LEFT|wxALL, 5 )
description = wxStaticText( self, -1, "Description" )
autofmt = wxStaticText( self, -1, "AutoFormat Code" )
fields = wxStaticText( self, -1, "Field Objects" )
ctrl = wxStaticText( self, -1, "wxMaskedEdit Control" )
description.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
autofmt.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
fields.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
ctrl.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
grid = wxFlexGridSizer( 0, 4, vgap=10, hgap=10 )
grid.Add( description, 0, wxALIGN_LEFT )
grid.Add( autofmt, 0, wxALIGN_LEFT )
grid.Add( fields, 0, wxALIGN_LEFT )
grid.Add( ctrl, 0, wxALIGN_LEFT )
autoformat = "USPHONEFULLEXT"
fieldsDict = {0: Field(choices=["617","781","508","978","413"], choiceRequired=True)}
fieldsLabel = """\
{0: Field(choices=[
"617","781",
"508","978","413"],
choiceRequired=True)}"""
grid.Add( wxStaticText( self, -1, "Restricted Area Code"), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, autoformat), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, fieldsLabel), 0, wxALIGN_LEFT )
grid.Add( wxMaskedTextCtrl( self, -1, "",
autoformat = autoformat,
fields = fieldsDict,
demo = True,
name = autoformat),
0, wxALIGN_LEFT )
autoformat = "EXPDATEMMYY"
fieldsDict = {1: Field(choices=["03", "04", "05"], choiceRequired=True)}
fieldsLabel = """\
{1: Field(choices=[
"03", "04", "05"],
choiceRequired=True)}"""
exp = wxMaskedTextCtrl( self, -1, "",
autoformat = autoformat,
fields = fieldsDict,
demo = True,
name = autoformat)
grid.Add( wxStaticText( self, -1, "Restricted Expiration"), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, autoformat), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, fieldsLabel), 0, wxALIGN_LEFT )
grid.Add( exp, 0, wxALIGN_LEFT )
fieldsDict = {0: Field(choices=["02134","02155"], choiceRequired=True),
1: Field(choices=["1234", "5678"], choiceRequired=False)}
fieldsLabel = """\
{0: Field(choices=["02134","02155"],
choiceRequired=True),
1: Field(choices=["1234", "5678"],
choiceRequired=False)}"""
autoformat = "USZIPPLUS4"
zip = wxMaskedTextCtrl( self, -1, "",
autoformat = autoformat,
fields = fieldsDict,
demo = True,
name = autoformat)
grid.Add( wxStaticText( self, -1, "Restricted Zip + 4"), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, autoformat), 0, wxALIGN_LEFT )
grid.Add( wxStaticText( self, -1, fieldsLabel), 0, wxALIGN_LEFT )
grid.Add( zip, 0, wxALIGN_LEFT )
self.sizer.Add( grid, 0, wxALIGN_LEFT|wxALL, border=5 )
self.SetSizer( self.sizer )
self.SetAutoLayout(1)
self.SetupScrolling()
class demoPage5( wxScrolledPanel, demoMixin ):
def __init__( self, parent, log ):
self.log = log
wxScrolledPanel.__init__( self, parent, -1 )
self.sizer = wxBoxSizer( wxVERTICAL )
label = wxStaticText( self, -1, """\
These are examples of wxMaskedComboBox and wxIpAddrCtrl, and a more
useful configuration of a wxMaskedTextCtrl for floating point input.
""")
label.SetForegroundColour( "Blue" )
self.sizer.Add( label, 0, wxALIGN_LEFT|wxALL, 5 )
numerators = [ str(i) for i in range(1, 4) ]
denominators = [ string.ljust(str(i), 2) for i in [2,3,4,5,8,16,32,64] ]
fieldsDict = {0: Field(choices=numerators, choiceRequired=False),
1: Field(choices=denominators, choiceRequired=True)}
choices = []
for n in numerators:
for d in denominators:
if n != d:
choices.append( '%s/%s' % (n,d) )
text1 = wxStaticText( self, -1, """\
A masked ComboBox for fraction selection.
Choices for each side of the fraction can be
selected with PageUp/Down:""")
fraction = wxMaskedComboBox( self, -1, "",
choices = choices,
choiceRequired = True,
mask = "#/##",
formatcodes = "F_",
validRegex = "^\d\/\d\d?",
fields = fieldsDict )
text2 = wxStaticText( self, -1, """
A masked ComboBox to validate
text from a list of numeric codes:""")
choices = ["91", "136", "305", "4579"]
code = wxMaskedComboBox( self, -1, choices[0],
choices = choices,
choiceRequired = True,
formatcodes = "F_r",
mask = "####")
text3 = wxStaticText( self, -1, """\
A masked state selector; only "legal" values
can be entered:""")
state = wxMaskedComboBox( self, -1, states[0],
choices = states,
autoformat="USSTATE")
text4 = wxStaticText( self, -1, "An empty IP Address entry control:")
ip_addr1 = wxIpAddrCtrl( self, -1, style = wxTE_PROCESS_TAB )
text5 = wxStaticText( self, -1, "An IP Address control with a restricted mask:")
ip_addr2 = wxIpAddrCtrl( self, -1, mask=" 10. 1.109.###" )
text6 = wxStaticText( self, -1, """\
An IP Address control with restricted choices
of form: 10. (1|2) . (129..255) . (0..255)""")
ip_addr3 = wxIpAddrCtrl( self, -1, mask=" 10. #.###.###")
ip_addr3.SetFieldParameters(0, validRegex="1|2" ) # requires entry to match or not allowed
# This allows any value in penultimate field, but colors anything outside of the range invalid:
ip_addr3.SetFieldParameters(1, validRange=(129,255), validRequired=False )
text7 = wxStaticText( self, -1, """\
A floating point entry control
with right-insert for ordinal:""")
floatctrl = wxMaskedTextCtrl(self, -1, mask="#{9}.#{2}", formatcodes="F_-R")
floatctrl.SetFieldParameters(0, formatcodes='r,<', validRequired=True) # right-insert, allow commas, require explicit cursor movement to change fields
floatctrl.SetFieldParameters(1, defaultValue='00') # don't allow blank fraction
grid = wxFlexGridSizer( 0, 2, vgap=20, hgap = 5 )
grid.Add( text1, 0, wxALIGN_LEFT )
grid.Add( fraction, 0, wxALIGN_LEFT )
grid.Add( text2, 0, wxALIGN_LEFT )
grid.Add( code, 0, wxALIGN_LEFT )
grid.Add( text3, 0, wxALIGN_LEFT )
grid.Add( state, 0, wxALIGN_LEFT )
grid.Add( text4, 0, wxALIGN_LEFT )
grid.Add( ip_addr1, 0, wxALIGN_LEFT )
grid.Add( text5, 0, wxALIGN_LEFT )
grid.Add( ip_addr2, 0, wxALIGN_LEFT )
grid.Add( text6, 0, wxALIGN_LEFT )
grid.Add( ip_addr3, 0, wxALIGN_LEFT )
grid.Add( text7, 0, wxALIGN_LEFT )
grid.Add( floatctrl, 0, wxALIGN_LEFT )
self.sizer.Add( grid, 0, wxALIGN_LEFT|wxALL, border=5 )
self.SetSizer( self.sizer )
self.SetAutoLayout(1)
self.SetupScrolling()
EVT_COMBOBOX( self, fraction.GetId(), self.OnComboChange )
EVT_COMBOBOX( self, code.GetId(), self.OnComboChange )
EVT_COMBOBOX( self, state.GetId(), self.OnComboChange )
EVT_TEXT( self, fraction.GetId(), self.OnComboChange )
EVT_TEXT( self, code.GetId(), self.OnComboChange )
EVT_TEXT( self, state.GetId(), self.OnComboChange )
EVT_TEXT( self, ip_addr1.GetId(), self.OnIpAddrChange )
EVT_TEXT( self, ip_addr2.GetId(), self.OnIpAddrChange )
EVT_TEXT( self, ip_addr3.GetId(), self.OnIpAddrChange )
EVT_TEXT( self, floatctrl.GetId(), self.OnTextChange )
def OnComboChange( self, event ):
ctl = self.FindWindowById( event.GetId() )
if not ctl.IsValid():
self.log.write('current value not a valid choice')
def OnIpAddrChange( self, event ):
ip_addr = self.FindWindowById( event.GetId() )
if ip_addr.IsValid():
self.log.write('new addr = %s\n' % ip_addr.GetAddress() )
def OnTextChange( self, event ):
ctl = self.FindWindowById( event.GetId() )
if ctl.IsValid():
self.log.write('new value = %s\n' % ctl.GetValue() )
# ---------------------------------------------------------------------
class TestMaskedTextCtrls(wxNotebook):
def __init__(self, parent, id, log):
wxNotebook.__init__(self, parent, id)
self.log = log
win = demoPage1(self, log)
self.AddPage(win, "General examples")
win = demoPage2(self, log)
self.AddPage(win, "Using default values")
win = demoPage3(self, log)
self.AddPage(win, 'Auto-formatted controls')
win = demoPage4(self, log)
self.AddPage(win, 'Using auto-complete fields')
win = demoPage5(self, log)
self.AddPage(win, 'Other masked controls')
#----------------------------------------------------------------------------
def runTest(frame, nb, log):
testWin = TestMaskedTextCtrls(nb, -1, log)
return testWin
def RunStandalone():
app = wxPySimpleApp()
frame = wxFrame(None, -1, "Test wxMaskedTextCtrl", size=(640, 480))
win = TestMaskedTextCtrls(frame, -1, sys.stdout)
frame.Show(True)
app.MainLoop()
#----------------------------------------------------------------------------
if __name__ == "__main__":
RunStandalone()
overview = """<html>
<PRE><FONT SIZE=-1>
""" + overviewdoc + """
</FONT></PRE>
"""
if __name__ == "__main__":
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])])

View File

@@ -1,68 +1,114 @@
from wxPython.wx import * from wxPython.wx import *
from wxPython.lib.timectrl import * from wxPython.lib.timectrl import *
from wxPython.lib.timectrl import __doc__ as overviewdoc
from wxPython.lib.scrolledpanel import wxScrolledPanel
#---------------------------------------------------------------------- #----------------------------------------------------------------------
class TestPanel( wxPanel ): class TestPanel( wxScrolledPanel ):
def __init__( self, parent, log ): def __init__( self, parent, log ):
wxPanel.__init__( self, parent, -1 ) wxScrolledPanel.__init__( self, parent, -1 )
self.log = log self.log = log
panel = wxPanel( self, -1 )
grid = wxFlexGridSizer( 0, 2, 20, 0 )
text1 = wxStaticText( panel, 10, "A 12-hour format wxTimeCtrl:") text1 = wxStaticText( self, -1, "12-hour format:")
self.time12 = wxTimeCtrl( panel, 20, name="12 hour control" ) self.time12 = wxTimeCtrl( self, -1, name="12 hour control" )
spin1 = wxSpinButton( panel, 30, wxDefaultPosition, wxSize(-1,20), 0 ) spin1 = wxSpinButton( self, -1, wxDefaultPosition, wxSize(-1,20), 0 )
self.time12.BindSpinButton( spin1 ) self.time12.BindSpinButton( spin1 )
grid.AddWindow( text1, 0, wxALIGN_RIGHT, 5 ) text2 = wxStaticText( self, -1, "24-hour format:")
spin2 = wxSpinButton( self, -1, wxDefaultPosition, wxSize(-1,20), 0 )
self.time24 = wxTimeCtrl( self, -1, name="24 hour control", fmt24hr=True, spinButton = spin2 )
text3 = wxStaticText( self, -1, "No seconds\nor spin button:")
self.spinless_ctrl = wxTimeCtrl( self, -1, name="spinless control", display_seconds = False )
grid = wxFlexGridSizer( 0, 2, 10, 5 )
grid.Add( text1, 0, wxALIGN_RIGHT )
hbox1 = wxBoxSizer( wxHORIZONTAL ) hbox1 = wxBoxSizer( wxHORIZONTAL )
hbox1.AddWindow( self.time12, 0, wxALIGN_CENTRE, 5 ) hbox1.Add( self.time12, 0, wxALIGN_CENTRE )
hbox1.AddWindow( spin1, 0, wxALIGN_CENTRE, 5 ) hbox1.Add( spin1, 0, wxALIGN_CENTRE )
grid.AddSizer( hbox1, 0, wxLEFT, 5 ) grid.Add( hbox1, 0, wxLEFT )
grid.Add( text2, 0, wxALIGN_RIGHT|wxTOP|wxBOTTOM )
text2 = wxStaticText( panel, 40, "A 24-hour format wxTimeCtrl:")
self.time24 = wxTimeCtrl( panel, 50, fmt24hr=True, name="24 hour control" )
spin2 = wxSpinButton( panel, 60, wxDefaultPosition, wxSize(-1,20), 0 )
self.time24.BindSpinButton( spin2 )
grid.AddWindow( text2, 0, wxALIGN_RIGHT|wxTOP|wxBOTTOM, 5 )
hbox2 = wxBoxSizer( wxHORIZONTAL ) hbox2 = wxBoxSizer( wxHORIZONTAL )
hbox2.AddWindow( self.time24, 0, wxALIGN_CENTRE, 5 ) hbox2.Add( self.time24, 0, wxALIGN_CENTRE )
hbox2.AddWindow( spin2, 0, wxALIGN_CENTRE, 5 ) hbox2.Add( spin2, 0, wxALIGN_CENTRE )
grid.AddSizer( hbox2, 0, wxLEFT, 5 ) grid.Add( hbox2, 0, wxLEFT )
grid.Add( text3, 0, wxALIGN_RIGHT|wxTOP|wxBOTTOM )
grid.Add( self.spinless_ctrl, 0, wxLEFT )
text3 = wxStaticText( panel, 70, "A wxTimeCtrl without a spin button:") buttonChange = wxButton( self, -1, "Change Controls")
self.spinless_ctrl = wxTimeCtrl( panel, 80, name="spinless control" ) self.radio12to24 = wxRadioButton( self, -1, "Copy 12-hour time to 24-hour control", wxDefaultPosition, wxDefaultSize, wxRB_GROUP )
self.radio24to12 = wxRadioButton( self, -1, "Copy 24-hour time to 12-hour control")
grid.AddWindow( text3, 0, wxALIGN_RIGHT|wxTOP|wxBOTTOM, 5 ) self.radioWx = wxRadioButton( self, -1, "Set controls to 'now' using wxDateTime")
grid.AddWindow( self.spinless_ctrl, 0, wxLEFT, 5 ) self.radioMx = wxRadioButton( self, -1, "Set controls to 'now' using mxDateTime")
buttonChange = wxButton( panel, 100, "Change Controls")
self.radio12to24 = wxRadioButton( panel, 110, "Copy 12-hour time to 24-hour control", wxDefaultPosition, wxDefaultSize, wxRB_GROUP )
self.radio24to12 = wxRadioButton( panel, 120, "Copy 24-hour time to 12-hour control")
self.radioWx = wxRadioButton( panel, 130, "Set controls to 'now' using wxDateTime")
self.radioMx = wxRadioButton( panel, 140, "Set controls to 'now' using mxDateTime")
radio_vbox = wxBoxSizer( wxVERTICAL ) radio_vbox = wxBoxSizer( wxVERTICAL )
radio_vbox.AddWindow( self.radio12to24, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ) radio_vbox.Add( self.radio12to24, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 )
radio_vbox.AddWindow( self.radio24to12, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ) radio_vbox.Add( self.radio24to12, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 )
radio_vbox.AddWindow( self.radioWx, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ) radio_vbox.Add( self.radioWx, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 )
radio_vbox.AddWindow( self.radioMx, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ) radio_vbox.Add( self.radioMx, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 )
box_label = wxStaticBox( panel, 90, "Change Controls through API" ) box_label = wxStaticBox( self, -1, "Change Controls through API" )
buttonbox = wxStaticBoxSizer( box_label, wxHORIZONTAL ) buttonbox = wxStaticBoxSizer( box_label, wxHORIZONTAL )
buttonbox.AddWindow( buttonChange, 0, wxALIGN_CENTRE|wxALL, 5 ) buttonbox.Add( buttonChange, 0, wxALIGN_CENTRE|wxALL, 5 )
buttonbox.AddSizer( radio_vbox, 0, wxALIGN_CENTRE|wxALL, 5 ) buttonbox.Add( radio_vbox, 0, wxALIGN_CENTRE|wxALL, 5 )
hbox = wxBoxSizer( wxHORIZONTAL )
hbox.Add( grid, 0, wxALIGN_LEFT|wxALL, 15 )
hbox.Add( buttonbox, 0, wxALIGN_RIGHT|wxBOTTOM, 20 )
box_label = wxStaticBox( self, -1, "Bounds Control" )
boundsbox = wxStaticBoxSizer( box_label, wxHORIZONTAL )
self.set_bounds = wxCheckBox( self, -1, "Set time bounds:" )
minlabel = wxStaticText( self, -1, "minimum time:" )
self.min = wxTimeCtrl( self, -1, name="min", display_seconds = False )
self.min.Enable( False )
maxlabel = wxStaticText( self, -1, "maximum time:" )
self.max = wxTimeCtrl( self, -1, name="max", display_seconds = False )
self.max.Enable( False )
self.limit_check = wxCheckBox( self, -1, "Limit control" )
label = wxStaticText( self, -1, "Resulting time control:" )
self.target_ctrl = wxTimeCtrl( self, -1, name="new" )
grid2 = wxFlexGridSizer( 0, 2, 0, 0 )
grid2.Add( 20, 0, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( 20, 0, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( self.set_bounds, 0, wxALIGN_LEFT|wxALL, 5 )
grid3 = wxFlexGridSizer( 0, 2, 5, 5 )
grid3.Add(minlabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL )
grid3.Add( self.min, 0, wxALIGN_LEFT )
grid3.Add(maxlabel, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL )
grid3.Add( self.max, 0, wxALIGN_LEFT )
grid2.Add(grid3, 0, wxALIGN_LEFT )
grid2.Add( self.limit_check, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( 20, 0, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( 20, 0, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( 20, 0, 0, wxALIGN_LEFT|wxALL, 5 )
grid2.Add( label, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
grid2.Add( self.target_ctrl, 0, wxALIGN_LEFT|wxALL, 5 )
boundsbox.Add(grid2, 0, wxALIGN_CENTER|wxEXPAND|wxALL, 5)
vbox = wxBoxSizer( wxVERTICAL )
vbox.AddSpacer(20, 20)
vbox.Add( hbox, 0, wxALIGN_LEFT|wxALL, 5)
vbox.Add( boundsbox, 0, wxALIGN_LEFT|wxALL, 5 )
outer_box = wxBoxSizer( wxVERTICAL ) outer_box = wxBoxSizer( wxVERTICAL )
outer_box.AddSizer( grid, 0, wxALIGN_CENTRE|wxBOTTOM, 20 ) outer_box.Add( vbox, 0, wxALIGN_LEFT|wxALL, 5)
outer_box.AddSizer( buttonbox, 0, wxALIGN_CENTRE|wxALL, 5 )
# Turn on mxDateTime option only if we can import the module: # Turn on mxDateTime option only if we can import the module:
@@ -72,23 +118,31 @@ class TestPanel( wxPanel ):
self.radioMx.Enable( False ) self.radioMx.Enable( False )
panel.SetAutoLayout( True ) self.SetAutoLayout( True )
panel.SetSizer( outer_box ) self.SetSizer( outer_box )
outer_box.Fit( panel ) outer_box.Fit( self )
panel.Move( (50,50) ) self.SetupScrolling()
self.panel = panel
EVT_BUTTON( self, buttonChange.GetId(), self.OnButtonClick )
EVT_TIMEUPDATE( self, self.time12.GetId(), self.OnTimeChange ) EVT_TIMEUPDATE( self, self.time12.GetId(), self.OnTimeChange )
EVT_TIMEUPDATE( self, self.time24.GetId(), self.OnTimeChange ) EVT_TIMEUPDATE( self, self.time24.GetId(), self.OnTimeChange )
EVT_TIMEUPDATE( self, self.spinless_ctrl.GetId(), self.OnTimeChange ) EVT_TIMEUPDATE( self, self.spinless_ctrl.GetId(), self.OnTimeChange )
EVT_BUTTON( self, buttonChange.GetId(), self.OnButtonClick )
EVT_CHECKBOX( self, self.set_bounds.GetId(), self.OnBoundsCheck )
EVT_CHECKBOX( self, self.limit_check.GetId(), self.SetTargetMinMax )
EVT_TIMEUPDATE( self, self.min.GetId(), self.SetTargetMinMax )
EVT_TIMEUPDATE( self, self.max.GetId(), self.SetTargetMinMax )
EVT_TIMEUPDATE( self, self.target_ctrl.GetId(), self.OnTimeChange )
def OnTimeChange( self, event ): def OnTimeChange( self, event ):
timectrl = self.panel.FindWindowById( event.GetId() ) timectrl = self.FindWindowById( event.GetId() )
self.log.write('%s time = %s\n' % ( timectrl.GetName(), timectrl.GetValue() ) ) ib_str = [ " (out of bounds)", "" ]
self.log.write('%s time = %s%s\n' % ( timectrl.GetName(), timectrl.GetValue(), ib_str[ timectrl.IsInBounds() ] ) )
def OnButtonClick( self, event ): def OnButtonClick( self, event ):
if self.radio12to24.GetValue(): if self.radio12to24.GetValue():
@@ -99,16 +153,53 @@ class TestPanel( wxPanel ):
elif self.radioWx.GetValue(): elif self.radioWx.GetValue():
now = wxDateTime_Now() now = wxDateTime_Now()
self.time12.SetWxDateTime( now ) self.time12.SetValue( now )
self.time24.SetWxDateTime( now ) # (demonstrates that G/SetValue returns/takes a wxDateTime)
self.spinless_ctrl.SetWxDateTime( now ) self.time24.SetValue( self.time12.GetValue(as_wxDateTime=True) )
# (demonstrates that G/SetValue returns/takes a wxTimeSpan)
self.spinless_ctrl.SetValue( self.time12.GetValue(as_wxTimeSpan=True) )
elif self.radioMx.GetValue(): elif self.radioMx.GetValue():
from mx import DateTime from mx import DateTime
now = DateTime.now() now = DateTime.now()
self.time12.SetMxDateTime( now ) self.time12.SetValue( now )
self.time24.SetMxDateTime( now )
self.spinless_ctrl.SetMxDateTime( now ) # (demonstrates that G/SetValue returns/takes a DateTime)
self.time24.SetValue( self.time12.GetValue(as_mxDateTime=True) )
# (demonstrates that G/SetValue returns/takes a DateTimeDelta)
self.spinless_ctrl.SetValue( self.time12.GetValue(as_mxDateTimeDelta=True) )
def OnBoundsCheck( self, event ):
self.min.Enable( self.set_bounds.GetValue() )
self.max.Enable( self.set_bounds.GetValue() )
self.SetTargetMinMax()
def SetTargetMinMax( self, event=None ):
min = max = None
if self.set_bounds.GetValue():
min = self.min.GetWxDateTime()
max = self.max.GetWxDateTime()
else:
min, max = None, None
cur_min, cur_max = self.target_ctrl.GetBounds()
if min != cur_min: self.target_ctrl.SetMin( min )
if max != cur_max: self.target_ctrl.SetMax( max )
self.target_ctrl.SetLimited( self.limit_check.GetValue() )
if min != cur_min or max != cur_max:
new_min, new_max = self.target_ctrl.GetBounds()
if new_min and new_max:
self.log.write( "current min, max: (%s, %s)\n" % ( new_min.FormatTime(), new_max.FormatTime() ) )
else:
self.log.write( "current min, max: (None, None)\n" )
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@@ -118,93 +209,7 @@ def runTest( frame, nb, log ):
#---------------------------------------------------------------------- #----------------------------------------------------------------------
overview = """<html><body> overview = overviewdoc
<P>
<B>wxTimeCtrl</B> provides a multi-cell control that allows manipulation of a time
value. It supports 12 or 24 hour format, and you can use wxDateTime or mxDateTime
to get/set values from the control.
<P>
Left/right/tab keys to switch cells within a wxTimeCtrl, and the up/down arrows act
like a spin control. wxTimeCtrl also allows for an actual spin button to be attached
to the control, so that it acts like the up/down arrow keys.
<P>
The <B>!</B> or <B>c</B> key sets the value of the control to <B><I>now.</I></B>
<P>
Here's the API for wxTimeCtrl:
<DL><PRE>
<B>wxTimeCtrl</B>(
parent, id = -1,
<B>value</B> = '12:00:00 AM',
pos = wxDefaultPosition,
size = wxDefaultSize,
<B>fmt24hr</B> = False,
<B>spinButton</B> = None,
<B>style</B> = wxTE_PROCESS_TAB,
name = "time")
</PRE>
<UL>
<DT><B>value</B>
<DD>If no initial value is set, the default will be midnight; if an illegal string
is specified, a ValueError will result. (You can always later set the initial time
with SetValue() after instantiation of the control.)
<DL><B>size</B>
<DD>The size of the control will be automatically adjusted for 12/24 hour format
if wxDefaultSize is specified.
<BR>
<DT><B>fmt24hr</B>
<DD>If True, control will display time in 24 hour time format; if False, it will
use 12 hour AM/PM format. SetValue() will adjust values accordingly for the
control, based on the format specified.
<BR>
<DT><B>spinButton</B>
<DD>If specified, this button's events will be bound to the behavior of the
wxTimeCtrl, working like up/down cursor key events. (See BindSpinButton.)
<BR>
<DT><B>style</B>
<DD>By default, wxTimeCtrl will process TAB events, by allowing tab to the
different cells within the control.
</DL>
</UL>
<BR>
<BR>
<DT><B>SetValue(time_string)</B>
<DD>Sets the value of the control to a particular time, given a valid time string;
raises ValueError on invalid value
<BR>
<DT><B>GetValue()</B>
<DD>Retrieves the string value of the time from the control
<BR>
<DT><B>SetWxDateTime(wxDateTime)</B>
<DD>Uses the time portion of a wxDateTime to construct a value for the control.
<BR>
<DT><B>GetWxDateTime()</B>
<DD>Retrieves the value of the control, and applies it to the wxDateTimeFromHMS()
constructor, and returns the resulting value. (This returns the date portion as
"today".)
<BR>
<DT><B>SetMxDateTime(mxDateTime)</B>
<DD>Uses the time portion of an mxDateTime to construct a value for the control.
<EM>NOTE:</EM> This imports mx.DateTime at runtime only if this or the Get function
is called.
<BR>
<DT><B>GetMxDateTime()</B>
<DD>Retrieves the value of the control and applies it to the DateTime.Time()
constructor, and returns the resulting value. (mxDateTime is smart enough to
know this is just a time value.)
<BR>
<DT><B>BindSpinButton(wxSpinBtton)</B>
<DD>Binds an externally created spin button to the control, so that up/down spin
events change the active cell or selection in the control (in addition to the
up/down cursor keys.) (This is primarily to allow you to create a "standard"
interface to time controls, as seen in Windows.)
<BR>
<DT><B>EVT_TIMEUPDATE(win, id, func)</B>
<DD>func is fired whenever the value of the control changes.
</DL>
</body></html>
"""
if __name__ == '__main__': if __name__ == '__main__':
import sys,os import sys,os

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff