MaskedEditCtrl updates from Will Sadkin
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26096 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
# Created: 09/06/2003
|
||||
# Copyright: (c) 2003 by Will Sadkin
|
||||
# RCS-ID: $Id$
|
||||
# License: wxWindows license
|
||||
# License: wxWidgets license
|
||||
#----------------------------------------------------------------------------
|
||||
# NOTE:
|
||||
# This was written to provide a numeric edit control for wxPython that
|
||||
@@ -29,7 +29,7 @@
|
||||
# are exceeded.
|
||||
#
|
||||
# MaskedNumCtrl is intended to support fixed-point numeric entry, and
|
||||
# is derived from MaskedTextCtrl. As such, it supports a limited range
|
||||
# is derived from BaseMaskedTextCtrl. As such, it supports a limited range
|
||||
# of values to comply with a fixed-width entry mask.
|
||||
#----------------------------------------------------------------------------
|
||||
# 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
||||
@@ -65,10 +65,10 @@ Here's the API:
|
||||
<B>MaskedNumCtrl</B>(
|
||||
parent, id = -1,
|
||||
<B>value</B> = 0,
|
||||
pos = wxDefaultPosition,
|
||||
size = wxDefaultSize,
|
||||
pos = wx.DefaultPosition,
|
||||
size = wx.DefaultSize,
|
||||
style = 0,
|
||||
validator = wxDefaultValidator,
|
||||
validator = wx.DefaultValidator,
|
||||
name = "maskednumber",
|
||||
<B>integerWidth</B> = 10,
|
||||
<B>fractionWidth</B> = 0,
|
||||
@@ -87,6 +87,7 @@ Here's the API:
|
||||
<B>emptyBackgroundColour</B> = "White",
|
||||
<B>validBackgroundColour</B> = "White",
|
||||
<B>invalidBackgroundColour</B> = "Yellow",
|
||||
<B>autoSize</B> = True
|
||||
)
|
||||
</PRE>
|
||||
<UL>
|
||||
@@ -177,11 +178,20 @@ Here's the API:
|
||||
<DT><B>invalidBackgroundColour</B>
|
||||
<DD>Color value used for illegal values or values out-of-bounds of the
|
||||
control when the bounds are set but the control is not limited.
|
||||
<BR>
|
||||
<DT><B>autoSize</B>
|
||||
<DD>Boolean indicating whether or not the control should set its own
|
||||
width based on the integer and fraction widths. True by default.
|
||||
<B><I>Note:</I></B> Setting this to False will produce seemingly odd
|
||||
behavior unless the control is large enough to hold the maximum
|
||||
specified value given the widths and the sign positions; if not,
|
||||
the control will appear to "jump around" as the contents scroll.
|
||||
(ie. autoSize is highly recommended.)
|
||||
</UL>
|
||||
<BR>
|
||||
<BR>
|
||||
<DT><B>EVT_MASKEDNUM(win, id, func)</B>
|
||||
<DD>Respond to a wxEVT_COMMAND_MASKED_NUMBER_UPDATED event, generated when
|
||||
<DD>Respond to a EVT_COMMAND_MASKED_NUMBER_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.)
|
||||
@@ -353,6 +363,12 @@ within the control. (The default is True.)
|
||||
the field values on entry.
|
||||
<BR>
|
||||
<BR>
|
||||
<DT><B>SetAutoSize(bool)</B>
|
||||
<DD>Resets the autoSize attribute of the control.
|
||||
<DT><B>GetAutoSize()</B>
|
||||
<DD>Returns the current state of the autoSize attribute for the control.
|
||||
<BR>
|
||||
<BR>
|
||||
</DL>
|
||||
</body></html>
|
||||
"""
|
||||
@@ -368,8 +384,7 @@ MAXINT = maxint # (constants should be in upper case)
|
||||
MININT = -maxint-1
|
||||
|
||||
from wx.tools.dbg import Logger
|
||||
from wx.lib.maskededit import MaskedEditMixin, MaskedTextCtrl, Field
|
||||
|
||||
from wx.lib.maskededit import MaskedEditMixin, BaseMaskedTextCtrl, Field
|
||||
dbg = Logger()
|
||||
dbg(enable=0)
|
||||
|
||||
@@ -394,16 +409,55 @@ class MaskedNumNumberUpdatedEvent(wx.PyCommandEvent):
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
class MaskedNumCtrlAccessorsMixin:
|
||||
# Define wxMaskedNumCtrl's list of attributes having their own
|
||||
# Get/Set functions, ignoring those that make no sense for
|
||||
# an numeric control.
|
||||
exposed_basectrl_params = (
|
||||
'decimalChar',
|
||||
'shiftDecimalChar',
|
||||
'groupChar',
|
||||
'useParensForNegatives',
|
||||
'defaultValue',
|
||||
'description',
|
||||
|
||||
'useFixedWidthFont',
|
||||
'autoSize',
|
||||
'signedForegroundColour',
|
||||
'emptyBackgroundColour',
|
||||
'validBackgroundColour',
|
||||
'invalidBackgroundColour',
|
||||
|
||||
'emptyInvalid',
|
||||
'validFunc',
|
||||
'validRequired',
|
||||
)
|
||||
for param in exposed_basectrl_params:
|
||||
propname = param[0].upper() + param[1:]
|
||||
exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param))
|
||||
exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param))
|
||||
|
||||
if param.find('Colour') != -1:
|
||||
# add non-british spellings, for backward-compatibility
|
||||
propname.replace('Colour', 'Color')
|
||||
|
||||
exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param))
|
||||
exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param))
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin):
|
||||
|
||||
class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
valid_ctrl_params = {
|
||||
'integerWidth': 10, # by default allow all 32-bit integers
|
||||
'fractionWidth': 0, # by default, use integers
|
||||
'fractionWidth': 0, # by default, use integers
|
||||
'decimalChar': '.', # by default, use '.' for decimal point
|
||||
'allowNegative': True, # by default, allow negative numbers
|
||||
'useParensForNegatives': False, # by default, use '-' to indicate negatives
|
||||
'groupDigits': True, # by default, don't insert grouping
|
||||
'groupDigits': True, # by default, don't insert grouping
|
||||
'groupChar': ',', # by default, use ',' for grouping
|
||||
'min': None, # by default, no bounds set
|
||||
'max': None,
|
||||
@@ -415,7 +469,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
'emptyBackgroundColour': "White",
|
||||
'validBackgroundColour': "White",
|
||||
'invalidBackgroundColour': "Yellow",
|
||||
'useFixedWidthFont': True, # by default, use a fixed-width font
|
||||
'useFixedWidthFont': True, # by default, use a fixed-width font
|
||||
'autoSize': True, # by default, set the width of the control based on the mask
|
||||
}
|
||||
|
||||
|
||||
@@ -488,6 +543,12 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
del init_args['integerWidth']
|
||||
del init_args['fractionWidth']
|
||||
|
||||
self._autoSize = init_args['autoSize']
|
||||
if self._autoSize:
|
||||
formatcodes = 'FR<'
|
||||
else:
|
||||
formatcodes = 'R<'
|
||||
|
||||
|
||||
mask = intmask+fracmask
|
||||
|
||||
@@ -497,11 +558,11 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
self._typedSign = False
|
||||
|
||||
# Construct the base control:
|
||||
MaskedTextCtrl.__init__(
|
||||
BaseMaskedTextCtrl.__init__(
|
||||
self, parent, id, '',
|
||||
pos, size, style, validator, name,
|
||||
mask = mask,
|
||||
formatcodes = 'FR<',
|
||||
formatcodes = formatcodes,
|
||||
fields = fields,
|
||||
validFunc=self.IsInBounds,
|
||||
setupEventHandling = False)
|
||||
@@ -538,7 +599,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
if( (kwargs.has_key('integerWidth') and kwargs['integerWidth'] != self._integerWidth)
|
||||
or (kwargs.has_key('fractionWidth') and kwargs['fractionWidth'] != self._fractionWidth)
|
||||
or (kwargs.has_key('groupDigits') and kwargs['groupDigits'] != self._groupDigits) ):
|
||||
or (kwargs.has_key('groupDigits') and kwargs['groupDigits'] != self._groupDigits)
|
||||
or (kwargs.has_key('autoSize') and kwargs['autoSize'] != self._autoSize) ):
|
||||
|
||||
fields = {}
|
||||
|
||||
@@ -614,7 +676,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
dbg('kwargs:', kwargs)
|
||||
|
||||
# reprocess existing format codes to ensure proper resulting format:
|
||||
formatcodes = self.GetFormatcodes()
|
||||
formatcodes = self.GetCtrlParameter('formatcodes')
|
||||
if kwargs.has_key('allowNegative'):
|
||||
if kwargs['allowNegative'] and '-' not in formatcodes:
|
||||
formatcodes += '-'
|
||||
@@ -641,6 +703,16 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
formatcodes = formatcodes.replace('S','')
|
||||
maskededit_kwargs['formatcodes'] = formatcodes
|
||||
|
||||
if kwargs.has_key('autoSize'):
|
||||
self._autoSize = kwargs['autoSize']
|
||||
if kwargs['autoSize'] and 'F' not in formatcodes:
|
||||
formatcodes += 'F'
|
||||
maskededit_kwargs['formatcodes'] = formatcodes
|
||||
elif not kwargs['autoSize'] and 'F' in formatcodes:
|
||||
formatcodes = formatcodes.replace('F', '')
|
||||
maskededit_kwargs['formatcodes'] = formatcodes
|
||||
|
||||
|
||||
if 'r' in formatcodes and self._fractionWidth:
|
||||
# top-level mask should only be right insert if no fractional
|
||||
# part will be shown; ie. if reconfiguring control, remove
|
||||
@@ -648,6 +720,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
formatcodes = formatcodes.replace('r', '')
|
||||
maskededit_kwargs['formatcodes'] = formatcodes
|
||||
|
||||
|
||||
if kwargs.has_key('limited'):
|
||||
if kwargs['limited'] and not self._limited:
|
||||
maskededit_kwargs['validRequired'] = True
|
||||
@@ -661,6 +734,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
# Record end of integer and place cursor there:
|
||||
integerEnd = self._fields[0]._extent[1]
|
||||
self.SetInsertionPoint(0)
|
||||
self.SetInsertionPoint(integerEnd)
|
||||
self.SetSelection(integerEnd, integerEnd)
|
||||
|
||||
@@ -733,7 +807,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
dbg('abs(value):', value)
|
||||
self._isNeg = False
|
||||
|
||||
elif not self._allowNone and MaskedTextCtrl.GetValue(self) == '':
|
||||
elif not self._allowNone and BaseMaskedTextCtrl.GetValue(self) == '':
|
||||
if self._min > 0:
|
||||
value = self._min
|
||||
else:
|
||||
@@ -775,7 +849,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
else:
|
||||
fracstart, fracend = self._fields[1]._extent
|
||||
if candidate is None:
|
||||
value = self._toGUI(MaskedTextCtrl.GetValue(self))
|
||||
value = self._toGUI(BaseMaskedTextCtrl.GetValue(self))
|
||||
else:
|
||||
value = self._toGUI(candidate)
|
||||
fracstring = value[fracstart:fracend].strip()
|
||||
@@ -824,8 +898,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
if numvalue == "":
|
||||
if self._allowNone:
|
||||
dbg('calling base MaskedTextCtrl._SetValue(self, "%s")' % value)
|
||||
MaskedTextCtrl._SetValue(self, value)
|
||||
dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value)
|
||||
BaseMaskedTextCtrl._SetValue(self, value)
|
||||
self.Refresh()
|
||||
return
|
||||
elif self._min > 0 and self.IsLimited():
|
||||
@@ -925,7 +999,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
# reasonable instead:
|
||||
dbg('setting replacement value:', replacement)
|
||||
self._SetValue(self._toGUI(replacement))
|
||||
sel_start = MaskedTextCtrl.GetValue(self).find(str(abs(replacement))) # find where it put the 1, so we can select it
|
||||
sel_start = BaseMaskedTextCtrl.GetValue(self).find(str(abs(replacement))) # find where it put the 1, so we can select it
|
||||
sel_to = sel_start + len(str(abs(replacement)))
|
||||
dbg('queuing selection of (%d, %d)' %(sel_start, sel_to))
|
||||
wx.CallAfter(self.SetInsertionPoint, sel_start)
|
||||
@@ -951,8 +1025,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
|
||||
sel_start, sel_to = self._GetSelection() # record current insertion point
|
||||
dbg('calling base MaskedTextCtrl._SetValue(self, "%s")' % adjvalue)
|
||||
MaskedTextCtrl._SetValue(self, adjvalue)
|
||||
dbg('calling BaseMaskedTextCtrl._SetValue(self, "%s")' % adjvalue)
|
||||
BaseMaskedTextCtrl._SetValue(self, adjvalue)
|
||||
# After all actions so far scheduled, check that resulting cursor
|
||||
# position is appropriate, and move if not:
|
||||
wx.CallAfter(self._CheckInsertionPoint)
|
||||
@@ -985,7 +1059,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
# delete next digit to appropriate side:
|
||||
if self._groupDigits:
|
||||
key = event.GetKeyCode()
|
||||
value = MaskedTextCtrl.GetValue(self)
|
||||
value = BaseMaskedTextCtrl.GetValue(self)
|
||||
sel_start, sel_to = self._GetSelection()
|
||||
|
||||
if key == wx.WXK_BACK:
|
||||
@@ -1011,7 +1085,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
self.SetInsertionPoint(sel_start)
|
||||
self.SetSelection(sel_start, sel_to+1)
|
||||
|
||||
MaskedTextCtrl._OnErase(self, event)
|
||||
BaseMaskedTextCtrl._OnErase(self, event)
|
||||
dbg(indent=0)
|
||||
|
||||
|
||||
@@ -1025,7 +1099,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
before passing the events on.
|
||||
"""
|
||||
dbg('MaskedNumCtrl::OnTextChange', indent=1)
|
||||
if not MaskedTextCtrl._OnTextChange(self, event):
|
||||
if not BaseMaskedTextCtrl._OnTextChange(self, event):
|
||||
dbg(indent=0)
|
||||
return
|
||||
|
||||
@@ -1046,7 +1120,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
|
||||
def _GetValue(self):
|
||||
"""
|
||||
Override of MaskedTextCtrl to allow amixin to get the raw text value of the
|
||||
Override of BaseMaskedTextCtrl to allow mixin to get the raw text value of the
|
||||
control with this function.
|
||||
"""
|
||||
return wx.TextCtrl.GetValue(self)
|
||||
@@ -1056,7 +1130,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
"""
|
||||
Returns the current numeric value of the control.
|
||||
"""
|
||||
return self._fromGUI( MaskedTextCtrl.GetValue(self) )
|
||||
return self._fromGUI( BaseMaskedTextCtrl.GetValue(self) )
|
||||
|
||||
def SetValue(self, value):
|
||||
"""
|
||||
@@ -1067,16 +1141,16 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
A ValueError exception will be raised if an invalid value
|
||||
is specified.
|
||||
"""
|
||||
MaskedTextCtrl.SetValue( self, self._toGUI(value) )
|
||||
BaseMaskedTextCtrl.SetValue( self, self._toGUI(value) )
|
||||
|
||||
|
||||
def SetIntegerWidth(self, value):
|
||||
self.SetCtrlParameters(integerWidth=value)
|
||||
self.SetParameters(integerWidth=value)
|
||||
def GetIntegerWidth(self):
|
||||
return self._integerWidth
|
||||
|
||||
def SetFractionWidth(self, value):
|
||||
self.SetCtrlParameters(fractionWidth=value)
|
||||
self.SetParameters(fractionWidth=value)
|
||||
def GetFractionWidth(self):
|
||||
return self._fractionWidth
|
||||
|
||||
@@ -1221,7 +1295,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
except ValueError, e:
|
||||
dbg('error getting NumValue(self._toGUI(value)):', e, indent=0)
|
||||
return False
|
||||
if value == '':
|
||||
if value.strip() == '':
|
||||
value = None
|
||||
elif self._fractionWidth:
|
||||
value = float(value)
|
||||
@@ -1294,6 +1368,12 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
def GetSelectOnEntry(self):
|
||||
return self._selectOnEntry
|
||||
|
||||
def SetAutoSize(self, value):
|
||||
self.SetParameters(autoSize=value)
|
||||
def GetAutoSize(self):
|
||||
return self._autoSize
|
||||
|
||||
|
||||
# (Other parameter accessors are inherited from base class)
|
||||
|
||||
|
||||
@@ -1311,6 +1391,14 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
elif type(value) in (types.StringType, types.UnicodeType):
|
||||
value = self._GetNumValue(value)
|
||||
dbg('cleansed num value: "%s"' % value)
|
||||
if value == "":
|
||||
if self.IsNoneAllowed():
|
||||
dbg(indent=0)
|
||||
return self._template
|
||||
else:
|
||||
dbg('exception raised:', e, indent=0)
|
||||
raise ValueError ('wxMaskedNumCtrl requires numeric value, passed %s'% repr(value) )
|
||||
# else...
|
||||
try:
|
||||
if self._fractionWidth or value.find('.') != -1:
|
||||
value = float(value)
|
||||
@@ -1380,7 +1468,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
|
||||
# So, to ensure consistency and to prevent spurious ValueErrors,
|
||||
# we make the following test, and react accordingly:
|
||||
#
|
||||
if value == '':
|
||||
if value.strip() == '':
|
||||
if not self.IsNoneAllowed():
|
||||
dbg('empty value; not allowed,returning 0', indent = 0)
|
||||
if self._fractionWidth:
|
||||
@@ -1514,3 +1602,12 @@ i=0
|
||||
## =============================##
|
||||
## 1. Add support for printf-style format specification.
|
||||
## 2. Add option for repositioning on 'illegal' insertion point.
|
||||
##
|
||||
## Version 1.1
|
||||
## 1. Fixed .SetIntegerWidth() and .SetFractionWidth() functions.
|
||||
## 2. Added autoSize parameter, to allow manual sizing of the control.
|
||||
## 3. Changed inheritance to use wxBaseMaskedTextCtrl, to remove exposure of
|
||||
## nonsensical parameter methods from the control, so it will work
|
||||
## properly with Boa.
|
||||
## 4. Fixed allowNone bug found by user sameerc1@grandecom.net
|
||||
|
||||
|
Reference in New Issue
Block a user