X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5f280eaa578e05b3b85d9bcf5ab6c3dcee03a448..d1b736b7968ceea4233f3fceecdb01173f68a9a3:/wxPython/wx/lib/masked/combobox.py?ds=inline diff --git a/wxPython/wx/lib/masked/combobox.py b/wxPython/wx/lib/masked/combobox.py index c42db0c945..1eba82de0c 100644 --- a/wxPython/wx/lib/masked/combobox.py +++ b/wxPython/wx/lib/masked/combobox.py @@ -13,19 +13,29 @@ # #---------------------------------------------------------------------------- -import wx +""" +Provides masked edit capabilities within a ComboBox format, as well as +a base class from which you can derive masked comboboxes tailored to a specific +function. See maskededit module overview for how to configure the control. +""" + +import wx, types, string from wx.lib.masked import * # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would # be a good place to implement the 2.3 logger class from wx.tools.dbg import Logger -dbg = Logger() -##dbg(enable=0) +##dbg = Logger() +##dbg(enable=1) ## ---------- ---------- ---------- ---------- ---------- ---------- ---------- ## Because calling SetSelection programmatically does not fire EVT_COMBOBOX ## events, we have to do it ourselves when we auto-complete. class MaskedComboBoxSelectEvent(wx.PyCommandEvent): + """ + Because calling SetSelection programmatically does not fire EVT_COMBOBOX + events, the derived control has to do it itself when it auto-completes. + """ def __init__(self, id, selection = 0, object=None): wx.PyCommandEvent.__init__(self, wx.wxEVT_COMMAND_COMBOBOX_SELECTED, id) @@ -37,11 +47,36 @@ class MaskedComboBoxSelectEvent(wx.PyCommandEvent): this event was generated.""" return self.__selection +class MaskedComboBoxEventHandler(wx.EvtHandler): + """ + This handler ensures that the derived control can react to events + from the base control before any external handlers run, to ensure + proper behavior. + """ + def __init__(self, combobox): + wx.EvtHandler.__init__(self) + self.combobox = combobox + combobox.PushEventHandler(self) + self.Bind(wx.EVT_SET_FOCUS, self.combobox._OnFocus ) ## defeat automatic full selection + self.Bind(wx.EVT_KILL_FOCUS, self.combobox._OnKillFocus ) ## run internal validator + self.Bind(wx.EVT_LEFT_DCLICK, self.combobox._OnDoubleClick) ## select field under cursor on dclick + self.Bind(wx.EVT_RIGHT_UP, self.combobox._OnContextMenu ) ## bring up an appropriate context menu + self.Bind(wx.EVT_CHAR, self.combobox._OnChar ) ## handle each keypress + self.Bind(wx.EVT_KEY_DOWN, self.combobox._OnKeyDownInComboBox ) ## for special processing of up/down keys + self.Bind(wx.EVT_KEY_DOWN, self.combobox._OnKeyDown ) ## for processing the rest of the control keys + ## (next in evt chain) + self.Bind(wx.EVT_COMBOBOX, self.combobox._OnDropdownSelect ) ## to bring otherwise completely independent base + ## ctrl selection into maskededit framework + self.Bind(wx.EVT_TEXT, self.combobox._OnTextChange ) ## color control appropriately & keep + ## track of previous value for undo + + class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): """ - This masked edit control adds the ability to use a masked input - on a combobox, and do auto-complete of such values. + Base class for generic masked edit comboboxes; allows auto-complete of values. + It is not meant to be instantiated directly, but rather serves as a base class + for any subsequent refinements. """ def __init__( self, parent, id=-1, value = '', pos = wx.DefaultPosition, @@ -54,11 +89,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 +110,55 @@ 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.SetInitialSize((width, height)) + if value: # ensure value is width of the mask of the control: @@ -103,21 +173,18 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): self._SetInitialValue(value) - self._SetKeycodeHandler(wx.WXK_UP, self.OnSelectChoice) - self._SetKeycodeHandler(wx.WXK_DOWN, self.OnSelectChoice) + self._SetKeycodeHandler(wx.WXK_UP, self._OnSelectChoice) + self._SetKeycodeHandler(wx.WXK_DOWN, self._OnSelectChoice) + + self.replace_next_combobox_event = False + self.correct_selection = -1 if setupEventHandling: - ## Setup event handlers - 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_DCLICK, self._OnDoubleClick) ## select field under cursor on dclick - self.Bind(wx.EVT_RIGHT_UP, self._OnContextMenu ) ## bring up an appropriate context menu - self.Bind(wx.EVT_CHAR, self._OnChar ) ## handle each keypress - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown ) ## for special processing of up/down keys - self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown ) ## for processing the rest of the control keys - ## (next in evt chain) - self.Bind(wx.EVT_TEXT, self._OnTextChange ) ## color control appropriately & keep - ## track of previous value for undo + ## Setup event handling functions through event handler object, + ## to guarantee processing prior to giving event callbacks from + ## outside the class: + self.evt_handler = MaskedComboBoxEventHandler(self) + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnWindowDestroy ) @@ -125,6 +192,13 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): return "" % self.GetValue() + def OnWindowDestroy(self, event): + # clean up associated event handler object: + if self.RemoveEventHandler(self.evt_handler): + self.evt_handler.Destroy() + event.Skip() + + def _CalcSize(self, size=None): """ Calculate automatic size if allowed; augment base mixin function @@ -134,11 +208,24 @@ 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.SetInitialSize((width, height)) + + def _GetSelection(self): """ Allow mixin to get the text selection of this control. REQUIRED by any class derived from MaskedEditMixin. """ +## dbg('MaskedComboBox::_GetSelection()') return self.GetMark() def _SetSelection(self, sel_start, sel_to): @@ -146,16 +233,29 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): Allow mixin to set the text selection of this control. REQUIRED by any class derived from MaskedEditMixin. """ +## dbg('MaskedComboBox::_SetSelection: setting mark to (%d, %d)' % (sel_start, sel_to)) return self.SetMark( sel_start, sel_to ) def _GetInsertionPoint(self): - return self.GetInsertionPoint() +## dbg('MaskedComboBox::_GetInsertionPoint()', indent=1) +## ret = self.GetInsertionPoint() + # work around new bug in 2.5, in which the insertion point + # returned is always at the right side of the selection, + # rather than the start, as is the case with TextCtrl. + ret = self.GetMark()[0] +## dbg('returned', ret, indent=0) + return ret def _SetInsertionPoint(self, pos): +## dbg('MaskedComboBox::_SetInsertionPoint(%d)' % pos) self.SetInsertionPoint(pos) + def IsEmpty(*args, **kw): + return MaskedEditMixin.IsEmpty(*args, **kw) + + def _GetValue(self): """ Allow mixin to get the raw value of the control with this function. @@ -180,7 +280,9 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): # Record current selection and insertion point, for undo self._prevSelection = self._GetSelection() self._prevInsertionPoint = self._GetInsertionPoint() +## dbg('MaskedComboBox::_SetValue(%s), selection beforehand: %d' % (value, self.GetSelection())) wx.ComboBox.SetValue(self, value) +## dbg('MaskedComboBox::_SetValue(%s), selection now: %d' % (value, self.GetSelection())) # text change events don't always fire, so we check validity here # to make certain formatting is applied: self._CheckValid() @@ -192,11 +294,14 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): masked control. NOTE: this must be done in the class derived from the base wx control. """ +## dbg('MaskedComboBox::SetValue(%s)' % value, indent=1) if not self._mask: wx.ComboBox.SetValue(value) # revert to base control behavior +## dbg('no mask; deferring to base class', indent=0) return # else... # empty previous contents, replacing entire value: +## dbg('MaskedComboBox::SetValue: selection beforehand: %d' % (self.GetSelection())) self._SetInsertionPoint(0) self._SetSelection(0, self._masklength) @@ -234,15 +339,26 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): dateparts = value.split(' ') dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True) value = string.join(dateparts, ' ') -## dbg('adjusted value: "%s"' % value) value = self._Paste(value, raise_on_invalid=True, just_return_value=True) else: raise +## dbg('adjusted value: "%s"' % value) - self._SetValue(value) -#### dbg('queuing insertion after .SetValue', replace_to) - wx.CallAfter(self._SetInsertionPoint, replace_to) - wx.CallAfter(self._SetSelection, replace_to, replace_to) + # Attempt to compensate for fact that calling .SetInsertionPoint() makes the + # selection index -1, even if the resulting set value is in the list. + # So, if we are setting a value that's in the list, use index selection instead. + if value in self._choices: + index = self._choices.index(value) + self._prevValue = self._curValue + self._curValue = self._choices[index] + self._ctrl_constraints._autoCompleteIndex = index + self.SetSelection(index) + else: + self._SetValue(value) +#### dbg('queuing insertion after .SetValue', replace_to) + wx.CallAfter(self._SetInsertionPoint, replace_to) + wx.CallAfter(self._SetSelection, replace_to, replace_to) +## dbg(indent=0) def _Refresh(self): @@ -306,14 +422,13 @@ 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 - of choices, because wxComboBox doesn't have an accessor for the choice list. - The code here is the same as in the SetParameters() mixin function, but is - done for the individual value as appended, so the list can be built incrementally - without speed penalty. + This base control function override is necessary so the control can keep track + of any additions to the list of choices, because wx.ComboBox doesn't have an + accessor for the choice list. The code here is the same as in the + SetParameters() mixin function, but is done for the individual value + as appended, so the list can be built incrementally without speed penalty. """ if self._mask: if type(choice) not in (types.StringType, types.UnicodeType): @@ -352,11 +467,19 @@ 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 ): """ - This function override is necessary so we can keep track of any additions to the list - of choices, because wxComboBox doesn't have an accessor for the choice list. + This base control function override is necessary so the derived control can + keep track of any additions to the list of choices, because wx.ComboBox + doesn't have an accessor for the choice list. """ if self._mask: self._choices = [] @@ -368,8 +491,8 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): def _OnCtrlParametersChanged(self): """ - Override mixin's default OnCtrlParametersChanged to detect changes in choice list, so - we can update the base control: + This overrides the mixin's default OnCtrlParametersChanged to detect + changes in choice list, so masked.Combobox can update the base control: """ if self.controlInitialized and self._choices != self._ctrl_constraints._choices: wx.ComboBox.Clear(self) @@ -378,71 +501,115 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): wx.ComboBox.Append( self, choice ) - def GetMark(self): - """ - This function is a hack to make up for the fact that wxComboBox has no - method for returning the selected portion of its edit control. It - works, but has the nasty side effect of generating lots of intermediate - events. - """ -## dbg(suspend=1) # turn off debugging around this function -## dbg('MaskedComboBox::GetMark', indent=1) - if self.__readonly: -## dbg(indent=0) - return 0, 0 # no selection possible for editing -## sel_start, sel_to = wxComboBox.GetMark(self) # what I'd *like* to have! - sel_start = sel_to = self.GetInsertionPoint() -## dbg("current sel_start:", sel_start) - value = self.GetValue() -## dbg('value: "%s"' % value) - - self._ignoreChange = True # tell _OnTextChange() to ignore next event (if any) - - wx.ComboBox.Cut(self) - newvalue = self.GetValue() -## dbg("value after Cut operation:", newvalue) - - if newvalue != value: # something was selected; calculate extent -## dbg("something selected") - sel_to = sel_start + len(value) - len(newvalue) - wx.ComboBox.SetValue(self, value) # restore original value and selection (still ignoring change) - wx.ComboBox.SetInsertionPoint(self, sel_start) - wx.ComboBox.SetMark(self, sel_start, sel_to) - - self._ignoreChange = False # tell _OnTextChange() to pay attn again - -## dbg('computed selection:', sel_start, sel_to, indent=0, suspend=0) - return sel_start, sel_to + # Not all wx platform implementations have .GetMark, so we make the following test, + # and fall back to our old hack if they don't... + # + if not hasattr(wx.ComboBox, 'GetMark'): + def GetMark(self): + """ + This function is a hack to make up for the fact that wx.ComboBox has no + method for returning the selected portion of its edit control. It + works, but has the nasty side effect of generating lots of intermediate + events. + """ +## dbg(suspend=1) # turn off debugging around this function +## dbg('MaskedComboBox::GetMark', indent=1) + if self.__readonly: +## dbg(indent=0) + return 0, 0 # no selection possible for editing +## sel_start, sel_to = wxComboBox.GetMark(self) # what I'd *like* to have! + sel_start = sel_to = self.GetInsertionPoint() +## dbg("current sel_start:", sel_start) + value = self.GetValue() +## dbg('value: "%s"' % value) + + self._ignoreChange = True # tell _OnTextChange() to ignore next event (if any) + + wx.ComboBox.Cut(self) + newvalue = self.GetValue() +## dbg("value after Cut operation:", newvalue) + + if newvalue != value: # something was selected; calculate extent +## dbg("something selected") + sel_to = sel_start + len(value) - len(newvalue) + wx.ComboBox.SetValue(self, value) # restore original value and selection (still ignoring change) + wx.ComboBox.SetInsertionPoint(self, sel_start) + wx.ComboBox.SetMark(self, sel_start, sel_to) + + self._ignoreChange = False # tell _OnTextChange() to pay attn again + +## dbg('computed selection:', sel_start, sel_to, indent=0, suspend=0) + return sel_start, sel_to + else: + def GetMark(self): +## dbg('MaskedComboBox::GetMark()', indent = 1) + ret = wx.ComboBox.GetMark(self) +## dbg('returned', ret, indent=0) + return ret def SetSelection(self, index): """ - Necessary for bookkeeping on choice selection, to keep current value + Necessary override for bookkeeping on choice selection, to keep current value current. """ -## dbg('MaskedComboBox::SetSelection(%d)' % index) +## dbg('MaskedComboBox::SetSelection(%d)' % index, indent=1) if self._mask: self._prevValue = self._curValue - self._curValue = self._choices[index] self._ctrl_constraints._autoCompleteIndex = index + if index != -1: + self._curValue = self._choices[index] + else: + self._curValue = None wx.ComboBox.SetSelection(self, index) +## dbg('selection now: %d' % self.GetCurrentSelection(), indent=0) - def OnKeyDown(self, event): + def _OnKeyDownInComboBox(self, event): """ - This function is necessary because navigation and control key - events do not seem to normally be seen by the wxComboBox's - EVT_CHAR routine. (Tabs don't seem to be visible no matter - what... {:-( ) + This function is necessary because navigation and control key events + do not seem to normally be seen by the wxComboBox's EVT_CHAR routine. + (Tabs don't seem to be visible no matter what, except for CB_READONLY + controls, for some bizarre reason... {:-( ) """ + key = event.GetKeyCode() +## dbg('MaskedComboBox::OnKeyDownInComboBox(%d)' % key) if event.GetKeyCode() in self._nav + self._control: - self._OnChar(event) - return + if not self._IsEditable(): + # WANTS_CHARS with CB_READONLY apparently prevents navigation on WXK_TAB; + # ensure we can still navigate properly, as maskededit mixin::OnChar assumes + # that event.Skip() will just work, but it doesn't: + if self._keyhandlers.has_key(key): + self._keyhandlers[key](event) + # else pass + else: +## dbg('calling OnChar()') + self._OnChar(event) else: event.Skip() # let mixin default KeyDown behavior occur +## dbg(indent=0) + + + def _OnDropdownSelect(self, event): + """ + This function appears to be necessary because dropdown selection seems to + manipulate the contents of the control in an inconsistent way, properly + changing the selection index, but *not* the value. (!) Calling SetSelection() + on a selection event for the same selection would seem like a nop, but it seems to + fix the problem. + """ +## dbg('MaskedComboBox::OnDropdownSelect(%d)' % event.GetSelection(), indent=1) + if self.replace_next_combobox_event: +## dbg('replacing EVT_COMBOBOX') + self.replace_next_combobox_event = False + self._OnAutoSelect(self._ctrl_constraints, self.correct_selection) + else: +## dbg('skipping EVT_COMBOBOX') + event.Skip() +## dbg(indent=0) - def OnSelectChoice(self, event): + def _OnSelectChoice(self, event): """ This function appears to be necessary, because the processing done on the text of the control somehow interferes with the combobox's @@ -496,7 +663,7 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): Override mixin (empty) autocomplete handler, so that autocompletion causes combobox to update appropriately. """ -## dbg('MaskedComboBox::OnAutoSelect', field._index, indent=1) +## dbg('MaskedComboBox::OnAutoSelect(%d, %d)' % (field._index, match_index), indent=1) ## field._autoCompleteIndex = match_index if field == self._ctrl_constraints: self.SetSelection(match_index) @@ -505,7 +672,7 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): MaskedComboBoxSelectEvent( self.GetId(), match_index, self ) ) self._CheckValid() ## dbg('field._autoCompleteIndex:', match_index) -## dbg('self.GetSelection():', self.GetSelection()) +## dbg('self.GetCurrentSelection():', self.GetCurrentSelection()) end = self._goEnd(getPosOnly=True) ## dbg('scheduling set of end position to:', end) # work around bug in wx 2.5 @@ -516,31 +683,93 @@ class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): def _OnReturn(self, event): """ - For wxComboBox, it seems that if you hit return when the dropdown is + For wx.ComboBox, it seems that if you hit return when the dropdown is dropped, the event that dismisses the dropdown will also blank the - control, because of the implementation of wxComboBox. So here, - we look and if the selection is -1, and the value according to - (the base control!) is a value in the list, then we schedule a + control, because of the implementation of wxComboBox. So this function + examines the selection and if it is -1, and the value according to + (the base control!) is a value in the list, then it schedules a programmatic wxComboBox.SetSelection() call to pick the appropriate - item in the list. (and then do the usual OnReturn bit.) + item in the list. (and then does the usual OnReturn bit.) """ ## dbg('MaskedComboBox::OnReturn', indent=1) -## dbg('current value: "%s"' % self.GetValue(), 'current index:', self.GetSelection()) - if self.GetSelection() == -1 and self.GetValue().lower().strip() in self._ctrl_constraints._compareChoices: - wx.CallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex) - +## dbg('current value: "%s"' % self.GetValue(), 'current selection:', self.GetCurrentSelection()) + if self.GetCurrentSelection() == -1 and self.GetValue().lower().strip() in self._ctrl_constraints._compareChoices: +## dbg('attempting to correct the selection to make it %d' % self._ctrl_constraints._autoCompleteIndex) +## wx.CallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex) + self.replace_next_combobox_event = True + self.correct_selection = self._ctrl_constraints._autoCompleteIndex event.m_keyCode = wx.WXK_TAB event.Skip() ## dbg(indent=0) + def _LostFocus(self): +## dbg('MaskedComboBox::LostFocus; Selection=%d, value="%s"' % (self.GetSelection(), self.GetValue())) + if self.GetCurrentSelection() == -1 and self.GetValue().lower().strip() in self._ctrl_constraints._compareChoices: +## dbg('attempting to correct the selection to make it %d' % self._ctrl_constraints._autoCompleteIndex) + wx.CallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex) + + class ComboBox( BaseMaskedComboBox, MaskedEditAccessorsMixin ): """ - This extra level of inheritance allows us to add the generic set of - masked edit parameters only to this class while allowing other - classes to derive from the "base" masked combobox control, and provide - a smaller set of valid accessor functions. + The "user-visible" masked combobox control, this class is + identical to the BaseMaskedComboBox class it's derived from. + (This extra level of inheritance allows us to add the generic + set of masked edit parameters only to this class while allowing + other classes to derive from the "base" masked combobox control, + and provide a smaller set of valid accessor functions.) + See BaseMaskedComboBox for available methods. """ pass +class PreMaskedComboBox( BaseMaskedComboBox, MaskedEditAccessorsMixin ): + """ + This class exists to support the use of 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.4 +## 1. Added handler for EVT_COMBOBOX to address apparently inconsistent behavior +## of control when the dropdown control is used to do a selection. +## NOTE: due to misbehavior of wx.ComboBox re: losing all concept of the +## current selection index if SetInsertionPoint() is called, which is required +## to support masked .SetValue(), this control is flaky about retaining selection +## information. I can't truly fix this without major changes to the base control, +## but I've tried to compensate as best I can. +## TODO: investigate replacing base control with ComboCtrl instead... +## 2. Fixed navigation in readonly masked combobox, which was not working because +## the base control doesn't do navigation if style=CB_READONLY|WANTS_CHARS. +## +## +## Version 1.3 +## 1. Made definition of "hack" GetMark conditional on base class not +## implementing it properly, to allow for migration in wx code base +## while taking advantage of improvements therein for some platforms. +## +## Version 1.2 +## 1. Converted docstrings to reST format, added doc for ePyDoc. +## 2. Renamed helper functions, vars etc. not intended to be visible in public +## interface to code. +## +## 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.