Patches from Will Sadkin:

MaskedEditMixin:
- fixed size calculations on changing fonts
- fixed tabbing logic now that tab events are entered into the control
  by default (ie event.Skip()) if wx.TE_PROCESS_TAB is set
- fixed code attempting to fix the selection after focus events
  generated on control destruction, to prevent tracebacks

TextCtrl, ComboBox
- Added support for XRC
- Fixed sizing calculation code
- Added SetFont() override method that will recalculate the size if this
  is called.
- Added AppendItems() for ComboBox

NumCtrl:
- prevented ctrl from accepting same grouping and decimal character,
- fixed issue preventing paste from working if decimal char was different
  than '.'

TimeCtrl:
- Fixed default value to use 24hour time (which will be converted
  appropriately if format supports it, and added code to check if
  local timezone uses "AM/PM" for this concept; if not, control now
  defaults to 24hour format, and disallows the am/pm form.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28400 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn 2004-07-22 18:38:34 +00:00
parent b591b7cf2b
commit 339983ff62
6 changed files with 257 additions and 55 deletions

View File

@ -12,8 +12,8 @@
# import relevant external symbols into package namespace:
from maskededit import *
from textctrl import BaseMaskedTextCtrl, TextCtrl
from combobox import BaseMaskedComboBox, ComboBox, MaskedComboBoxSelectEvent
from textctrl import BaseMaskedTextCtrl, PreMaskedTextCtrl, TextCtrl
from combobox import BaseMaskedComboBox, PreMaskedComboBox, ComboBox, MaskedComboBoxSelectEvent
from numctrl import NumCtrl, wxEVT_COMMAND_MASKED_NUMBER_UPDATED, EVT_NUM, NumberUpdatedEvent
from timectrl import TimeCtrl, wxEVT_TIMEVAL_UPDATED, EVT_TIMEUPDATE, TimeUpdatedEvent
from ipaddrctrl import IpAddrCtrl

View File

@ -54,11 +54,6 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
**kwargs):
# This is necessary, because wxComboBox currently provides no
# method for determining later if this was specified in the
# constructor for the control...
self.__readonly = style & wx.CB_READONLY == wx.CB_READONLY
kwargs['choices'] = choices ## set up maskededit to work with choice list too
## Since combobox completion is case-insensitive, always validate same way
@ -80,15 +75,56 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
choices=choices, style=style|wx.WANTS_CHARS,
validator=validator,
name=name)
self.controlInitialized = True
self._PostInit(style=style, setupEventHandling=setupEventHandling,
name=name, value=value, **kwargs)
def _PostInit(self, style=wx.CB_DROPDOWN,
setupEventHandling = True, ## setup event handling by default):
name = "maskedComboBox", value='', **kwargs):
# This is necessary, because wxComboBox currently provides no
# method for determining later if this was specified in the
# constructor for the control...
self.__readonly = style & wx.CB_READONLY == wx.CB_READONLY
if not hasattr(self, 'controlInitialized'):
self.controlInitialized = True ## must have been called via XRC, therefore base class is constructed
if not kwargs.has_key('choices'):
choices=[]
kwargs['choices'] = choices ## set up maskededit to work with choice list too
self._choices = []
## Since combobox completion is case-insensitive, always validate same way
if not kwargs.has_key('compareNoCase'):
kwargs['compareNoCase'] = True
MaskedEditMixin.__init__( self, name, **kwargs )
self._choices = self._ctrl_constraints._choices
## dbg('self._choices:', self._choices)
if self._ctrl_constraints._alignRight:
choices = [choice.rjust(self._masklength) for choice in choices]
else:
choices = [choice.ljust(self._masklength) for choice in choices]
wx.ComboBox.Clear(self)
wx.ComboBox.AppendItems(self, choices)
# Set control font - fixed width by default
self._setFont()
if self._autofit:
self.SetClientSize(self._CalcSize())
self.SetSizeHints(self.GetSize())
width = self.GetSize().width
height = self.GetBestSize().height
self.SetSize((width, height))
self.SetSizeHints((width, height))
if value:
# ensure value is width of the mask of the control:
@ -134,6 +170,19 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
return (size[0]+20, size[1])
def SetFont(self, *args, **kwargs):
""" Set the font, then recalculate control size, if appropriate. """
wx.ComboBox.SetFont(self, *args, **kwargs)
if self._autofit:
dbg('calculated size:', self._CalcSize())
self.SetClientSize(self._CalcSize())
width = self.GetSize().width
height = self.GetBestSize().height
dbg('setting client size to:', (width, height))
self.SetSize((width, height))
self.SetSizeHints((width, height))
def _GetSelection(self):
"""
Allow mixin to get the text selection of this control.
@ -306,7 +355,6 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
else:
wx.ComboBox.Undo() # else revert to base control behavior
def Append( self, choice, clientData=None ):
"""
This function override is necessary so we can keep track of any additions to the list
@ -352,6 +400,13 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
wx.ComboBox.Append(self, choice, clientData)
def AppendItems( self, choices ):
"""
AppendItems() is handled in terms of Append, to avoid code replication.
"""
for choice in choices:
self.Append(choice)
def Clear( self ):
"""
@ -544,3 +599,30 @@ class ComboBox( BaseMaskedComboBox, MaskedEditAccessorsMixin ):
pass
class PreMaskedComboBox( BaseMaskedComboBox, MaskedEditAccessorsMixin ):
"""
This allows us to use XRC subclassing.
"""
# This should really be wx.EVT_WINDOW_CREATE but it is not
# currently delivered for native controls on all platforms, so
# we'll use EVT_SIZE instead. It should happen shortly after the
# control is created as the control is set to its "best" size.
_firstEventType = wx.EVT_SIZE
def __init__(self):
pre = wx.PreComboBox()
self.PostCreate(pre)
self.Bind(self._firstEventType, self.OnCreate)
def OnCreate(self, evt):
self.Unbind(self._firstEventType)
self._PostInit()
i=0
## CHANGELOG:
## ====================
## Version 1.1
## 1. Added .SetFont() method that properly resizes control
## 2. Modified control to support construction via XRC mechanism.
## 3. Added AppendItems() to conform with latest combobox.

View File

@ -757,7 +757,7 @@ import wx
from wx.tools.dbg import Logger
dbg = Logger()
##dbg(enable=0)
##dbg(enable=1)
## ---------- ---------- ---------- ---------- ---------- ---------- ----------
@ -1914,9 +1914,13 @@ class MaskedEditMixin:
self._prevValue = newvalue # disallow undo of sign type
if self._autofit:
## dbg('setting client size to:', self._CalcSize())
## dbg('calculated size:', self._CalcSize())
self.SetClientSize(self._CalcSize())
self.SetSizeHints(self.GetSize())
width = self.GetSize().width
height = self.GetBestSize().height
## dbg('setting client size to:', (width, height))
self.SetSize((width, height))
self.SetSizeHints((width, height))
# Set value/type-specific formatting
self._applyFormatting()
@ -1991,8 +1995,24 @@ class MaskedEditMixin:
self._SetInitialValue()
if self._autofit:
# this is tricky, because, as Robin explains:
# "Basically there are two sizes to deal with, that are potentially
# different. The client size is the inside size and may, depending
# on platform, exclude the borders and such. The normal size is
# the outside size that does include the borders. What you are
# calculating (in _CalcSize) is the client size, but the sizers
# deal with the full size and so that is the minimum size that
# we need to set with SetSizeHints. The root of the problem is
# that in _calcSize the current client size height is returned,
# instead of a height based on the current font. So I suggest using
# _calcSize to just get the width, and then use GetBestSize to
# get the height."
self.SetClientSize(self._CalcSize())
self.SetSizeHints(self.GetSize())
width = self.GetSize().width
height = self.GetBestSize().height
self.SetSize((width, height))
self.SetSizeHints((width, height))
# Set value/type-specific formatting
self._applyFormatting()
@ -2642,7 +2662,7 @@ class MaskedEditMixin:
sizing_text += 'M'
#### dbg('len(sizing_text):', len(sizing_text), 'sizing_text: "%s"' % sizing_text)
w, h = self.GetTextExtent(sizing_text)
size = (w+4, self.GetClientSize().height)
size = (w+4, self.GetSize().height)
#### dbg('size:', size, indent=0)
return size
@ -2690,7 +2710,7 @@ class MaskedEditMixin:
## dbg('ignoring bogus text change event', indent=0)
pass
else:
## dbg('curvalue: "%s", newvalue: "%s"' % (self._curValue, newvalue))
## dbg('curvalue: "%s", newvalue: "%s", len(newvalue): %d' % (self._curValue, newvalue, len(newvalue)))
if self._Change():
if self._signOk and self._isNeg and newvalue.find('-') == -1 and newvalue.find('(') == -1:
## dbg('clearing self._isNeg')
@ -2864,6 +2884,8 @@ class MaskedEditMixin:
if newfield != field and newfield._selectOnFieldEntry:
## dbg('queuing selection: (%d, %d)' % (newfield._extent[0], newfield._extent[1]))
wx.CallAfter(self._SetSelection, newfield._extent[0], newfield._extent[1])
else:
wx.CallAfter(self._SetSelection, newpos, new_select_to)
keep_processing = False
elif keep_processing:
@ -3400,12 +3422,12 @@ class MaskedEditMixin:
def _OnReturn(self, event):
"""
Changes the event to look like a tab event, so we can then call
event.Skip() on it, and have the parent form "do the right thing."
Swallows the return, issues a Navigate event instead, since
masked controls are "single line" by defn.
"""
## dbg('MaskedEditMixin::OnReturn')
event.m_keyCode = wx.WXK_TAB
event.Skip()
self.Navigate(True)
return False
def _OnHome(self,event):
@ -3486,9 +3508,6 @@ class MaskedEditMixin:
"""
Primarily handles TAB events, but can be used for any key that
designer wants to change fields within a masked edit control.
NOTE: at the moment, although coded to handle shift-TAB and
control-shift-TAB, these events are not sent to the controls
by the framework.
"""
## dbg('MaskedEditMixin::_OnChangeField', indent = 1)
# determine end of current field:
@ -3500,7 +3519,10 @@ class MaskedEditMixin:
self._AdjustField(pos)
if event.GetKeyCode() == wx.WXK_TAB:
## dbg('tab to next ctrl')
event.Skip()
# As of 2.5.2, you don't call event.Skip() to do
# this, but instead force explicit navigation, if
# wx.TE_PROCESS_TAB is used (like in the masked edits)
self.Navigate(True)
#else: do nothing
## dbg(indent=0)
return False
@ -3534,7 +3556,10 @@ class MaskedEditMixin:
self._AdjustField(pos)
if event.GetKeyCode() == wx.WXK_TAB:
## dbg('tab to previous ctrl')
event.Skip()
# As of 2.5.2, you don't call event.Skip() to do
# this, but instead force explicit navigation, if
# wx.TE_PROCESS_TAB is used (like in the masked edits)
self.Navigate(False)
else:
## dbg('position at beginning')
wx.CallAfter(self._SetInsertionPoint, field_start)
@ -3580,7 +3605,10 @@ class MaskedEditMixin:
self._AdjustField(pos)
if event.GetKeyCode() == wx.WXK_TAB:
## dbg('tab to next ctrl')
event.Skip()
# As of 2.5.2, you don't call event.Skip() to do
# this, but instead force explicit navigation, if
# wx.TE_PROCESS_TAB is used (like in the masked edits)
self.Navigate(True)
else:
## dbg('position at end')
wx.CallAfter(self._SetInsertionPoint, field_end)
@ -3594,7 +3622,10 @@ class MaskedEditMixin:
self._AdjustField(pos)
if event.GetKeyCode() == wx.WXK_TAB:
## dbg('tab to next ctrl')
event.Skip()
# As of 2.5.2, you don't call event.Skip() to do
# this, but instead force explicit navigation, if
# wx.TE_PROCESS_TAB is used (like in the masked edits)
self.Navigate(True)
#else: do nothing
## dbg(indent=0)
return False
@ -3640,6 +3671,8 @@ class MaskedEditMixin:
if fraction._selectOnFieldEntry:
## dbg('queuing selection after decimal point to:', (start, end))
wx.CallAfter(self._SetSelection, start, end)
else:
wx.CallAfter(self._SetSelection, start, start)
keep_processing = False
if self._isInt: ## handle integer value, truncate from current position
@ -3654,6 +3687,7 @@ class MaskedEditMixin:
if newstr.find(')') != -1:
newpos -= 1 # (don't move past right paren)
wx.CallAfter(self._SetInsertionPoint, newpos)
wx.CallAfter(self._SetSelection, newpos, newpos)
keep_processing = False
## dbg(indent=0)
@ -3949,6 +3983,7 @@ class MaskedEditMixin:
pos = pos+2
if newvalue != value:
## dbg('old value: "%s"\nnew value: "%s"' % (value, newvalue))
self._SetValue(newvalue)
self._SetInsertionPoint(pos)
@ -4042,6 +4077,8 @@ class MaskedEditMixin:
self._SetInsertionPoint(pos)
if pos < sel_to: # restore selection
self._SetSelection(pos, sel_to)
else:
self._SetSelection(pos, pos)
## dbg('adjusted pos:', pos, indent=0)
return pos
@ -5182,7 +5219,10 @@ class MaskedEditMixin:
the control, and deselect.
"""
## dbg('MaskedEditMixin::_fixSelection', indent=1)
if not self._mask or not self._IsEditable():
# can get here if called with wx.CallAfter after underlying
# control has been destroyed on close, but after focus
# events
if not self or not self._mask or not self._IsEditable():
## dbg(indent=0)
return
@ -6396,6 +6436,8 @@ i=1
## chars properly.)
## 4. Fixed autoselect behavior to work similarly to (2) above, so that combobox
## selection will only select the non-empty text, as per request.
## 5. Fixed tabbing to work with 2.5.2 semantics.
## 6. Fixed size calculation to handle changing fonts
##
## Version 1.6
## 1. Reorganized masked controls into separate package, renamed things accordingly

