📄 timectrl.py
字号:
'limited': False, # by default, no limiting even if bounds set
'useFixedWidthFont': True, # by default, use a fixed-width font
'oob_color': "Yellow" # by default, the default masked.TextCtrl "invalid" color
}
def __init__ (
self, parent, id=-1, value = '00:00:00',
pos = wx.DefaultPosition, size = wx.DefaultSize,
fmt24hr=False,
spinButton = None,
style = wx.TE_PROCESS_TAB,
validator = wx.DefaultValidator,
name = "time",
**kwargs ):
# set defaults for control:
## dbg('setting defaults:')
self.__fmt24hr = False
wxdt = wx.DateTimeFromDMY(1, 0, 1970)
try:
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.)
except:
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
setattr(self, "_TimeCtrl__" + key, copy.copy(param_value))
# create locals from current defaults, so we can override if
# specified in kwargs, and handle uniformly:
min = self.__min
max = self.__max
limited = self.__limited
self.__posCurrent = 0
# handle deprecated keword argument name:
if kwargs.has_key('display_seconds'):
kwargs['displaySeconds'] = kwargs['display_seconds']
del kwargs['display_seconds']
if not kwargs.has_key('displaySeconds'):
kwargs['displaySeconds'] = True
# (handle positional arg (from original release) differently from rest of kwargs:)
if not kwargs.has_key('format'):
if fmt24hr:
if kwargs.has_key('displaySeconds') and kwargs['displaySeconds']:
kwargs['format'] = '24HHMMSS'
del kwargs['displaySeconds']
else:
kwargs['format'] = '24HHMM'
else:
if kwargs.has_key('displaySeconds') and kwargs['displaySeconds']:
kwargs['format'] = 'HHMMSS'
del kwargs['displaySeconds']
else:
kwargs['format'] = 'HHMM'
if not kwargs.has_key('useFixedWidthFont'):
# allow control over font selection:
kwargs['useFixedWidthFont'] = self.__useFixedWidthFont
maskededit_kwargs = self.SetParameters(**kwargs)
# allow for explicit size specification:
if size != wx.DefaultSize:
# override (and remove) "autofit" autoformat code in standard time formats:
maskededit_kwargs['formatcodes'] = 'T!'
# This allows range validation if set
maskededit_kwargs['validFunc'] = self.IsInBounds
# This allows range limits to affect insertion into control or not
# dynamically without affecting individual field constraint validation
maskededit_kwargs['retainFieldValidation'] = True
# Now we can initialize the base control:
BaseMaskedTextCtrl.__init__(
self, parent, id=id,
pos=pos, size=size,
style = style,
validator = validator,
name = name,
setupEventHandling = False,
**maskededit_kwargs)
# This makes ':' act like tab (after we fix each ':' key event to remove "shift")
self._SetKeyHandler(':', self._OnChangeField)
# This makes the up/down keys act like spin button controls:
self._SetKeycodeHandler(wx.WXK_UP, self.__OnSpinUp)
self._SetKeycodeHandler(wx.WXK_DOWN, self.__OnSpinDown)
# This allows ! and c/C to set the control to the current time:
self._SetKeyHandler('!', self.__OnSetToNow)
self._SetKeyHandler('c', self.__OnSetToNow)
self._SetKeyHandler('C', self.__OnSetToNow)
# Set up event handling ourselves, so we can insert special
# processing on the ":' key to remove the "shift" attribute
# *before* the default handlers have been installed, so
# that : takes you forward, not back, and so we can issue
# EVT_TIMEUPDATE events on changes:
self.Bind(wx.EVT_SET_FOCUS, self._OnFocus ) ## defeat automatic full selection
self.Bind(wx.EVT_KILL_FOCUS, self._OnKillFocus ) ## run internal validator
self.Bind(wx.EVT_LEFT_UP, self.__LimitSelection) ## limit selections to single field
self.Bind(wx.EVT_LEFT_DCLICK, self._OnDoubleClick ) ## select field under cursor on dclick
self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown ) ## capture control events not normally seen, eg ctrl-tab.
self.Bind(wx.EVT_CHAR, self.__OnChar ) ## remove "shift" attribute from colon key event,
## then call BaseMaskedTextCtrl._OnChar with
## the possibly modified event.
self.Bind(wx.EVT_TEXT, self.__OnTextChange, self ) ## color control appropriately and EVT_TIMEUPDATE events
# Validate initial value and set if appropriate
try:
self.SetBounds(min, max)
self.SetLimited(limited)
self.SetValue(value)
except:
self.SetValue('00:00:00')
if spinButton:
self.BindSpinButton(spinButton) # bind spin button up/down events to this control
def SetParameters(self, **kwargs):
"""
Function providing access to the parameters governing TimeCtrl display and bounds.
"""
## dbg('TimeCtrl::SetParameters(%s)' % repr(kwargs), indent=1)
maskededit_kwargs = {}
reset_format = False
if kwargs.has_key('display_seconds'):
kwargs['displaySeconds'] = kwargs['display_seconds']
del kwargs['display_seconds']
if kwargs.has_key('format') and kwargs.has_key('displaySeconds'):
del kwargs['displaySeconds'] # always apply format if specified
# assign keyword args as appropriate:
for key, param_value in kwargs.items():
if key not in TimeCtrl.valid_ctrl_params.keys():
raise AttributeError('invalid keyword argument "%s"' % key)
if key == 'format':
wxdt = wx.DateTimeFromDMY(1, 0, 1970)
try:
if wxdt.Format('%p') != 'AM':
require24hr = True
else:
require24hr = False
except:
require24hr = True
# handle both local or generic 'maskededit' autoformat codes:
if param_value == 'HHMMSS' or param_value == 'TIMEHHMMSS':
self.__displaySeconds = True
self.__fmt24hr = False
elif param_value == 'HHMM' or param_value == 'TIMEHHMM':
self.__displaySeconds = False
self.__fmt24hr = False
elif param_value == '24HHMMSS' or param_value == '24HRTIMEHHMMSS':
self.__displaySeconds = True
self.__fmt24hr = True
elif param_value == '24HHMM' or param_value == '24HRTIMEHHMM':
self.__displaySeconds = False
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'):
self.__displaySeconds = param_value
reset_format = True
elif key == "min": min = param_value
elif key == "max": max = param_value
elif key == "limited": limited = param_value
elif key == "useFixedWidthFont":
maskededit_kwargs[key] = param_value
elif key == "oob_color":
maskededit_kwargs['invalidBackgroundColor'] = param_value
if reset_format:
if self.__fmt24hr:
if self.__displaySeconds: maskededit_kwargs['autoformat'] = '24HRTIMEHHMMSS'
else: maskededit_kwargs['autoformat'] = '24HRTIMEHHMM'
# Set hour field to zero-pad, right-insert, require explicit field change,
# select entire field on entry, and require a resultant valid entry
# to allow character entry:
hourfield = Field(formatcodes='0r<SV', validRegex='0\d|1\d|2[0123]', validRequired=True)
else:
if self.__displaySeconds: maskededit_kwargs['autoformat'] = 'TIMEHHMMSS'
else: maskededit_kwargs['autoformat'] = 'TIMEHHMM'
# Set hour field to allow spaces (at start), right-insert,
# require explicit field change, select entire field on entry,
# and require a resultant valid entry to allow character entry:
hourfield = Field(formatcodes='_0<rSV', validRegex='0[1-9]| [1-9]|1[012]', validRequired=True)
ampmfield = Field(formatcodes='S', emptyInvalid = True, validRequired = True)
# Field 1 is always a zero-padded right-insert minute field,
# similarly configured as above:
minutefield = Field(formatcodes='0r<SV', validRegex='[0-5]\d', validRequired=True)
fields = [ hourfield, minutefield ]
if self.__displaySeconds:
fields.append(copy.copy(minutefield)) # second field has same constraints as field 1
if not self.__fmt24hr:
fields.append(ampmfield)
# set fields argument:
maskededit_kwargs['fields'] = fields
# This allows range validation if set
maskededit_kwargs['validFunc'] = self.IsInBounds
# This allows range limits to affect insertion into control or not
# dynamically without affecting individual field constraint validation
maskededit_kwargs['retainFieldValidation'] = True
if hasattr(self, 'controlInitialized') and self.controlInitialized:
self.SetCtrlParameters(**maskededit_kwargs) # set appropriate parameters
# Validate initial value and set if appropriate
try:
self.SetBounds(min, max)
self.SetLimited(limited)
self.SetValue(value)
except:
self.SetValue('00:00:00')
## dbg(indent=0)
return {} # no arguments to return
else:
## dbg(indent=0)
return maskededit_kwargs
def BindSpinButton(self, sb):
"""
This function binds an externally created spin button to the control, so that
up/down events from the button automatically change the control.
"""
## dbg('TimeCtrl::BindSpinButton')
self.__spinButton = sb
if self.__spinButton:
# bind event handlers to spin ctrl
self.__spinButton.Bind(wx.EVT_SPIN_UP, self.__OnSpinUp, self.__spinButton)
self.__spinButton.Bind(wx.EVT_SPIN_DOWN, self.__OnSpinDown, self.__spinButton)
def __repr__(self):
return "<TimeCtrl: %s>" % self.GetValue()
def SetValue(self, value):
"""
Validating SetValue function for time values:
This function will do dynamic type checking on the value argument,
and convert wxDateTime, mxDateTime, or 12/24 format time string
into the appropriate format string for the control.
"""
## dbg('TimeCtrl::SetValue(%s)' % repr(value), indent=1)
try:
strtime = self._toGUI(self.__validateValue(value))
except:
## dbg('validation failed', indent=0)
raise
## dbg('strtime:', strtime)
self._SetValue(strtime)
## dbg(indent=0)
def GetValue(self,
as_wxDateTime = False,
as_mxDateTime = False,
as_wxTimeSpan = False,
as_mxDateTimeDelta = False):
"""
This function returns the value of the display as a string by default, but
supports return as a wx.DateTime, mx.DateTime, wx.TimeSpan, or mx.DateTimeDelta,
if requested. (Evaluated in the order above-- first one wins!)
"""
if as_wxDateTime or as_mxDateTime or as_wxTimeSpan or as_mxDateTimeDelta:
value = self.GetWxDateTime()
if as_wxDateTime:
pass
elif as_mxDateTime:
value = DateTime.DateTime(1970, 1, 1, value.GetHour(), value.GetMinute(), value.GetSecond())
elif as_wxTimeSpan:
value = wx.TimeSpan(value.GetHour(), value.GetMinute(), value.GetSecond())
elif as_mxDateTimeDelta:
value = DateTime.DateTimeDelta(0, value.GetHour(), value.GetMinute(), value.GetSecond())
else:
value = BaseMaskedTextCtrl.GetValue(self)
return value
def SetWxDateTime(self, wxdt):
"""
Because SetValue can take a wx.DateTime, this is now just an alias.
"""
self.SetValue(wxdt)
def GetWxDateTime(self, value=None):
"""
This function is the conversion engine for TimeCtrl; it takes
one of the following types:
time string
wxDateTime
wxTimeSpan
mxDateTime
mxDateTimeDelta
and converts it to a wx.DateTime that always has Jan 1, 1970 as its date
portion, so that range comparisons around values can work using
wx.DateTime's built-in comparison function. If a value is not
provided to convert, the string value of the control will be used.
If the value is not one of the accepted types, a ValueError will be
raised.
"""
global accept_mx
## dbg(suspend=1)
## dbg('TimeCtrl::GetWxDateTime(%s)' % repr(value), indent=1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -