X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d4b73b1b8e585418459362c9bf9173aa21da8c41..b887061dd1d7b3a49a111513309b1bb5c308537c:/wxPython/wx/lib/maskednumctrl.py?ds=sidebyside diff --git a/wxPython/wx/lib/maskednumctrl.py b/wxPython/wx/lib/maskednumctrl.py index 138a88adbe..9a3d234793 100644 --- a/wxPython/wx/lib/maskednumctrl.py +++ b/wxPython/wx/lib/maskednumctrl.py @@ -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: MaskedNumCtrl( parent, id = -1, value = 0, - pos = wxDefaultPosition, - size = wxDefaultSize, + pos = wx.DefaultPosition, + size = wx.DefaultSize, style = 0, - validator = wxDefaultValidator, + validator = wx.DefaultValidator, name = "maskednumber", integerWidth = 10, fractionWidth = 0, @@ -87,6 +87,7 @@ Here's the API: emptyBackgroundColour = "White", validBackgroundColour = "White", invalidBackgroundColour = "Yellow", + autoSize = True )

EVT_MASKEDNUM(win, id, func) -
Respond to a wxEVT_COMMAND_MASKED_NUMBER_UPDATED event, generated when +
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.

+
SetAutoSize(bool) +
Resets the autoSize attribute of the control. +
GetAutoSize() +
Returns the current state of the autoSize attribute for the control. +
+
""" @@ -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 +