View File

@ -386,7 +386,7 @@ MININT = -maxint-1
from wx.tools.dbg import Logger
from wx.lib.masked import MaskedEditMixin, Field, BaseMaskedTextCtrl
dbg = Logger()
##dbg(enable=0)
##dbg(enable=1)
#----------------------------------------------------------------------------
@ -654,14 +654,26 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
maskededit_kwargs['mask'] = intmask+fracmask
if kwargs.has_key('groupChar'):
if kwargs.has_key('groupChar') or kwargs.has_key('decimalChar'):
old_groupchar = self._groupChar # save so we can reformat properly
## dbg("old_groupchar: '%s'" % old_groupchar)
maskededit_kwargs['groupChar'] = kwargs['groupChar']
if kwargs.has_key('decimalChar'):
old_decimalchar = self._decimalChar
## dbg("old_groupchar: '%s'" % old_groupchar)
## dbg("old_decimalchar: '%s'" % old_decimalchar)
maskededit_kwargs['decimalChar'] = kwargs['decimalChar']
groupchar = old_groupchar
decimalchar = old_decimalchar
if kwargs.has_key('groupChar'):
maskededit_kwargs['groupChar'] = kwargs['groupChar']
groupchar = kwargs['groupChar']
if kwargs.has_key('decimalChar'):
maskededit_kwargs['decimalChar'] = kwargs['decimalChar']
decimalchar = kwargs['decimalChar']
# Add sanity check to make sure these are distinct, and if not,
# raise attribute error
if groupchar == decimalchar:
raise AttributeError('groupChar and decimalChar must be distinct')
# for all other parameters, assign keyword args as appropriate:
for key, param_value in kwargs.items():
@ -1089,9 +1101,8 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
and value[sel_start:sel_to] == self._groupChar ):
self.SetInsertionPoint(sel_start)
self.SetSelection(sel_start, sel_to+1)
return BaseMaskedTextCtrl._OnErase(self, event, just_return_value)
## dbg(indent=0)
return BaseMaskedTextCtrl._OnErase(self, event, just_return_value)
def OnTextChange( self, event ):
@ -1146,7 +1157,9 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
A ValueError exception will be raised if an invalid value
is specified.
"""
## dbg('NumCtrl::SetValue(%s)' % value, indent=1)
BaseMaskedTextCtrl.SetValue( self, self._toGUI(value) )
## dbg(indent=0)
def SetIntegerWidth(self, value):
@ -1519,7 +1532,7 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
Preprocessor for base control paste; if value needs to be right-justified
to fit in control, do so prior to paste:
"""
## dbg('NumCtrl::_Paste (value = "%s")' % value)
## dbg('NumCtrl::_Paste (value = "%s")' % value, indent=1)
if value is None:
paste_text = self._getClipboardContents()
else:
@ -1533,7 +1546,7 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
#
field = self._FindField(sel_start)
edit_start, edit_end = field._extent
paste_text = paste_text.replace(self._groupChar, '').replace(self._decimalChar, '.').replace('(', '-').replace(')','')
paste_text = paste_text.replace(self._groupChar, '').replace('(', '-').replace(')','')
if field._insertRight and self._groupDigits:
# want to paste to the left; see if it will fit:
left_text = old_value[edit_start:sel_start].lstrip()
@ -1547,8 +1560,8 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
sel_start += sel_to - orig_sel_start # decrease by amount selected
else:
## dbg("won't fit left;", 'paste text remains: "%s"' % paste_text)
## dbg('adjusted start before accounting for grouping:', sel_start)
## dbg('adjusted paste_text before accounting for grouping: "%s"' % paste_text)
## dbg('adjusted start before accounting for grouping:', sel_start)
## dbg('adjusted paste_text before accounting for grouping: "%s"' % paste_text)
pass
if self._groupDigits and sel_start != orig_sel_start:
left_len = len(old_value[:sel_to].lstrip())
@ -1564,12 +1577,6 @@ class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin):
self.SetInsertionPoint(sel_to)
self.SetSelection(sel_start, sel_to)
## # treat paste as "replace number", if appropriate:
## sel_start, sel_to = self._GetSelection()
## if sel_start == sel_to or self._selectOnEntry and (sel_start, sel_to) == self._fields[0]._extent:
## paste_text = self._toGUI(paste_text)
## self._SetSelection(0, len(self._mask))
new_text, replace_to = MaskedEditMixin._Paste(self,
paste_text,
raise_on_invalid=raise_on_invalid,

View File

@ -22,7 +22,7 @@ from wx.lib.masked import *
# be a good place to implement the 2.3 logger class
from wx.tools.dbg import Logger
dbg = Logger()
##dbg(enable=0)
##dbg(enable=1)
# ## TRICKY BIT: to avoid a ton of boiler-plate, and to
# ## automate the getter/setter generation for each valid
@ -76,6 +76,13 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
style=style, validator=validator,
name=name)
self._PostInit(setupEventHandling = setupEventHandling,
name=name, value=value,**kwargs )
def _PostInit(self,setupEventHandling=True,
name='maskedTextCtrl' , value='', **kwargs):
self.controlInitialized = True
MaskedEditMixin.__init__( self, name, **kwargs )
@ -219,6 +226,18 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
wx.CallAfter(self._SetSelection, replace_to, replace_to)
## dbg(indent=0)
def SetFont(self, *args, **kwargs):
""" Set the font, then recalculate control size, if appropriate. """
wx.TextCtrl.SetFont(self, *args, **kwargs)
if self._autofit:
## dbg('calculated size:', self._CalcSize())
self.SetClientSize(self._CalcSize())
width = self.GetSize().width
height = self.GetBestSize().height
## dbg('setting client size to:', (width, height))
self.SetSize((width, height))
self.SetSizeHints((width, height))
def Clear(self):
""" Blanks the current control value by replacing it with the default value."""
@ -324,3 +343,29 @@ class TextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
pass
class PreMaskedTextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
"""
This allows us to use XRC subclassing.
"""
# This should really be wx.EVT_WINDOW_CREATE but it is not
# currently delivered for native controls on all platforms, so
# we'll use EVT_SIZE instead. It should happen shortly after the
# control is created as the control is set to its "best" size.
_firstEventType = wx.EVT_SIZE
def __init__(self):
pre = wx.PreTextCtrl()
self.PostCreate(pre)
self.Bind(self._firstEventType, self.OnCreate)
def OnCreate(self, evt):
self.Unbind(self._firstEventType)
self._PostInit()
i=0
## CHANGELOG:
## ====================
## Version 1.1
## 1. Added .SetFont() method that properly resizes control
## 2. Modified control to support construction via XRC mechanism.

View File

@ -59,7 +59,7 @@ Here's the API for TimeCtrl:
<DL><PRE>
<B>TimeCtrl</B>(
parent, id = -1,
<B>value</B> = '12:00:00 AM',
<B>value</B> = '00:00:00',
pos = wx.DefaultPosition,
size = wx.DefaultSize,
<B>style</B> = wxTE_PROCESS_TAB,
@ -82,7 +82,10 @@ Here's the API for TimeCtrl:
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 wx.DefaultSize is specified.
if wx.DefaultSize is specified. NOTE: due to a problem with wx.DateTime, if the
locale does not use 'AM/PM' for its values, the default format will automatically
change to 24 hour format, and an AttributeError will be thrown if a non-24 format
is specified.
<DT><B>style</B>
<DD>By default, TimeCtrl will process TAB events, by allowing tab to the
different cells within the control.
@ -95,7 +98,7 @@ Here's the API for TimeCtrl:
<DD>This parameter can be used instead of the fmt24hr and displaySeconds
parameters, respectively; it provides a shorthand way to specify the time
format you want. Accepted values are 'HHMMSS', 'HHMM', '24HHMMSS', and
'24HHMM'. If the format is specified, the other two arguments will be ignored.
'24HHMM'. If the format is specified, the other two arguments will be ignored.
<BR>
<DT><B>fmt24hr</B>
<DD>If True, control will display time in 24 hour time format; if False, it will
@ -337,7 +340,7 @@ class TimeCtrl(BaseMaskedTextCtrl):
}
def __init__ (
self, parent, id=-1, value = '12:00:00 AM',
self, parent, id=-1, value = '00:00:00',
pos = wx.DefaultPosition, size = wx.DefaultSize,
fmt24hr=False,
spinButton = None,
@ -348,6 +351,15 @@ class TimeCtrl(BaseMaskedTextCtrl):
# set defaults for control:
## dbg('setting defaults:')
self.__fmt24hr = False
wxdt = wx.DateTimeFromDMY(1, 0, 1970)
if wxdt.Format('%p') != 'AM':
TimeCtrl.valid_ctrl_params['format'] = '24HHMMSS'
self.__fmt24hr = True
fmt24hr = True # force/change default positional argument
# (will countermand explicit set to False too.)
for key, param_value in TimeCtrl.valid_ctrl_params.items():
# This is done this way to make setattr behave consistently with
# "private attribute" name mangling
@ -367,7 +379,6 @@ class TimeCtrl(BaseMaskedTextCtrl):
kwargs['displaySeconds'] = True
# (handle positional arg (from original release) differently from rest of kwargs:)
self.__fmt24hr = False
if not kwargs.has_key('format'):
if fmt24hr:
if kwargs.has_key('displaySeconds') and kwargs['displaySeconds']:
@ -449,7 +460,7 @@ class TimeCtrl(BaseMaskedTextCtrl):
self.SetLimited(limited)
self.SetValue(value)
except:
self.SetValue('12:00:00 AM')
self.SetValue('00:00:00')
if spinButton:
self.BindSpinButton(spinButton) # bind spin button up/down events to this control
@ -472,6 +483,12 @@ class TimeCtrl(BaseMaskedTextCtrl):
raise AttributeError('invalid keyword argument "%s"' % key)
if key == 'format':
wxdt = wx.DateTimeFromDMY(1, 0, 1970)
if wxdt.Format('%p') != 'AM':
require24hr = True
else:
require24hr = False
# handle both local or generic 'maskededit' autoformat codes:
if param_value == 'HHMMSS' or param_value == 'TIMEHHMMSS':
self.__displaySeconds = True
@ -487,6 +504,10 @@ class TimeCtrl(BaseMaskedTextCtrl):
self.__fmt24hr = True
else:
raise AttributeError('"%s" is not a valid format' % param_value)
if require24hr and not self.__fmt24hr:
raise AttributeError('"%s" is an unsupported time format for the current locale' % param_value)
reset_format = True
elif key in ("displaySeconds", "display_seconds") and not kwargs.has_key('format'):
@ -552,7 +573,7 @@ class TimeCtrl(BaseMaskedTextCtrl):
self.SetLimited(limited)
self.SetValue(value)
except:
self.SetValue('12:00:00 AM')
self.SetValue('00:00:00')
## dbg(indent=0)
return {} # no arguments to return
else:
@ -663,8 +684,13 @@ class TimeCtrl(BaseMaskedTextCtrl):
## dbg('checkTime == len(value)?', valid)
if not valid:
# deal with bug/deficiency in wx.DateTime:
if wxdt.Format('%p') not in ('AM', 'PM') and checkTime in (5,8):
# couldn't parse the AM/PM field
raise ValueError('cannot convert string "%s" to valid time for the current locale; please use 24hr time instead' % value)
else:
## dbg(indent=0, suspend=0)
raise ValueError('cannot convert string "%s" to valid time' % value)
raise ValueError('cannot convert string "%s" to valid time' % value)
else:
if isinstance(value, wx.DateTime):