在MFC里需要获取文本输入时经常会用到CEdit或者它的子类可以通过设置它的Edit Control Styles来控制Edit控件的一些行为例如说设置ES_NUMBER标识使控件只允许接受数字(虽然可以复制粘贴非数字字符串到这个控件中)
在NET中用于获取文本输入的控件是TextBox但TextBox本身并不包含可以直接调用的方法或属性来将其设置为只接受数字输入这个问题有好几种方法来解决
继承TextBox并覆盖其CreateParams属性对该属性的Style成员添加ES_NUMBER标识 这个方法与MFC中用Edit Control Styles来初始化CEdit一样可以说是最偷懒的方法
自行监听TextBox的KeyDown事件实现输入验证(但不保证复制粘贴输入的正确性) 其实设置ES_NUMBER做的也是这件事如果要实现的功能与Windows控件中默认的一样的话没必要自己监听KeyDown事件如果需要些额外的功能例如说允许输入负数十六进制数等默认没有的功能时则监听KeyDown事件是个有效的方式
使用第三方编写的继承自TextBox的控件 这是拥有不重复发明轮子精神的人们的做法既然获取数字输入应该是个常见问题之前也肯定有人解决过那么利用别人的解决方案就行
光是CodeProject上就有好几个与这个相关的实现
Validating Edit Controls包括了NumericTextBoxAlphanumericTextBoxDateTextBox等许多版本的TextBox子类值得一看
A numeric textbox with a twist
Numeric TextBox Allow your users to enter numeric data the easy way
使用MaskedTextBox 控件 这是NET Framework自带的一个TextBox的子类实现了一个带过滤功能的TextBox可以自定义接受的输入内容的格式只要设置其string Mask属性即可如果觉得ES_NUMBER的功能不够用而自行监听KeyDown事件来做验证不够优雅的话这个MaskedTextBox绝对是值得考虑的选择例如说要接受到的数字只要把Mask属性设为就行(意味着六位的可选十进制数字一个小数点和两位必须输入的小数)MSDN上对这个控件有个简单的walkthrough
使用NumericUpDown控件 当需要获取简单数字输入时在NET世界中最直接的方法不是去想办法与TextBox搏斗而应该换个控件来用——NumericUpDown这个控件不但能接受来自键盘的数字输入还有一组上下箭头来步进它包含了许多可以设置的属性例如显示分隔符逗号的bool ThousandsSeparator控制最小/最大值的decimal Minimum/decimal Maximum属性等
下面对这几种解决方法的其中一些稍微讨论一下
一继承TextBox并覆盖其CreateParams属性
使用这种方法的NumericTextBox的实现(代码的第行)及用例
C#代码
public class NumericTextBox : SystemWindowsFormsTextBox
{
private const int ES_NUMBER = x; // ( defined in WinUserh )
protected override SystemWindowsFormsCreateParams CreateParams {
get {
SystemWindowsFormsCreateParams cp = baseCreateParams;
cpStyle |= ES_NUMBER;
return cp;
}
}
}
#region use case code sample
sealed class TestForm : SystemWindowsFormsForm
{
private NumericTextBox m_ntxt;
public TestForm() {
InitializeComponent();
}
private void InitializeComponent() {
thism_ntxt = new NumericTextBox();
thism_ntxtDock = SystemWindowsFormsDockStyleFill;
thisClientSize = new SystemDrawingSize( );
thisControlsAdd(thism_ntxt);
thisPerformLayout();
}
[SystemSTAThread]
static void Main(string[] args) {
SystemWindowsFormsApplicationEnableVisualStyles();
SystemWindowsFormsApplicationSetCompatibleTextRenderingDefault(false);
SystemWindowsFormsApplicationRun(new TestForm());
}
}
#endregion
运行程序在输入任意非的字符时的样子
(截图反映的是在我的简体中文Windows XP上的运行效果若系统语言不是简体中文的话会根据系统语言而不同)
如果这个文本框已经能满足需求就没必要自己监听KeyDown事件那么麻烦了
二自行监听KeyDown事件
可以参考CodeProject上Numeric TextBox Allow your users to enter numeric data the easy way的实现方式基本原理就是在KeyDown的响应方法中对eKeyCode进行判断如果输入不满足条件则设置某个标识然后再KeyPress的响应方法里设置eHandled = true来取消该次事件
最简单来说类似这样
C#代码
using System;
using SystemDrawing;
using SystemWindowsForms;
sealed class TestForm : Form
{
private TextBox m_textBox;
private bool m_nonNumberEntered = false;
public TestForm() {
InitializeComponent();
}
private void InitializeComponent() {
thism_textBox = new TextBox();
thism_textBoxDock = DockStyleFill;
thism_textBoxKeyDown += m_textBox_KeyDown;
thism_textBoxKeyPress += m_textBox_KeyPress;
thisClientSize = new Size( );
thisControlsAdd(thism_textBox);
thisPerformLayout();
}
private void m_textBox_KeyDown(object sender KeyEventArgs e) {
// Initialize the flag to false
m_nonNumberEntered = false;
// Determine whether the keystroke is a number from the top of the keyboard
if (eKeyCode < KeysD || eKeyCode > KeysD) {
// Determine whether the keystroke is a number from the keypad
if (eKeyCode < KeysNumPad || eKeyCode > KeysNumPad) {
// Determine whether the keystroke is a backspace
if(eKeyCode != KeysBack) {
// A nonnumerical keystroke was pressed
// Set the flag to true and evaluate in KeyPress event
m_nonNumberEntered = true;
}
}
}
}
private void m_textBox_KeyPress(object sender KeyPressEventArgs e) {
// Check for the flag being set in the KeyDown event
if (m_nonNumberEntered) {
// Stop the character from being entered into the control
// since it is nonnumerical
eHandled = true;
}
}
[STAThread]
static void Main(string[] args) {
ApplicationEnableVisualStyles();
ApplicationSetCompatibleTextRenderingDefault(false);
ApplicationRun(new TestForm());
}
}
(判断逻辑来自KeyEventArgs在MSDN文档上的范例代码)
得到的文本框外观与一般的TextBox没区别只是无法由键盘输入数字字符以外的字符要避免任意字符串被复制粘贴进来的话要另外做些判断这里就不详细写了
三使用MaskedTextBox
使用例子
C#代码
using System;
using SystemWindowsForms;
sealed class TestForm : Form
{
private MaskedTextBox m_maskedTextBox;
private ToolTip m_toolTip;
public TestForm() {
InitializeComponent();
}
private void InitializeComponent() {
thism_maskedTextBox = new MaskedTextBox();
thism_maskedTextBoxMask = ;
thism_maskedTextBoxDock = DockStyleFill;
thism_maskedTextBoxMaskInputRejected += m_maskedTextBox_InputRejected;
thism_maskedTextBoxKeyDown += m_maskedTextBox_KeyDown;
thism_toolTip = new ToolTip();
thisClientSize = new Size( );
thisControlsAdd(thism_maskedTextBox);
thisPerformLayout();
}
private void m_maskedTextBox_InputRejected(object sender
MaskInputRejectedEventArgs e) {
toolTipToolTipTitle = Invalid Input;
toolTipShow(Only digits () are allowed
m_maskedTextBox m_maskedTextBoxLocation );
}
private void m_maskedTextBox_KeyDown(object sender KeyEventArgs e) {
m_toolTipHide(maskedTextBox);
}
[STAThread]
static void Main(string[] args) {
ApplicationEnableVisualStyles();
ApplicationSetCompatibleTextRenderingDefault(false);
ApplicationRun(new TestForm());
}
}
这段代码是手写的要是用VS/VS的设计器的话这个例子的所有功能都能直接在设计器里指定
输入内容(可以看到分隔符都不需要自己写了已经写好在输入框里只要填空就行)
输入内容不符合Mask属性指定的模式时
四使用NumericUpDown
C#代码
using System;
using SystemDrawing;
using SystemWindowsForms;
sealed class TestForm : Form
{
private NumericUpDown m_numericUpDown;
public TestForm() {
InitializeComponent();
}
private void InitializeComponent() {
thism_numericUpDown = new NumericUpDown();
thism_numericUpDownValue = ;
thism_numericUpDownDock = DockStyleFill;
thism_numericUpDownThousandsSeparator = true;
thism_numericUpDownMaximum = intMaxValue;
thisClientSize = new Size( );
thisControlsAdd(thism_numericUpDown);
thisPerformLayout();
}
[SystemSTAThread]
static void Main(string[] args) {
ApplicationEnableVisualStyles();
ApplicationSetCompatibleTextRenderingDefault(false);
ApplicationRun(new TestForm());
}
}
这段代码是手写的要是用VS/VS的设计器的话这个例子的所有功能都能直接在设计器里指定
NumericUpDown的内容的值可以用Value属性来设置或获取类型为decimal
截图(输入不符合要求的字符时默认行为是beep一下没有工具条的提示)