How to limit JTextFiled to accept only numbers less then 10? - java

How to restrict a JTextFiled to accept only numbers less then 10, no words, no spaces or any other special characters?

The easiest would be to use a component designed for this:
JSpinner spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(0, null, 10, 1));
Technically JSpinner is not derived from JTextField, it uses one internally for the editor part and thus looks like one (plus it has additional buttons to change the number with mouse clicks).

Again, a DocumentFilter is one way to solve this:
import javax.swing.*;
import javax.swing.text.*;
#SuppressWarnings("serial")
public class DocFilterExample extends JPanel{
JTextField textfield = new JTextField(5);
public DocFilterExample() {
PlainDocument doc = (PlainDocument) textfield.getDocument();
doc.setDocumentFilter(new MaxNumberDocFilter(10));
add(textfield);
}
private class MaxNumberDocFilter extends DocumentFilter {
private int maxNumber;
public MaxNumberDocFilter(int maxnumber) {
this.maxNumber = maxnumber;
}
private boolean verifyText(String text) {
if (text.isEmpty()) {
return true; // allow for a blank text field
}
int value = 0;
try {
value = Integer.parseInt(text);
if (value >= 0 && value < maxNumber) {
return true; // if it's a number in range, it passes
}
} catch (NumberFormatException e) {
return false; // if it's not a number, it fails.
}
return false;
}
#Override
public void insertString(FilterBypass fb, int offset, String string,
AttributeSet attr) throws BadLocationException {
Document doc = fb.getDocument();
String oldText = doc.getText(0, doc.getLength());
StringBuilder sb = new StringBuilder(oldText);
sb.insert(offset, string);
if (verifyText(sb.toString())) {
super.insertString(fb, offset, string, attr);
}
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
Document doc = fb.getDocument();
String oldText = doc.getText(0, doc.getLength());
StringBuilder sb = new StringBuilder(oldText);
sb.replace(offset, offset + length, text);
if (verifyText(sb.toString())) {
super.replace(fb, offset, length, text, attrs);
}
}
#Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
Document doc = fb.getDocument();
String oldText = doc.getText(0, doc.getLength());
StringBuilder sb = new StringBuilder(oldText);
sb.replace(offset, offset + length, "");
if (verifyText(sb.toString())) {
super.remove(fb, offset, length);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Eg");
frame.getContentPane().add(new DocFilterExample());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Advantages:
no error messages are needed. Instead it simply prevents input of bad input.
It works for cut and paste just fine.
Disadvantages:
no error messages are given, and so the user won't know why his text is not accepted.
it's a bit long and bulky.
it's not easy "chaining" -- using multiple filters at once, something Rob Camick has done some work on.

Try This :-
JTextField textField = new JTextField();
textField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
//do stuff here when enter pressed
String text = textField.getText();
if(text!=null && !text.equals("")){
char c = evt.getKeyChar();
int val=Integer.parseInt(c);
if(val>=48 && val<=57){
if(Integer.parseInt(text)<=10){
//Its valid and allowed
}else{
//Its invalid, show error message here
}
}else{
//Show message only numbers are allowed
return false;
}
}
}
});
Hope it will help you.

