combobox.py
来自「Wxpython Implemented on Windows CE, Sou」· Python 代码 · 共 672 行 · 第 1/2 页
PY
672 行
#----------------------------------------------------------------------------
# Name: masked.combobox.py
# Authors: Will Sadkin
# Email: wsadkin@nameconnector.com
# Created: 02/11/2003
# Copyright: (c) 2003 by Will Sadkin, 2003
# RCS-ID: $Id: combobox.py,v 1.8 2005/04/08 21:31:25 RD Exp $
# License: wxWidgets license
#----------------------------------------------------------------------------
#
# This masked edit class allows for the semantics of masked controls
# to be applied to combo boxes.
#
#----------------------------------------------------------------------------
"""
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=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)
self.__selection = selection
self.SetEventObject(object)
def GetSelection(self):
"""Retrieve the value of the control at the time
this event was generated."""
return self.__selection
class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ):
"""
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,
size = wx.DefaultSize,
choices = [],
style = wx.CB_DROPDOWN,
validator = wx.DefaultValidator,
name = "maskedComboBox",
setupEventHandling = True, ## setup event handling by default):
**kwargs):
kwargs['choices'] = choices ## set up maskededit to work with choice list too
## 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.__init__(self, parent, id, value='',
pos=pos, size = size,
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())
width = self.GetSize().width
height = self.GetBestSize().height
self.SetBestFittingSize((width, height))
if value:
# ensure value is width of the mask of the control:
if self._ctrl_constraints._alignRight:
value = value.rjust(self._masklength)
else:
value = value.ljust(self._masklength)
if self.__readonly:
self.SetStringSelection(value)
else:
self._SetInitialValue(value)
self._SetKeycodeHandler(wx.WXK_UP, self._OnSelectChoice)
self._SetKeycodeHandler(wx.WXK_DOWN, self._OnSelectChoice)
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._OnKeyDownInComboBox ) ## 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
def __repr__(self):
return "<MaskedComboBox: %s>" % self.GetValue()
def _CalcSize(self, size=None):
"""
Calculate automatic size if allowed; augment base mixin function
to account for the selector button.
"""
size = self._calcSize(size)
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.SetBestFittingSize((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):
"""
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):
## 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 _GetValue(self):
"""
Allow mixin to get the raw value of the control with this function.
REQUIRED by any class derived from MaskedEditMixin.
"""
return self.GetValue()
def _SetValue(self, value):
"""
Allow mixin to set the raw value of the control with this function.
REQUIRED by any class derived from MaskedEditMixin.
"""
# For wxComboBox, ensure that values are properly padded so that
# if varying length choices are supplied, they always show up
# in the window properly, and will be the appropriate length
# to match the mask:
if self._ctrl_constraints._alignRight:
value = value.rjust(self._masklength)
else:
value = value.ljust(self._masklength)
# Record current selection and insertion point, for undo
self._prevSelection = self._GetSelection()
self._prevInsertionPoint = self._GetInsertionPoint()
wx.ComboBox.SetValue(self, value)
# text change events don't always fire, so we check validity here
# to make certain formatting is applied:
self._CheckValid()
def SetValue(self, value):
"""
This function redefines the externally accessible .SetValue to be
a smart "paste" of the text in question, so as not to corrupt the
masked control. NOTE: this must be done in the class derived
from the base wx control.
"""
if not self._mask:
wx.ComboBox.SetValue(value) # revert to base control behavior
return
# else...
# empty previous contents, replacing entire value:
self._SetInsertionPoint(0)
self._SetSelection(0, self._masklength)
if( len(value) < self._masklength # value shorter than control
and (self._isFloat or self._isInt) # and it's a numeric control
and self._ctrl_constraints._alignRight ): # and it's a right-aligned control
# try to intelligently "pad out" the value to the right size:
value = self._template[0:self._masklength - len(value)] + value
## dbg('padded value = "%s"' % value)
# For wxComboBox, ensure that values are properly padded so that
# if varying length choices are supplied, they always show up
# in the window properly, and will be the appropriate length
# to match the mask:
elif self._ctrl_constraints._alignRight:
value = value.rjust(self._masklength)
else:
value = value.ljust(self._masklength)
# make SetValue behave the same as if you had typed the value in:
try:
value, replace_to = self._Paste(value, raise_on_invalid=True, just_return_value=True)
if self._isFloat:
self._isNeg = False # (clear current assumptions)
value = self._adjustFloat(value)
elif self._isInt:
self._isNeg = False # (clear current assumptions)
value = self._adjustInt(value)
elif self._isDate and not self.IsValid(value) and self._4digityear:
value = self._adjustDate(value, fixcentury=True)
except ValueError:
# If date, year might be 2 digits vs. 4; try adjusting it:
if self._isDate and self._4digityear:
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
self._SetValue(value)
#### dbg('queuing insertion after .SetValue', replace_to)
wx.CallAfter(self._SetInsertionPoint, replace_to)
wx.CallAfter(self._SetSelection, replace_to, replace_to)
def _Refresh(self):
"""
Allow mixin to refresh the base control with this function.
REQUIRED by any class derived from MaskedEditMixin.
"""
wx.ComboBox.Refresh(self)
def Refresh(self):
"""
This function redefines the externally accessible .Refresh() to
validate the contents of the masked control as it refreshes.
NOTE: this must be done in the class derived from the base wx control.
"""
self._CheckValid()
self._Refresh()
def _IsEditable(self):
"""
Allow mixin to determine if the base control is editable with this function.
REQUIRED by any class derived from MaskedEditMixin.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?