Click here to Skip to main content
15,887,288 members
Articles / Desktop Programming / Windows Forms
Article

DataGridViewColumn Hosting MaskedTextBox

Rate me:
Please Sign up or sign in to vote.
4.55/5 (21 votes)
12 May 2008CPOL3 min read 221.6K   7.9K   68   39
How to host a MaskedTextBox in a DataGridViewColumn
Image 1

Introduction

You want to use a MaskedTextBox in your DataGridViewColumn? Here it is. Add a DataGridViewMaskedTextColumn to your DataGridView and set the Mask string. Then you get a MaskedTextBox using this Mask as EditingControl.

Background

The .NET Framework contains for DataGridView columns a standard TextBox only. By data binding, it's no problem to restrict the input to numbers, e.g. TextBox.CharacterCasing can be set by DataGridView.EditingControlShowing event. More complex restrictions are available in MaskedTextBox. Therefore it's useful to host a MaskedTextBox in a DataGridViewColumn.

Yildirim Kocdag's solution Generic DataGridView (updated 24th January, 2008) contains a MaskedTextColumn, but there's a problem if one needs to add two (or more) MaskedTextColumns with different Mask strings: In this case, the control keeps one mask only because the DataGridView contains one specific EditingControl for all columns.

Microsoft's example How to: Host Controls in Windows Forms DataGridView Cells gives a simple way how to create your own DataGridViewColumn class. But it's insufficient because the Mask property needs to implement the Clone method, while the example doesn't need to. I found my solution after I studied all the original DataGridView classes using Lutz Roeder's Reflector.

Using the Code

The MaskedTextColumn solution consists of three combined classes, added by an attribute class.

The <code>ReferencedDescriptionAttribute class is used in the designer to call an existing description. See details here.

The MaskedText classes are included into your own ExtendedControls.dll assembly, or you store the prepared DLL directly. Add a reference to this assembly, and you can use the DataGridViewMaskedTextColumn. You need to use this class only; the DataGridViewMaskedTextCell class and the DataGridViewMaskedTextControl class are used automatically by the framework itself.

Working by Code

Add a DataGridViewMaskedTextColumn to your DataGridView like any other DataGridViewColumn and set the Mask property:

C#
using JThomas.Controls;

//  create a new column and set a mask using a minimum of 4 and a maximum of 7 digits
DataGridViewMaskedTextColumn column = new DataGridViewMaskedTextColumn("0000999");
column.DataPropertyName = "Number";
column.HeaderText = "Nummer";     //  German text
column.Name = "column";
column.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
column.Width = 70;

//  add this column to the DataGridView dgv
dgv.Columns.Add(column);

Working by Designer

After adding the reference to the ExtendedControls.dll assembly, you can open the IDE and select a DataGridViewMaskedTextColumn as DataGridViewColumn – either in the Edit Columns window, like in the image above, or in the Add Column window. There you can set the Mask string.

Mask Details

Check all Mask possibilities in the SDK documentation for the MaskedTextBox.Mask property.

How It Works

As shown in Microsoft's example, we have to define three classes.

DataGridViewMaskedTextColumn

This class is derived from DataGridViewColumn in the same way as the original DataGridViewTextBoxColumn class. We must implement our own derivation because the MaxInputLength property is not valid in MaskedTextBox instances. It contains the standard constructor and another constructor setting the Mask string directly:

C#
//  use the Bitmap of MaskedTextBox
[System.Drawing.ToolboxBitmap(typeof(System.Windows.Forms.MaskedTextBox))]
public class DataGridViewMaskedTextColumn : DataGridViewColumn
{
        public DataGridViewMaskedTextColumn() : this(String.Empty)   {}

        public DataGridViewMaskedTextColumn(string maskString)
                : base(new DataGridViewMaskedTextCell())
        {
                SortMode = DataGridViewColumnSortMode.Automatic;
                Mask = maskString;
        }

Some methods and properties are derived like in DataGridViewTextBoxColumn class:

C#
public override string ToString() { ... }
public override DataGridViewCell CellTemplate { get; set; }
public new DataGridViewColumnSortMode SortMode { get; set; }
private DataGridViewMaskedTextCell MaskedTextCellTemplate { get; }

We must add the Clone method for using the Mask property:

C#
public override object Clone()
{
    DataGridViewMaskedTextColumn col = (DataGridViewMaskedTextColumn)base.Clone();
    col.Mask = Mask;
    col.CellTemplate = (DataGridViewMaskedTextCell)this.CellTemplate.Clone();
    return col;
}

The main work is to use the Mask string in each DataGridViewMaskedTextCell of this column. Therefore we may not only define a simple getter and setter, but must store the value in each contained DataGridViewCell like DataGridViewTextBoxColumn does for its MaxInputLength property.

C#
[Category("Masking")]
//  use the MaskedTextBox.Mask description
[JThomas.Extensions.ReferencedDescription(typeof
    (System.Windows.Forms.MaskedTextBox),"Mask")]
public string Mask
{
    get     { ... }
    set     {
    if (Mask != value)
    {
        MaskedTextCellTemplate.Mask = value;
        if (base.DataGridView != null)
        {
            DataGridViewRowCollection rows = base.DataGridView.Rows;
            int count = rows.Count;
            for (int i = 0; i < count; i++)
            {
                DataGridViewMaskedTextCell cell
                    = rows.SharedRow(i).Cells[base.Index]
                    as DataGridViewMaskedTextCell;
                if (cell != null)
                    cell.Mask = value;
            }
        }
    }
    }
}

DataGridViewMaskedTextCell

This class can be derived from the DataGridViewTextBoxCell class because the behaviour in an inactive cell doesn't differ. It's only necessary to override some methods and properties and adapt to the current classes and names. The main work is to add the Clone method and the Mask property in a simple way.

C#
public override object Clone()
{
    DataGridViewMaskedTextCell cell = base.Clone() as DataGridViewMaskedTextCell;
    cell.Mask = this.Mask;
    return cell;
}

private string mask;

public string Mask {
    get { return mask == null ? String.Empty : mask; }
    set { mask = value; }
}

DataGridViewMaskedTextControl

This class must be derived from the <code><code><code>MaskedTextBox class implementing the <code><code><code>IDataGridViewEditingControl interface. Most members are adapted in the same way like Microsoft's example does. It's only necessary to use string values instead of object and MaskedTextBox.Text property instead of DateTimePicker.Value property.

The most important definitions are the following ones:

C#
public object EditingControlFormattedValue
{
    get    {    return Text;        }
    set    {    if (value is string)
            Text = (string)value;
    }
}

public void ApplyCellStyleToEditingControl(
    DataGridViewCellStyle dataGridViewCellStyle)
{
    Font = dataGridViewCellStyle.Font;
    //    get the current cell to use the specific mask string
    DataGridViewMaskedTextCell cell
        = dataGridView.CurrentCell as DataGridViewMaskedTextCell;
    if (cell != null) {
        Mask = cell.Mask;
    }
}

public void PrepareEditingControlForEdit(bool selectAll)
{
    if (selectAll)
        SelectAll();
    else {
        SelectionStart = 0;
        SelectionLength = 0;
    }
}

// MaskedTextBox event
protected override void OnTextChanged(System.EventArgs e)
{
    base.OnTextChanged(e);
    EditingControlValueChanged = true;
    if (EditingControlDataGridView != null) {
        EditingControlDataGridView.CurrentCell.Value = Text;
    }
}

Points of Interest

TextBox.CharacterCasing doesn't need a DataGridViewMaskedTextColumn, but can be embedded as follows:

C#
void DgvEditingControlShowing
    (object sender, DataGridViewEditingControlShowingEventArgs e)
{
        if (e.Control is TextBox) {
                TextBox box = e.Control as TextBox;
                // example: 2<sup>nd</sup> column requires upper case
                box.CharacterCasing
                        = dgv.CurrentCell.ColumnIndex == 1
                        ? CharacterCasing.Upper
                        : CharacterCasing.Normal;
        }
}  

It would be possible to insert a DefaultValue property into the DataGridViewMaskedText solution. On the other side, it's useful to connect default values to data instances. You should better use DataColumn.DefaultValue property, or DataTable.TableNewRow event, or DataGridView.RowsAdded event, or BindingNavigator.AddNewItem.Click event, or something else like that.

History

  • 05/04/2008: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralBug found Pin
Dennis Betten9-Dec-08 23:11
Dennis Betten9-Dec-08 23:11 
GeneralRe: Bug found Pin
Dennis Betten10-Dec-08 2:58
Dennis Betten10-Dec-08 2:58 
GeneralRe: Bug found Pin
debeysm12-Apr-11 1:31
debeysm12-Apr-11 1:31 
GeneralRe: Bug found Pin
dongvan21-Sep-11 9:25
dongvan21-Sep-11 9:25 
GeneralRe: Bug found Pin
StacyOW22-Aug-14 4:16
StacyOW22-Aug-14 4:16 
QuestionDifferences between this solution and MS MaskedTextBoxColumn? Pin
kaborka15-Jul-08 11:58
kaborka15-Jul-08 11:58 
AnswerRe: differences are not important Pin
J.Thomas16-Jul-08 4:21
J.Thomas16-Jul-08 4:21 
Generalterrible that theire still is no good inputmask in java and visual studio ... like theire was in clipper ... Pin
jckoenen20-Jun-08 13:59
jckoenen20-Jun-08 13:59 
I have found a good articel voor inputmask in java ... its called textgroup.

Within a textgroup you have textfields.
every textfield has a number (first to last) so you know were to go after tab-key or down-key or after last-character is inputted Wink | ;-)
every textfield can have a mask (99/99/9999 for example for date)
every textfield can have a validator or array of validators. A date has 3 validaters .. 1=day, 2=month, 3=year

Stupid that Visual Studio 2008 / java etcetera has no control to make it easy to make such a textgroup.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package a;

/**
*
* @author okt07
*/
/*
public class TextGroup {

}
*/
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;

/*
** Group multiple MaskTextFields and JLabels to act like
** a single component.
**
** 1) A MaskTextField is a customized JTextField.
** 2) The focus manager will only set focus on the first
** text field added to the group.
** 3 The up/down/right/left arrow keys can be used to
** move within the group.
** 4) The getText() method returns the text of all
** components added to the group.
** 5) The getData() method returns the text of the
** text fields added to the group.
*/
public class TextGroup extends JPanel implements KeyListener {

/**
*
*/
public final static int TAB_NEXT = 1;
public final static int TAB_PREVIOUS = -1;
public final static Border DEFAULT_BORDER = UIManager.getBorder("TextField.border");
public final static Color DEFAULT_BACKGROUND = UIManager.getColor("TextField.background");
public final static Font DEFAULT_FONT = new Font("monospaced", Font.PLAIN, 12);
public final static Color DEFAULT_MASK_COLOR = Color.gray;
public final static boolean DEFAULT_DISPLAY_PARTIAL_MASK = true;
private static Border labelBorder = new EmptyBorder(0, 5, 0, 5);
private String delimiters;
private Color maskColor = DEFAULT_MASK_COLOR;
private boolean displayPartialMask = DEFAULT_DISPLAY_PARTIAL_MASK;
private MaskTextField firstField;
private List maskTextFields;
private StringBuffer text = new StringBuffer(16);

/*
** Convenience constructors
*/
// yyyy/mm/dd, "/" maar ook: "(###)___-____", "()-" =3delimiters
public TextGroup(String mask, String delimiters) {
this(mask, delimiters, null, null);
}

TextGroup(String mask, String delimiters, FieldValidator validator) {
this(mask, delimiters, validator, null);
}

TextGroup(String mask, String delimiters, FieldValidator[] validators) {
this(mask, delimiters, null, validators);
}

/*
** Complete constructer
*/
TextGroup(String mask, String delimiters, FieldValidator validator, FieldValidator[] validators) {
this.delimiters = delimiters;
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
setBorder(DEFAULT_BORDER);
setBackground(DEFAULT_BACKGROUND);
setFont(DEFAULT_FONT);
maskTextFields = new ArrayList();

// Parse the mask into mask text fields and labels

StringTokenizer st = new StringTokenizer(mask, delimiters, true);
int tokenCount = 0;

while (st.hasMoreTokens()) {
String token = st.nextToken();

if (delimiters.indexOf(token) == -1) {
FieldValidator fv = getNextValidator(tokenCount, validator, validators);
addTextField(token, fv);
tokenCount++;
} else {
addLabel(token);
}
}
}

/*
** When a single FieldValidator is available it is used for all text fields.
** When multiple FieldValidators are available use validator corresponding to current token.
*/
private FieldValidator getNextValidator(int tokenCount, FieldValidator validator, FieldValidator[] validators) {
if (validator != null) {
return validator;
}

if (validators != null && tokenCount < validators.length) {
return validators[tokenCount];
} else {
return null;
}
}

/*
** Create a mask text field and add it to the panel
*/
@SuppressWarnings("unchecked")
MaskTextField addTextField(String mask, FieldValidator validator) {
MaskTextField textField = new MaskTextField(mask.length(), mask);
// uncomment the following line when using JDK1.3
// textField.setFocusTraversable( false );
textField.setFont(null);
textField.setBorder(null);
textField.setOpaque(false);
textField.setForeground(null);
textField.setParent(this);
textField.setValidator(validator);
textField.addKeyListener(this);
//jk:
textField.setColumns(textField.getColumns());
System.out.println(textField.getColumns());
System.out.println(mask);

// First mask field created can accept focus from the Focus Manager

if (maskTextFields.size() == 0) {
textField.setFocusTraversable(true);
}

maskTextFields.add(textField);

super.add(textField);
return textField;
}

/*
** Create a label and add it to the panel
*/
public JLabel addLabel(String delimiter) {
JLabel label = new JLabel(delimiter);
super.add(label);

label.setBorder(labelBorder);
label.setFont(null);

return label;
}

/*
**
*/
public void setText(String delimitedData) {
// Parse out the data from the delimited string

StringTokenizer st = new StringTokenizer(delimitedData, delimiters, true);
int tokenCount = 0;

while (st.hasMoreTokens()) {
String token = st.nextToken();

if (delimiters.indexOf(token) == -1) {
if (tokenCount < maskTextFields.size()) {
setText(tokenCount, token);
}

tokenCount++;
}
}
}

public void setText(int position, String text) {
if (position < maskTextFields.size()) {
((MaskTextField) maskTextFields.get(position)).setText(text);
}
}

/*
** Return the text with delimiters
*/
public String getText() {
return getComponentText(true);
}

public String getText(int position) {
if (position < maskTextFields.size()) {
return ((MaskTextField) maskTextFields.get(position)).getText();
} else {
return "";
}
}

/*
** Return the text without delimiters
*/
public String getData() {
return getComponentText(false);
}

/*
** Methods to control the mask text color
*/
public void setMaskColor(Color color) {
maskColor = color;
}

public Color getMaskColor() {
return maskColor;
}

/*
** Control how the background mask is rendered
** true: as characters are entered a partial mask is displayed
** false: once the first character is entered no mask is displayed
*/
public void setDisplayPartialMask(boolean value) {
displayPartialMask = value;
}

public boolean isDisplayPartialMask() {
return displayPartialMask;
}

/*
** Append the text from the individual components
** to form the text for the group component.
*/
private String getComponentText(boolean delimiterRequired) {
text.setLength(0);
Component[] components = getComponents();

for (int i = 0; i < components.length; i++) {
if (components[i] instanceof JTextField) {
JTextField textField = (JTextField) components[i];
text.append(textField.getText());
}

if (delimiterRequired && components[i] instanceof JLabel) {
JLabel label = (JLabel) components[i];
text.append(label.getText());
}
}

return text.toString();
}

/*
** Set focus on the next/previous text field
*/
public void tab(JTextField textField, int direction) {
Component[] components = getComponents();

// find the text field that currently has focus

int i = 0;

while (components[i] != textField) {
i++;
}

// find the next/previous text field on the panel

do {
i = (i + direction + components.length) % components.length;
} while (!(components[i] instanceof JTextField));

// set focus on the text field

components[i].requestFocus();
}

// Implement KeyListener
// Override the default behaviour of certain keys

public void keyPressed(KeyEvent e) {
JTextField textField = (JTextField) e.getSource();

switch (e.getKeyCode()) {
// tab to next text field

case KeyEvent.VK_UP:
tab(textField, TAB_NEXT);
break;

// tab to previous text field

case KeyEvent.VK_DOWN:
tab(textField, TAB_PREVIOUS);
break;

// move to next character or tab to next field

case KeyEvent.VK_RIGHT:
if (textField.getCaretPosition() == textField.getDocument().getLength()) {
tab(textField, TAB_NEXT);
e.consume();
}
break;

// move to previous character or tab to previous field

case KeyEvent.VK_LEFT:
if (textField.getCaretPosition() == 0) {
tab(textField, TAB_PREVIOUS);
e.consume();
}
break;
}
}

public void keyTyped(KeyEvent e) {
}

public void keyReleased(KeyEvent e) {
}

/*
** Test the class
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(0, 2));
//JPanel panel = new JPanel();
frame.setContentPane(panel);

// add date with no validation
final TextGroup date1 = new TextGroup("YYYY/MM/DD", "/");
date1.setBackground(Color.yellow);
date1.setForeground(Color.red);
panel.add(new JLabel("Date - not validated:"));
panel.add(date1);

JButton textButton = new JButton("Validate Date");
textButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {
System.out.println(date1.getText(0)); // get text from first field
System.out.println(date1.getData()); // get text, excluding delimiters
String text = date1.getText(); // get text, including delimeters
System.out.print(text);
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
df.setLenient(false);
df.parse(text);
System.out.println(" is valid");
} catch (Exception e2) {
System.out.println(" is invalid");
}
}
});
panel.add(new JLabel(""));
panel.add(textButton);

// add date with numeric validation
FieldValidator[] validators = new FieldValidator[3];
validators[0] = new IntegerValidator(1900, 2010);
validators[1] = new IntegerValidator(1, 12, 2);
validators[2] = new IntegerValidator(1, 31, 2);
TextGroup date2 = new TextGroup("YYYY/MM/DD", "/", validators);
date2.setDisplayPartialMask(false);
date2.setMaskColor(Color.red);
panel.add(new JLabel("Date - validated:"));
panel.add(date2);

// add phone number validate for integer characters
FieldValidator numeric = new IntegerValidator();
TextGroup phone = new TextGroup("(###)___-____", "()-", numeric);
panel.add(new JLabel("Phone Number:"));
panel.add(phone);

// add IP address
IntegerValidator ipv = new IntegerValidator(1, 255);
TextGroup ip = new TextGroup(" . . . ", ".", ipv);
ip.setText("1.2.3");
ip.setText(3, "4");
panel.add(new JLabel("IP Address:"));
panel.add(ip);

// add signed integer field
IntegerValidator signed = new IntegerValidator(-100, 100);
signed.setSignRequired(IntegerValidator.ALWAYS);
TextGroup signedField = new TextGroup("+ ", "", signed);
panel.add(new JLabel("Signed Integer:"));
panel.add(signedField);

// add postal code as stand alone MaskTextField
MaskTextField postalCode = new MaskTextField(6, "");
postalCode.setValidator(numeric);
panel.add(new JLabel("Postal Code:"));
panel.add(postalCode);

// add stand alone MaskTextField
MaskTextField name = new MaskTextField(20, "First Name");
name.setMaskColor(Color.blue);
name.setDisplayPartialMask(false);
panel.add(new JLabel("Masked First Name:"));
panel.add(name);

frame.pack();
frame.setVisible(true);
}
}

/*
** Customized JTextField with the following properties:
**
** 1) Text automatically selected when focus gained
** 2) Control for the number of characters allowed
** 3) Automatic tab when text field is full
** 4) Optional mask displayed in text field before entering data
** 5) Optional character validation can be added
** 6) ToolTip will display validation error message
*/
class MaskTextField extends JTextField
implements DocumentListener, FocusListener, KeyListener {

private TextGroup parent;
private String mask;
private Color maskColor = TextGroup.DEFAULT_MASK_COLOR;
private boolean displayPartialMask = TextGroup.DEFAULT_DISPLAY_PARTIAL_MASK;
private boolean isFocusTraversable = true;
private FieldValidator validator;
private StringBuffer textBuffer = new StringBuffer();

public MaskTextField(int size, String mask) {
super(size);
setMask(mask);

if (mask.trim().length() == 0) {
setMask(null);
}

getDocument().addDocumentListener(this);
addFocusListener(this);
addKeyListener(this);
}

/*
** Parent is set when this MaskTextField is part of a group
*/
public void setParent(TextGroup parent) {
this.parent = parent;
}

/*
** Text displayed in the background of the component
*/
public void setMask(String mask) {
this.mask = mask;
}

public String getMask() {
return mask;
}

/*
** Methods to control the mask text color
*/
public void setMaskColor(Color color) {
maskColor = color;
}

public Color getMaskColor() {
if (parent != null) {
return parent.getMaskColor();
} else {
return maskColor;
}
}

/*
** Control how the background mask is rendered
*/
public void setDisplayPartialMask(boolean value) {
displayPartialMask = value;
}

public boolean isDisplayPartialMask() {
if (parent != null) {
return parent.isDisplayPartialMask();
} else {
return displayPartialMask;
}
}

/*
** Add class to perform simple validation of typed characters
*/
public void setValidator(FieldValidator validator) {
this.validator = validator;
}

/*
**
*/
@Override
@SuppressWarnings("deprecation")
public boolean isFocusTraversable() {
return isFocusTraversable;
}

public void setFocusTraversable(boolean value) {
isFocusTraversable = value;
}

/*
** Override to add a mask as a background to the text field
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);

if (mask == null) {
return;
}

int length = getDocument().getLength();

// Paint mask character in remaining text field space

if (isDisplayPartialMask() && length < mask.length()) {
g.setColor(getMaskColor());
FontMetrics fm = getFontMetrics(getFont());
int y = getInsets().top + fm.getAscent();
int x = getInsets().left + fm.stringWidth(getText());
g.drawString(mask.substring(length), x, y);
return;
}

// Paint mask characters only when text field is empty

if (!isDisplayPartialMask() && length == 0) {
Dimension d = getSize();
g.setColor(getMaskColor());
FontMetrics fm = getFontMetrics(getFont());
int y = getInsets().top + fm.getAscent();
int x = getInsets().left + ((d.width - fm.stringWidth(mask)) / 2);
g.drawString(mask, x, y);
return;
}

}

/*
** Override so that the default document is always a SizeDocument
*/
@Override
protected Document createDefaultModel() {
return new SizeDocument(getColumns());
}

// Implement DocumentListener
// Automatically tab when the text field becomes full

public void insertUpdate(DocumentEvent e) {
Document doc = e.getDocument();

if (doc.getLength() == getColumns()) {
Object pa = getParent();

if (pa instanceof TextGroup) {
((TextGroup) pa).tab(this, TextGroup.TAB_NEXT);
} else {
FocusManager.getCurrentManager().focusNextComponent(this);
}
}
}

public void removeUpdate(DocumentEvent e) {
}

public void changedUpdate(DocumentEvent e) {
}

// Implement FocusListener
// Select all the text when a text field gains focus

public void focusGained(FocusEvent e) {
JTextField textField = (JTextField) e.getSource();
textField.selectAll();
textField.setToolTipText(null);
}

public void focusLost(FocusEvent e) {
}

// Implement KeyListener

@SuppressWarnings("deprecation")
public void keyTyped(KeyEvent e) {
// The following keys are always valid

switch ((int) e.getKeyChar()) {
case KeyEvent.VK_BACK_SPACE:
case KeyEvent.VK_ESCAPE:
case KeyEvent.VK_TAB:
return;
}

// Invoke the validator to make sure the key is valid

if (validator != null) {
setToolTipText(null);
String possibleText = getPossibleText(e);

if (!validator.isValid(possibleText)) {
// Toolkit.getDefaultToolkit().beep();
setToolTipText(validator.getMessage());
Component c = (Component) e.getSource();
c.dispatchEvent(new KeyEvent(c, KeyEvent.KEY_PRESSED, 0, KeyEvent.CTRL_MASK, KeyEvent.VK_F1));
e.consume();
}
}
}

public void keyPressed(KeyEvent e) {
}

public void keyReleased(KeyEvent e) {
}

/*
** Get the possible text by:
** 1) getting the current text,
** 2) delete any selected text,
** 3) insert typed character
*/
private String getPossibleText(KeyEvent e) {
JTextField textField = (JTextField) e.getSource();

textBuffer.setLength(0);
textBuffer.append(textField.getText());

int start = textField.getSelectionStart();
int end = textField.getSelectionEnd();
textBuffer.delete(start, end);

textBuffer.insert(start, e.getKeyChar());

return textBuffer.toString();
}

/*
** Control the number of characters that can be entered
*/
class SizeDocument extends PlainDocument {

private int maximumFieldLength = 0;

public SizeDocument(int maximumFieldLength) {
this.maximumFieldLength = maximumFieldLength;
}

@Override
public void insertString(int offset, String text, AttributeSet a)
throws BadLocationException {
if (text == null) {
return;
}

// Make sure text does not exceed its maximum length

if (getLength() + text.length() > maximumFieldLength) {
Toolkit.getDefaultToolkit().beep();
} else {
super.insertString(offset, text, a);
}
}
}
}

interface FieldValidator {
/*
** The text string will contain:
** the current contents of the document,
** less selected text about to be deleted,
** plus the character about to be added.
*/

public boolean isValid(String text);

/*
** Message explaining why last character typed was rejected
*/
public String getMessage();
}

/*
** Class that will only accept numeric digits.
** Optionally, the number enter can be validated within a range
*/
class IntegerValidator implements FieldValidator {

public final static int NEVER = 0;
public final static int OPTIONAL = 1;
public final static int ALWAYS = 2;
private int minimum;
private int maximum;
private int rangeCheckDigits;
private int signRequired;
protected String message;

/*
** Convenience constructor - effectively no range checking is done
*/
public IntegerValidator() {
this(Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
}

/*
** Convenience constructor - specify range checking
**/
public IntegerValidator(int minimum, int maximum) {
this(minimum, maximum, 0);

int min = Integer.toString(Math.abs(minimum)).length();
int max = Integer.toString(Math.abs(maximum)).length();
startRangeCheckAt(Math.min(min, max));
}

/*
** Main contructor for creating this class.
** minimum - the minimum value allowed in this field
** maximum - the maximum value allowed in this field
** rangeCheckDigits - start range checking when this number of digits
** have been entered
*/
@SuppressWarnings("empty-statement")
public IntegerValidator(int minimum, int maximum, int rangeCheckDigits) {
this.minimum = minimum;
this.maximum = maximum;
startRangeCheckAt(rangeCheckDigits);
;
}

public boolean isValid(String text) {
// Set variables used in later tests

int multiplier = 1;
boolean signEntered = false;
char firstCharacter = text.charAt(0);

if (firstCharacter == '+' || firstCharacter == '-') {
signEntered = true;
text = text.substring(1); // remove sign from text to validate

if (firstCharacter == '-') {
multiplier = -1;
}
}

// Validate the sign

if (signRequired == NEVER && signEntered) {
message = "Field must not contain a sign (+ or -)";
return false;
}

if (signRequired == ALWAYS && !signEntered) {
message = "Field must contain a sign (+ or -)";
return false;
}

// Only a sign has been entered, no number to validate

if (text.length() == 0) {
return true;
}

// Check for a valid integer

int value;

try {
value = Integer.parseInt(text) * multiplier;
} catch (Exception e) {
message = "Field must contain a number";
return false;
}

// Do a range check on the value
// (when enough digits have been entered)

if (text.length() < rangeCheckDigits) {
return true;
} else {
if (value < minimum || value > maximum) {
message = "Field must contain a number in the range " + minimum + " : " + maximum;
return false;
} else {
return true;
}
}
}

public String getMessage() {
return message;
}

/*
** Start range checking only when the specified number of digits
** have been entered.
** (For example, range check a year after 4 digits have been entered)
*/
public void startRangeCheckAt(int rangeCheckDigits) {
this.rangeCheckDigits = rangeCheckDigits;
}

/*
** Indicates whether a leading +/- sign is required when entering integer
** NEVER - entering a sign will result in an error (default)
** OPTIONAL - sign is optional
** ALWAYS - a sign must be entered or an error will result
*/
public void setSignRequired(int signRequired) {
this.signRequired = signRequired;
}
}
QuestionHow to apply mask to whole column and decimal column error Pin
AndrusM6-Jun-08 6:42
AndrusM6-Jun-08 6:42 
AnswerRe: How to apply mask to whole column and decimal column error Pin
J.Thomas6-Jun-08 7:22
J.Thomas6-Jun-08 7:22 
GeneralRe: How to apply mask to whole column and decimal column error Pin
AndrusM6-Jun-08 8:30
AndrusM6-Jun-08 8:30 
GeneralRe: Can't apply mask for output Pin
J.Thomas8-Jun-08 1:24
J.Thomas8-Jun-08 1:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.