Use Swing Javabuilders, where you can define your GUI in YML (below), including Text Field validation.
You declare in your gui in a yaml file, here is an example for Person.java, called Person.Yaml:
JFrame(name=frame, title=frame.title, size=packed, defaultCloseOperation=exitOnClose):
- JButton(name=save, text=button.save, onAction=[$validate,save,done])
- JButton(name=cancel, text=button.cancel, onAction=[$confirm,cancel])
- MigLayout: |
[pref] [grow,100] [pref] [grow,100]
"label.firstName" txtFirstName "label.lastName" txtLastName
"label.email" txtEmail+*
>save+*=1,cancel=1
bind:
- txtFirstName.text: person.firstName
- txtLastName.text: person.lastName
- txtEmail.text: person.emailAddress
validate:
- txtFirstName.text: {mandatory: true, label: label.firstName}
- txtLastName.text: {mandatory: true, label: label.lastName}
- txtEmail.text: {mandatory: true, emailAddress: true, label: label.email}
The three blocks above are as follows:
The Swing Classes (JFrame, and JButton) as well as the Layout Manager, with embedded JLabels (label.firstName and label.lastName) which are recognised by the 'label' part of their declaration and the JTextFields (txtLastName,txtFirstName and txtEmail ) which are recognised by the txt part of their name.
The Data Binding: This binds JTextArea.text to class.fieldName so that when data is entered into the JTextField it is mapped to the fields.
Validation: Here is where the text is validated. Notice that the JButton with the name Save has in the onAction section has the entry $validate which runs the in-built validate method. This reads the kind of validation in from the validate block:
txtFirstName.text: {mandatory: true, label: label.firstName}
Which declares the field has to be filled in (mandatory: true) and txtEmail must be filled with a valid email address (emailAddress: true). More validation is outlined below.
Once you've declared the GUI, you just run it like so, from within your java file.
private BuildResult result;
.....
public methodName(){
.....
result = SwingJavaBuilder.build(this).setVisible(true);
}
This method (build(this)) references a .yml file of the same name (so your gui is in person.yml and is paired with person.java).
There's more validation available in the documentation :
validate:
- mandatory.text: {label: Mandatory Field, mandatory: true}
- date.text: {label: Date Field, dateFormat: "yyyy/mm/dd"}
- email.text: {label: E-Mail, email: true}
- minmax.text: {label: Min/Max Length, minLength: 5, maxLength: 10}
- regex.text: {label: Regex, regex: "[a-zA-Z0-9]+"}
- regex2.text: {label: Regex, regex: "[a-zA-Z0-9]+",
regexMessage: "''{0}'' must be a number or letter"}
- long.text: {label: Min/Max Long, minValue: 5, maxValue: 50, mandatory: true}
So you would want to use the last one long.text with this specification:
myValidNumberField{label: Number less than ten, maxValue: 10, mandatory: true}`
There's more information on the github page, about setting your GUI up like this.

Related

Search in table codename one

I have created a table below that has name of the places as its entryPoint in the first column. I want to keep a textfield so that one can search for the place he wants to view in the table.
How can i do this? For eg: if i type "a" in text field, all the places starting from "a" only are shown in the table.
json value for table
connectionRequest = new ConnectionRequest() {
#Override
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
results = p.parse(new InputStreamReader(input));
responseInout = (Vector) results.get("inout");
for (int i = 0; i < responseInout.size(); i++) {
Hashtable hash = (Hashtable) responseInout.get(i);
String entryPoint = (String) hash.get("entry_point");
String passengerIn = (String) hash.get("passenger_in");
String passengerOut = (String) hash.get("passenger_out");
String vehicleIn = (String) hash.get("vehicle_in");
String vehicleOut = (String) hash.get("vehicle_out");
dataInOut[i][0] = entryPoint;
dataInOut[i][1] = passengerIn;
dataInOut[i][2] = passengerOut;
dataInOut[i][3] = vehicleIn;
dataInOut[i][4] = vehicleOut;
}
}
connectionRequest.setPost(false);
connectionRequest.setUrl("http://capitaleyedevelopment.com/~admin/traffic/api/reports/getReports/2015-12-30");
connectionRequest.setDuplicateSupported(true);
NetworkManager.getInstance().addToQueueAndWait(connectionRequest);
//table
Table table = new MyTable(new DefaultTableModel(columnNamesInOut, dataInOut));
//what to do here in textField
TextField tf = new TextField();
tf.addDataChangeListener(new DataChangedListener() {
#Override
public void dataChanged(int type, int index) {
String searchPlace = tf.getText();
}
});
You can have two types of "search":
Data narrowing - this will hide the rows where the text doesn't show.
Highlight - this will highlight the cells where the data appears
If you choose the data narrowing route just create a new model without the rows that don't contain the data you want and invoke: table.setModel(searchModel); this will leave only the search results.
If you want the highlighting mode In the search field just call table.setModel(table.getModel()); this will force the table to rebuild.
Then override in the table:
protected Component createCell(Object value, int row, int column, boolean editable) {
Component c = super.createCell(value, row, column, editable);
if(isSearchedValue(value)) {
c.setUIID("SearchResult");
}
return c;
}
Then style SearchResult to be the highlight color you want and all is well...

Jtable Number Editor with "," separator rather than "."

I am a French guy and not new to Java.
In French, Doubles have "," separator rather than ".". So I have a JTable Cell with column class = Double, when I enter e.g 2.4 it is Ok. But when I enter 2,4 it blocks.
I used Locale.setDefault(Locale.FRENCH); but I have the same result :
Number
And as you can see in the image below, my application started with French locale :
System Locale
Is there any way to enter 2,4 rather than 2.4 ?
Sincerely.
Is there any way to enter 2,4 rather than 2.4 ?
Well there are several issues.
the default renderer will display the "." not the ",".
the default editor will display the ".", not the ","
the default editor doesn't recognize the "," as a valid character for a Double when you attempt to save the value to the TableModel
When you leave a cell the entered String must be converted to a Double. However, the Double.parseDouble(...) method does not recognize the "," even when the French Locale is used.
The default cell editor realizes the String can't be converted properly so the cell is highlighted with the red border to indicate an invalid value.
The solution below uses a custom editor to internally handle the conversion of the "," to "." before the String is parsed as a Double. It will also convert the "." to a "," so the value is displayed properly in the editor.
import java.awt.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class LocaleEditor extends DefaultCellEditor
{
private Object value;
public LocaleEditor()
{
super( new JTextField() );
((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
}
#Override
public Object getCellEditorValue()
{
return value;
}
#Override
public boolean stopCellEditing()
{
try
{
String editingValue = (String)super.getCellEditorValue();
// Don't allow user to enter "."
if (editingValue.contains("."))
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
return false;
}
// Replace local specific character
int offset = editingValue.lastIndexOf(",");
if (offset != -1)
{
StringBuilder sb = new StringBuilder(editingValue);
sb.setCharAt(offset, '.');
editingValue = sb.toString();
}
value = Double.parseDouble( editingValue );
}
catch(NumberFormatException exception)
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
return false;
}
return super.stopCellEditing();
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
JTextField textField = (JTextField)c;
textField.setBorder( new LineBorder(Color.BLACK) );
String text = textField.getText();
int offset = text.lastIndexOf(".");
// Display local specific character
if (offset != -1)
{
StringBuilder sb = new StringBuilder(text);
sb.setCharAt(offset, ',');
textField.setText( sb.toString() );
}
return c;
}
private static void createAndShowUI()
{
String[] columnNames = {"String", "Double", "Boolean"};
Object[][] data =
{
{"A", new Double(1), Boolean.TRUE },
{"B", new Double(2.25), Boolean.FALSE},
{"C", new Double(12.34), Boolean.TRUE },
{"D", new Double(1234.56), Boolean.FALSE}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames)
{
// Returning the Class of each column will allow different
// renderers and editors to be used based on Class
public Class getColumnClass(int column)
{
for (int row = 0; row < getRowCount(); row++)
{
Object o = getValueAt(row, column);
if (o != null)
return o.getClass();
}
return Object.class;
}
};
JTable table = new JTable(model);
table.setRowHeight(20);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
// Use a custom renderer and editor
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
nf.setMinimumFractionDigits(2);
TableCellRenderer renderer = new NumberRenderer( nf );
table.setDefaultRenderer(Double.class, renderer);
TableCellEditor fce = new LocaleEditor();
table.setDefaultEditor(Double.class, fce);
JFrame frame = new JFrame("Table Five Character Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The above code also uses code found in Table Format Renderers, which allows you to easily create a custom renderer for a given Locale. Just comment out the code if you don't want to use the renderer, but then the "." will be displayed in the table.
I recommend you to implement a custom data model using AbstractTableModel, then inside the method getValueAt(int row, int col) use NumberFormat as follows:
NumberFormat.getInstance(Locale.FRENCH).format(2.4);
If your application is only going to be used by French users, you can hardcode the default locale to French.
Locale.setDefault( Locale.FRENCH );
Alternatively, as a workaround, just set all columns to String (thus, all input will be accepted), and in DefaultTableModel->TableModelListener->tableChanged() format your String as you wish and parse it to Double afterwards with setValueAt().

How can I make users ONLY input decimal?

So I am very new to java and struggling with my class ... here's what I thought would work:
double costPerKiloHr = 0; //sets value to 0
//tests to make sure a number was inputted
try {
costPerKiloHr = Double.parseDouble(
this.costPerKiloHrText.getText());
}
catch (Exception e) {
JOptionPane.showMessageDialog(this, "Please input a dollar amount including cents",
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
You can use regex to check for a match for at least 1 numerical value after the decimal.
String input = scanner.next();
Pattern pattern = Pattern.compile("[0-9]*\\.[0-9]+");
Matcher matcher = pattern.matcher(input);
if(matcher.matches()){
System.out.println("True");
}else{
System.out.println("False");
}
OUTPUT
1.0 True
ASB False
0.25 True
1 False
You cannot make users to input what you want, if you are not a mage or smth. But you can edit the code that accept user input. There can be a huge difference: I don't know what are you using as input. I noticed you're using JOptionPane so I guess you use swing.
In swing there is JTextField and you can control it's content like this:
final JTextField field = new JTextField();
field.addKeyListener(new KeyListener() {
StringBuilder buffer = new StringBuilder();
#Override
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if (Character.isDigit(c)) {
buffer.append(c);
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
field.setText(buffer.toString());
}
});
If you are using InputStream you should interpret byte pairs as chars and then filter out non-digit values. Declaration of delimiters is required that way.
Assuming you are using Swing (a safe bet given the use of JOptionPane), you can have the user type into a javax.swing.JFormattedTextField... This is an extension of the JTextField widget that takes a Formatter object that defines what is and isn't acceptible. It can be configured (through Formatter.setAllowsInvalid(false)) to never let the user type in an invalid string.
So a formatter for an arbitrary regular expression might look something like this:
public class RegExFormatter extends DefaultFormatter {
protected Matcher matcher;
public RegExFormatter(String regex) {
setOverwriteMode(false);
Pattern p = Pattern.compile(regex);
matcher = p.matcher(""); // initial field contents
}
#Override
public Object stringToValue(String string) throws ParseException {
if (string == null || string.trim().equals(""))
return null;
matcher.reset(string);
if (!matcher.matches()) {
throw new ParseException("Input did not match regex", 0);
}
return super.stringToValue(string); // default returns this string; see docs!
}
}
Then you use this in your code like this:
String regex = "^[1-9]*[0-9](\\.\\d*)?$"; // change this to taste!
RegExFormatter ref = new RegExFormatter(regex);
ref.setAllowsInvalid(false);
JFormattedTextField field1 = new JFormattedTextField(ref);

Empty String validation for Multiple JTextfield

Is there a way to validate a number of JTextfields in java without the if else structure. I have a set of 13 fields, i want an error message when no entry is given for any of the 13 fields and to be able to set focus to that particular textbox. this is to prevent users from entering empty data into database. could someone show me how this can be achieved without the if else structure like below.
if (firstName.equals("")) {
JOptionPane.showMessageDialog(null, "No data entered");
} else if (lastName.equals("")) {
JOptionPane.showMessageDialog(null, "No data entered");
} else if (emailAddress.equals("")) {
JOptionPane.showMessageDialog(null, "No data entered");
} else if (phone.equals("")) {
JOptionPane.showMessageDialog(null, "No data entered");
} else {
//code to enter values into MySql database
the above code come under the actionperformed method a of a submit registration button. despite setting fields in MySQL as NOT NULL, empty string were being accepted from java GUI. why is this? i was hoping perhaps an empty string exception could be thrown from which i could customise a validation message but was unable to do so as empty field were being accepted.
Thanks
Just for fun a little finger twitching demonstrating a re-usable validation setup which does use features available in core Swing.
The collaborators:
InputVerifier which contains the validation logic. Here it's simply checking for empty text in the field in verify. Note that
verify must not have side-effects
shouldYieldFocus is overridden to not restrict focus traversal
it's the same instance for all text fields
a commit action that checks the validity of all children of its parent by explicitly invoking the inputVerifier (if any) and simply does nothing if any is invalid
a mechanism for a very simple though generally available error message taking the label of the input field
Some code snippets
// a reusable, shareable input verifier
InputVerifier iv = new InputVerifier() {
#Override
public boolean verify(JComponent input) {
if (!(input instanceof JTextField)) return true;
return isValidText((JTextField) input);
}
protected boolean isValidText(JTextField field) {
return field.getText() != null &&
!field.getText().trim().isEmpty();
}
/**
* Implemented to unconditionally return true: focus traversal
* should never be restricted.
*/
#Override
public boolean shouldYieldFocus(JComponent input) {
return true;
}
};
// using MigLayout for lazyness ;-)
final JComponent form = new JPanel(new MigLayout("wrap 2", "[align right][]"));
for (int i = 0; i < 5; i++) {
// instantiate the input fields with inputVerifier
JTextField field = new JTextField(20);
field.setInputVerifier(iv);
// set label per field
JLabel label = new JLabel("input " + i);
label.setLabelFor(field);
form.add(label);
form.add(field);
}
Action validateForm = new AbstractAction("Commit") {
#Override
public void actionPerformed(ActionEvent e) {
Component source = (Component) e.getSource();
if (!validateInputs(source.getParent())) {
// some input invalid, do nothing
return;
}
System.out.println("all valid - do stuff");
}
protected boolean validateInputs(Container form) {
for (int i = 0; i < form.getComponentCount(); i++) {
JComponent child = (JComponent) form.getComponent(i);
if (!isValid(child)) {
String text = getLabelText(child);
JOptionPane.showMessageDialog(form, "error at" + text);
child.requestFocusInWindow();
return false;
}
}
return true;
}
/**
* Returns the text of the label which is associated with
* child.
*/
protected String getLabelText(JComponent child) {
JLabel labelFor = (JLabel) child.getClientProperty("labeledBy");
return labelFor != null ? labelFor.getText() : "";
}
private boolean isValid(JComponent child) {
if (child.getInputVerifier() != null) {
return child.getInputVerifier().verify(child);
}
return true;
}
};
// just for fun: MigLayout handles sequence of buttons
// automagically as per OS guidelines
form.add(new JButton("Cancel"), "tag cancel, span, split 2");
form.add(new JButton(validateForm), "tag ok");
There are multiple ways to do this, one is
JTextField[] txtFieldA = new JTextField[13] ;
txtFieldFirstName.setName("First Name") ; //add name for all text fields
txtFieldA[0] = txtFieldFirstName ;
txtFieldA[1] = txtFieldLastName ;
....
// in action event
for(JTextField txtField : txtFieldA) {
if(txtField.getText().equals("") ) {
JOptionPane.showMessageDialog(null, txtField.getName() +" is empty!");
//break it to avoid multiple popups
break;
}
}
Also please take a look at JGoodies Validation that framework helps you validate user input in Swing applications and assists you in reporting validation errors and warnings.
Take an array of these three JTextField, I am giving an overview
JTextField[] fields = new JTextField[13]
field[0] = firstname;
field[1] = lastname; //then add remaining textfields
for(int i = 0; i < fields.size(); ++i) {
if(fields[i].getText().isEmpty())
JOptionPane.showMessageDialog(null, "No data entered");
}
Correct me if i'm wrong, I am not familiar with Swing or awt.HTH :)
Here is one way to do it:
public static boolean areAllNotEmpty(String... texts)
{
for(String s : texts) if(s == null || "".equals(s)) return false;
return true;
}
// ...
if(areAllNotEmpty(firstName, lastName, emailAddress, phone))
{
JOptionPane.showMessageDialog(null, "No data entered");
}

Searching for words in textarea

I am building a custom a find and replace in java. I browse a text file and load the contents in a textarea. Now I have a textBox, where I input a text that needs to be searched.
What is the best way to search the text. I know a way using string.indexOf(), but I also need highlighting. So please help me out.
First of all read Text and New Lines for information on how to get the text to search.
Then to highlight the text your find you need to use a Highlighter. The code is something like:
Highlighter.HighlightPainter painter =
new DefaultHighlighter.DefaultHighlightPainter( Color.cyan );
int offset = text.indexOf(searchWord);
int length = searchWord.length();
while ( offset != -1)
{
try
{
textPane.getHighlighter().addHighlight(offset, offset + length, painter);
offset = text.indexOf(searchWord, offset+1);
}
catch(BadLocationException ble) { System.out.println(ble); }
}
indexOf is the easiest way, but might not be the fastest way.
Why isn't indexOf working for you? You will get the index of the match, and you know the length of the match, so just highlight the text that matched.
I am having the same problem with my text editor. I didn't use a highlighter though, I used
textArea.select(int i1, int i2); //where i1 is where your selection begins and i2 is where it ends.
also an easy way to find and replace is:
textArea.setText(textArea.getText().replaceAll(String string1, String string2));
final String inputValue = JOptionPane.showInputDialog("Find What?");
final int l1 = jTextArea1.getText().indexOf(inputValue);
final int l2 = inputValue.length();
if (l1 == -1) {
JOptionPane.showMessageDialog(null, "Search Value Not Found");
} else {
jTextArea1.select(l1, l2+l1);
}
if (e.getSource() == btnSearch && !searchWord.getText().isEmpty()) {
Highlighter.HighlightPainter painter =
new DefaultHighlighter.DefaultHighlightPainter( Color.cyan );
templateArea.getHighlighter().removeAllHighlights();
int offset = templateArea.getText().indexOf(searchWord.getText());
int length = searchWord.getText().length();
while ( offset != -1)
{
try
{
templateArea.getHighlighter().addHighlight(offset, offset + length, painter);
offset = templateArea.getText().indexOf(searchWord.getText(), offset+1);
}
catch(BadLocationException exception) { System.out.println(exception); }
}
}
}

Categories