📄 intctrl.py
字号:
#----------------------------------------------------------------------------
# Name: wxPython.lib.intctrl.py
# Author: Will Sadkin
# Created: 01/16/2003
# Copyright: (c) 2003 by Will Sadkin
# RCS-ID: $Id: intctrl.py,v 1.6 2003/12/22 19:09:52 RD Exp $
# License: wxWindows license
#----------------------------------------------------------------------------
# NOTE:
# This was written to provide a standard integer edit control for wxPython.
#
# IntCtrl permits integer (long) values to be retrieved or set via
# .GetValue() and .SetValue(), and provides an EVT_INT() event function
# for trapping changes to the control.
#
# It supports negative integers as well as the naturals, and does not
# permit leading zeros or an empty control; attempting to delete the
# contents of the control will result in a (selected) value of zero,
# thus preserving a legitimate integer value, or an empty control
# (if a value of None is allowed for the control.) Similarly, replacing the
# contents of the control with '-' will result in a selected (absolute)
# value of -1.
#
# IntCtrl also supports range limits, with the option of either
# enforcing them or simply coloring the text of the control if the limits
# are exceeded.
#----------------------------------------------------------------------------
# 12/08/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o 2.5 Compatability changes
#
# 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o wxIntUpdateEvent -> IntUpdateEvent
# o wxIntValidator -> IntValidator
# o wxIntCtrl -> IntCtrl
#
import string
import types
import wx
#----------------------------------------------------------------------------
from sys import maxint
MAXINT = maxint # (constants should be in upper case)
MININT = -maxint-1
#----------------------------------------------------------------------------
# Used to trap events indicating that the current
# integer value of the control has been changed.
wxEVT_COMMAND_INT_UPDATED = wx.NewEventType()
EVT_INT = wx.PyEventBinder(wxEVT_COMMAND_INT_UPDATED, 1)
#----------------------------------------------------------------------------
# wxWindows' wxTextCtrl translates Composite "control key"
# events into single events before returning them to its OnChar
# routine. The doc says that this results in 1 for Ctrl-A, 2 for
# Ctrl-B, etc. However, there are no wxPython or wxWindows
# symbols for them, so I'm defining codes for Ctrl-X (cut) and
# Ctrl-V (paste) here for readability:
WXK_CTRL_X = (ord('X')+1) - ord('A')
WXK_CTRL_V = (ord('V')+1) - ord('A')
class IntUpdatedEvent(wx.PyCommandEvent):
def __init__(self, id, value = 0, object=None):
wx.PyCommandEvent.__init__(self, wxEVT_COMMAND_INT_UPDATED, id)
self.__value = value
self.SetEventObject(object)
def GetValue(self):
"""Retrieve the value of the control at the time
this event was generated."""
return self.__value
#----------------------------------------------------------------------------
class IntValidator( wx.PyValidator ):
"""
Validator class used with IntCtrl; handles all validation of input
prior to changing the value of the underlying wx.TextCtrl.
"""
def __init__(self):
wx.PyValidator.__init__(self)
self.Bind(wx.EVT_CHAR, self.OnChar)
def Clone (self):
return self.__class__()
def Validate(self, window): # window here is the *parent* of the ctrl
"""
Because each operation on the control is vetted as it's made,
the value of the control is always valid.
"""
return 1
def OnChar(self, event):
"""
Validates keystrokes to make sure the resulting value will a legal
value. Erasing the value causes it to be set to 0, with the value
selected, so it can be replaced. Similarly, replacing the value
with a '-' sign causes the value to become -1, with the value
selected. Leading zeros are removed if introduced by selection,
and are prevented from being inserted.
"""
key = event.KeyCode()
ctrl = event.GetEventObject()
value = ctrl.GetValue()
textval = wx.TextCtrl.GetValue(ctrl)
allow_none = ctrl.IsNoneAllowed()
pos = ctrl.GetInsertionPoint()
sel_start, sel_to = ctrl.GetSelection()
select_len = sel_to - sel_start
# (Uncomment for debugging:)
## print 'keycode:', key
## print 'pos:', pos
## print 'sel_start, sel_to:', sel_start, sel_to
## print 'select_len:', select_len
## print 'textval:', textval
# set defaults for processing:
allow_event = 1
set_to_none = 0
set_to_zero = 0
set_to_minus_one = 0
paste = 0
internally_set = 0
new_value = value
new_text = textval
new_pos = pos
# Validate action, and predict resulting value, so we can
# range check the result and validate that too.
if key in (wx.WXK_DELETE, wx.WXK_BACK, WXK_CTRL_X):
if select_len:
new_text = textval[:sel_start] + textval[sel_to:]
elif key == wx.WXK_DELETE and pos < len(textval):
new_text = textval[:pos] + textval[pos+1:]
elif key == wx.WXK_BACK and pos > 0:
new_text = textval[:pos-1] + textval[pos:]
# (else value shouldn't change)
if new_text in ('', '-'):
# Deletion of last significant digit:
if allow_none and new_text == '':
new_value = None
set_to_none = 1
else:
new_value = 0
set_to_zero = 1
else:
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
elif key == WXK_CTRL_V: # (see comments at top of file)
# Only allow paste if number:
paste_text = ctrl._getClipboardContents()
new_text = textval[:sel_start] + paste_text + textval[sel_to:]
if new_text == '' and allow_none:
new_value = None
set_to_none = 1
else:
try:
# Convert the resulting strings, verifying they
# are legal integers and will fit in proper
# size if ctrl limited to int. (if not,
# disallow event.)
new_value = ctrl._fromGUI(new_text)
if paste_text:
paste_value = ctrl._fromGUI(paste_text)
else:
paste_value = 0
new_pos = sel_start + len(str(paste_value))
# if resulting value is 0, truncate and highlight value:
if new_value == 0 and len(new_text) > 1:
set_to_zero = 1
elif paste_value == 0:
# Disallow pasting a leading zero with nothing selected:
if( select_len == 0
and value is not None
and ( (value >= 0 and pos == 0)
or (value < 0 and pos in [0,1]) ) ):
allow_event = 0
paste = 1
except ValueError:
allow_event = 0
elif key < wx.WXK_SPACE or key > 255:
pass # event ok
elif chr(key) == '-':
# Allow '-' to result in -1 if replacing entire contents:
if( value is None
or (value == 0 and pos == 0)
or (select_len >= len(str(abs(value)))) ):
new_value = -1
set_to_minus_one = 1
# else allow negative sign only at start, and only if
# number isn't already zero or negative:
elif pos != 0 or (value is not None and value < 0):
allow_event = 0
else:
new_text = '-' + textval
new_pos = 1
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
elif chr(key) in string.digits:
# disallow inserting a leading zero with nothing selected
if( chr(key) == '0'
and select_len == 0
and value is not None
and ( (value >= 0 and pos == 0)
or (value < 0 and pos in [0,1]) ) ):
allow_event = 0
# disallow inserting digits before the minus sign:
elif value is not None and value < 0 and pos == 0:
allow_event = 0
else:
new_text = textval[:sel_start] + chr(key) + textval[sel_to:]
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
else:
# not a legal char
allow_event = 0
if allow_event:
# Do range checking for new candidate value:
if ctrl.IsLimited() and not ctrl.IsInBounds(new_value):
allow_event = 0
elif new_value is not None:
# ensure resulting text doesn't result in a leading 0:
if not set_to_zero and not set_to_minus_one:
if( (new_value > 0 and new_text[0] == '0')
or (new_value < 0 and new_text[1] == '0')
or (new_value == 0 and select_len > 1 ) ):
# Allow replacement of leading chars with
# zero, but remove the leading zero, effectively
# making this like "remove leading digits"
# Account for leading zero when positioning cursor:
if( key == wx.WXK_BACK
or (paste and paste_value == 0 and new_pos > 0) ):
new_pos = new_pos - 1
wx.CallAfter(ctrl.SetValue, new_value)
wx.CallAfter(ctrl.SetInsertionPoint, new_pos)
internally_set = 1
elif paste:
# Always do paste numerically, to remove
# leading/trailing spaces
wx.CallAfter(ctrl.SetValue, new_value)
wx.CallAfter(ctrl.SetInsertionPoint, new_pos)
internally_set = 1
elif (new_value == 0 and len(new_text) > 1 ):
allow_event = 0
if allow_event:
ctrl._colorValue(new_value) # (one way or t'other)
# (Uncomment for debugging:)
## if allow_event:
## print 'new value:', new_value
## if paste: print 'paste'
## if set_to_none: print 'set_to_none'
## if set_to_zero: print 'set_to_zero'
## if set_to_minus_one: print 'set_to_minus_one'
## if internally_set: print 'internally_set'
## else:
## print 'new text:', new_text
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -