Using a buffer between input and a JTextField - java

Instead of using a document filter, or a FormatMask I am trying something different.
Here is the requirements. Have a JTextField only accept/have one character of input allowed into it at a time, the only allowed input is numbers 1-9 think of the game Sudoku, all other input is invalid and should not be allowed. I tried handleing this with both of the above ideas and still kept getting error beeps for backspace and delete keys when using focus on the JTextField.
So I thought why not have something as a buffer that can ignore all input data I did not want to accept here is my solution.
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.*;
import java.awt.event.*;
public class MaskField
{
JFrame thisframe;
JPanel jPanel1 = new JPanel();
JTextField jTextField1 = new JTextField();
public MaskField()
{
thisframe = new JFrame();
jTextField1.addFocusListener(new FocusListener(){
#Override
public void focusLost(FocusEvent e){}
#Override
public void focusGained(FocusEvent e)
{
JTextField thisfield = (JTextField)e.getSource();
thisfield.getParent().requestFocus();
}
});
jPanel1.addKeyListener(new KeyAdapter()
{
#Override
public void keyReleased(KeyEvent e){}
#Override
public void keyTyped(KeyEvent e){}
#Override
public void keyPressed(KeyEvent e)
{
JPanel thispanel = (JPanel)e.getSource();
Component[] complist = thispanel.getComponents();
JTextField thisfield = (JTextField)complist[0];
text = thisfield.getText();
if(Character.isDigit(e.getKeyChar()) && !"0".equals(Character.toString(e.getKeyChar())))
{
thisfield.setText(Character.toString(e.getKeyChar()));
}
if(e.getKeyCode() == 127 || e.getKeyCode() == 8)
thisfield.setText("");
}
});
jPanel1.setLayout(new GridLayout(1,1));
jTextField1.setText("");
jPanel1.add(jTextField1);
thisframe.add(jPanel1);
thisframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisframe.setVisible(true);
thisframe.pack();
}
public static void main(String args[])
{
new MaskField();
}
}
I would greatly appreciate any different ideas about how to handle this because getting and changing the JTextField data is so verbose.

Related

How to change the background color of a JSpinner dependent on the current edited content of the field?

I have a GUI with a JSpinner using a SpinnerNumberModel using double values.
As soon as I change the content of the Editor of the JSpinner, I want the background to change to yellow (to show that the currently displayed value is not the one "saved" in the JSpinner respectively its Model.
If that content is not valid (e.g. out of the allowed range specified by my SpinnerNumberModel or a text as "abc") the background should change to red.
I tried to achieve what I want with a FocusListener already but yet have not been successful, also I am not sure if It could work anyway, as I need to check the content somewhere between focussing and defocussing.
I checked Tutorials for all Listeners that exist for Swing components, but could not find a right one that suits the job. (here I informed myself)
I am new to the concept of Listeners and would really appreciate any help that gets me closer to solving the problem but also helps generally understanding Listeners and how to use them in this context better!
My really basic code example with the mentioned poor attempt using a focus listener:
public class test implements FocusListener{
JFrame frame;
SpinnerNumberModel model;
JSpinner spinner;
JComponent comp;
JFormattedTextField field;
public test() {
JFrame frame = new JFrame("frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
model = new SpinnerNumberModel(0., 0., 100., 0.1);
spinner = new JSpinner(model);
comp = spinner.getEditor();
field = (JFormattedTextField) comp.getComponent(0);
field.addFocusListener(this);
frame.getContentPane().add(spinner);
frame.getContentPane().add(new JButton("defocus spinner")); //to have something to defocus when testing :)
frame.pack();
frame.setVisible(true);
}
#Override
public void focusGained(FocusEvent e) {
// TODO Auto-generated method stub
//when the values of the field and the spinner don't match, the field should get yellow
if(!field.getValue().equals(spinner.getModel().getValue())) {
field.setBackground(Color.YELLOW);
}
}
#Override
public void focusLost(FocusEvent e) {
// TODO Auto-generated method stub
//if they match again, reset to white
if(!field.getValue().equals(spinner.getModel().getValue())) {
field.setBackground(Color.RED);
}
}
}
A JSpinner uses a text field as the editor for the spinner
So, you can add a DocumentListener to the Document of the text field that is used as the editor.
Something like:
JTextField textField = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField());
textField.getDocument.addDocumentListener(...);
Then when text is added/removed a DocumentEvent will be generated and you can do your error checking. Read the section from the Swing tutorial on Listener For Changes on a Document for more information and working examples.
You can use CaretListener , here is a start:
import java.awt.Color;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
public class SpinerTest{
JSpinner spinner;
public SpinerTest() {
JFrame frame = new JFrame("frame");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
SpinnerNumberModel model = new SpinnerNumberModel(0., 0., 100., 0.1);
spinner = new JSpinner(model);
setCaretListener();
frame.getContentPane().add(spinner);
frame.pack();
frame.setVisible(true);
}
private void setCaretListener() {
for(Component c : spinner.getEditor().getComponents()) {
JFormattedTextField field =(JFormattedTextField) c;
field.addCaretListener(new CaretListener(){
#Override
public void caretUpdate(CaretEvent ce) {
if (field.isEditValid()) {
//add aditional test as needed
System.out.println("valid Edit Entered " + field.getText());
field.setBackground(Color.WHITE);
}
else {
System.out.println("Invalid Edit Entered" + field.getText());
field.setBackground(Color.PINK);
}
}
});
}
}
public static void main(String[] args) {
new SpinerTest();
}
}
I was able to fulfill the task with a combination of a KeyListener, a DocumentListener and a FocusListener. The solution might not be the easiest, but finally I coded sth. that works. Comments in the file appended should explain how I dealt with the problem.
I expanded the original task with a CommaReplacingNumericDocumentFilter expands DocumentFilter class that was not written by me, I got the code from my professor and edited it to my needs only. Now only digits, minus and e, E are accepted as entries in the JSpinner.
Commas are replaced with dots also.
Code:
import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class test implements DocumentListener, ChangeListener, KeyListener{
boolean keyPressed;
JFrame frame;
SpinnerNumberModel model;
JSpinner spinner;
JComponent comp;
JFormattedTextField field;
public test() {
JFrame frame = new JFrame("frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
model = new SpinnerNumberModel(0., 0., 100000., .1);
spinner = new JSpinner(model);
//disable grouping for spinner
JSpinner.NumberEditor editor = new JSpinner.NumberEditor(spinner);
editor.getFormat().setGroupingUsed(false);
spinner.setEditor(editor);
comp = spinner.getEditor();
field = (JFormattedTextField) comp.getComponent(0);
field.getDocument().addDocumentListener(this);
field.addKeyListener(this);
spinner.addChangeListener(this);
frame.getContentPane().add(spinner);
frame.pack();
frame.setVisible(true);
}
#Override
public void insertUpdate(DocumentEvent e) {
DocumentEventHandler(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
DocumentEventHandler(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
DocumentEventHandler(e);
}
public static boolean isNumeric(String str)
{
try
{
double d = Double.parseDouble(str);
}
catch(NumberFormatException nfe)
{
return false;
}
return true;
}
public static void main(String[] args) {
//to get the right format for double precision numbers
Locale.setDefault(Locale.US);
test test = new test();
}
#Override
public void stateChanged(ChangeEvent e) {
System.out.println("valuechanged: " + spinner.getValue().toString());
if(keyPressed) {
field.setBackground(Color.WHITE);
}
keyPressed = false;
}
public void DocumentEventHandler(DocumentEvent e) {
//as soon as update is inserted, set background to yellow
if (keyPressed) {
field.setBackground(Color.YELLOW);
//check if input is numeric and in bounds
String text = field.getText();
if (isNumeric(text)) {
double value = Double.parseDouble(text);
if (value < (Double)model.getMinimum() || value > (Double)model.getMaximum()) {
field.setBackground(Color.RED);
}
}
else { //set background to red
field.setBackground(Color.RED);
}
}
keyPressed = false;
//System.out.println(e.toString());
//System.out.println("Text: " + field.getText());
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
/** If not done yet, replaces the DocumentFilter with one replacing commas by decimal points.
* This can't be done at the very beginning because the DocumentFilter would be changed to a
* javax.swing.text.DefaultFormatter$DefaultDocumentFilter when setting up the JSpinner GUI. */
public void keyPressed(KeyEvent e) {
PlainDocument document = (PlainDocument)(field.getDocument());
if(!(document.getDocumentFilter() instanceof CommaReplacingNumericDocumentFilter))
document.setDocumentFilter(new CommaReplacingNumericDocumentFilter());
/*Tell the other handlers that a key has been pressed and the change in the document does
* not come from using the JSpinner buttons or the MouseWheel.
*/
keyPressed = true;
}
}
/** A javax.swing.text.DocumentFilter that replaces commas to decimal points
* and ignores non-numeric characters except 'e' and 'E'. This is called before
* modi */
class CommaReplacingNumericDocumentFilter extends DocumentFilter {
#Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr)
throws BadLocationException {
text = filter(text);
if (text.length() > 0)
super.insertString(fb, offset, text, attr);
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text,
AttributeSet attrs) throws BadLocationException {
text = filter(text);
if (text.length() > 0)
super.replace(fb, offset, length, text, attrs);
}
String filter(String text) {
return text.replace(',', '.').replaceAll("[^0-9eE.-]","");
}
}

Can't figure out error with ActionListener

The following is my program. the goal is to convert from a roman numeral to an Arabic number after a user types in the numeral and presses the enter key.
This is a homework assignment and we are forced to user JTextAreas in lieu of JTextFields.
My error exists on the line: enterRomanNumber.addActionListener(handler);
The error reads:
"The method addActionListener(ArabicToRomanGUI.HandlerForTextArea) is
undefined for the type JTextArea"
I can't seem to figure out why I am getting this error or how to correct it, can someone please advise.
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class ArabicToRomanGUI extends JFrame
{
private static final long serialVersionUID = 1L;
private JTextArea enterRomanNumber = new JTextArea();
JLabel label = new JLabel();
JPanel panel = new JPanel();
JFrame frame = new JFrame();
//TestArea contructor adds jtextArea to jframe
public ArabicToRomanGUI()
{
super("Convert a Roman Numeral");
setLayout(new FlowLayout());
//Text field to enter a roman numeral
enterRomanNumber = new JTextArea(1,25);
enterRomanNumber.setText("Delete this text and Enter a Roman Numerial Here!");
//enterRomanNumber.setAlignmentX(0);
//enterRomanNumber.setAlignmentY(0);
add(enterRomanNumber);
HandlerForTextArea handler = new HandlerForTextArea();
enterRomanNumber.addActionListener(handler);
}
private class HandlerForTextArea implements ActionListener
{
//used to process textArea events
#Override
public void actionPerformed(ActionEvent e)
{
String userInput = "";
userInput = enterRomanNumber.getText();
userInput = userInput.toUpperCase();
ConversionLogic.ConvertFromRomanToArabic(userInput); //converts user string of Roman numerals to an int in arabic
String arabicNumberAsString = ConversionLogic.getConvertedRomanNumeral();
enterRomanNumber.setText(arabicNumberAsString);
//user pressed enter in JTextField enterNumberField
if(e.getSource() == enterRomanNumber)
{
//enterRomanNumber.setText(arabicNumberAsString);
if (ConversionLogic.getCheckFail() == true)
{
JOptionPane.showMessageDialog(frame, "The Roman Numeral entered is Invalid", "Error", JOptionPane.ERROR_MESSAGE);
}
else
{
JOptionPane.showMessageDialog(frame, "The arabic equivalent is " + arabicNumberAsString + "." , "Conversion Successful", JOptionPane.PLAIN_MESSAGE);
}
}
}
}
}//end inner class TextAreaHandler
For a better answer, see #MadProgrammer 's answer.
My solution:
There is no ActionListener for JTextArea.
So just use KeyListener instead
HandlerForTextArea handler = new HandlerForTextArea();
enterRomanNumber.addKeyListener(handler);
Implements KeyListener
private class HandlerForTextArea implements KeyListener
{
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
if (arg0.getKeyCode() == VK_ENTER){
// TODO Your bussiness
}
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
KeyListeners are NEVER appropriate solutions to use with text components, if you want to be notified when a text component changes, you use a DocumentListener, if you want to change/filter what can be entered into a text component, you use a DocumentFilter, if you need to change a special key, like Enter, you should use a key binding
See How to Use Key Bindings for more details.
One of the problems you could have with KeyListener is not knowing when the key stroke is processed by the text component, in your case, it may not be a major issue, but it could change the way the program works on different platforms.
Instead, you can override the JTextArea's key binding for the Enter key (named insert-break). This provides you with the ability to actually change the behavior of the key stroke, or, in your case, manage how you process the event. For example, this replaces the Action for the text area's Enter key, but retains the previous/default behavior...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class KeyBindingsTest {
public static void main(String[] args) {
new KeyBindingsTest();
}
public KeyBindingsTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
ta = new JTextArea(10, 20);
ActionMap am = ta.getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
System.out.println("You pressed the enter key, you can have candy");
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
setLayout(new BorderLayout());
add(ta);
}
}
}
Now, you could even go to the extent for creating your own JTextArea which supported ActionPerformed...
public class ActionableTextArea extends JTextArea {
private String actionCommand;
public ActionableTextArea() {
installKeyBindings();
}
public ActionableTextArea(String text) {
super(text);
installKeyBindings();
}
public ActionableTextArea(int rows, int columns) {
super(rows, columns);
installKeyBindings();
}
public ActionableTextArea(String text, int rows, int columns) {
super(text, rows, columns);
installKeyBindings();
}
public ActionableTextArea(Document doc) {
super(doc);
installKeyBindings();
}
public ActionableTextArea(Document doc, String text, int rows, int columns) {
super(doc, text, rows, columns);
installKeyBindings();
}
protected void installKeyBindings() {
ActionMap am = getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
fireActionPerformed();
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
public void setActionCommand(String actionCommand) {
this.actionCommand = actionCommand;
}
public String getActionCommand() {
return actionCommand;
}
protected void fireActionPerformed() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand());
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}

Terminal class called from JFrame class don't have user inputs for a reason

Here is my code
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Login
{
static BufferedReader dataIn = new BufferedReader(new InputStreamReader(System.in));
static String a, b, c;
static int d, z, f, g, h, i, k;
public static void Login()
{
JFrame frame = new JFrame("Login");
JButton button1 = new JButton("Login");
JLabel label1 = new JLabel("Username: ");
JLabel label2 = new JLabel("Pin: ");
JTextField txt1 = new JTextField(8);
JPasswordField pass1 = new JPasswordField(8);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel FormPanel = new JPanel();
txt1.setBackground(Color.white);
pass1.setBackground(Color.white);
panel1.add(label1);
panel1.add(txt1);
panel2.add(label2);
panel2.add(pass1);
FormPanel.setLayout(new GridLayout(3,8));
FormPanel.add(panel1);
FormPanel.add(panel2);
FormPanel.add(button1);
pass1.getDocument().addDocumentListener(new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
changed();
}
public void removeUpdate(DocumentEvent e)
{
changed();
}
public void insertUpdate(DocumentEvent e)
{
changed();
}
public void changed()
{
if (pass1.getText().equals(""))
{
button1.setEnabled(false);
}
else
{
button1.setEnabled(true);
}
}
});
txt1.getDocument().addDocumentListener(new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
changed();
}
public void removeUpdate(DocumentEvent e)
{
changed();
}
public void insertUpdate(DocumentEvent e)
{
changed();
}
public void changed()
{
if (txt1.getText().equals(""))
{
button1.setEnabled(false);
}
else
{
button1.setEnabled(true);
}
}
});
button1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
frame.hide();
Body a = new Body();
a.Body();
}
});
button1.setActionCommand("Open");
frame.setContentPane(FormPanel);
frame.setSize(8,9);
frame.pack();
frame.show();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
}
}
and my Body.java is
try
{
do
{
System.out.print("Working time (hours): ");
a=dataIn.readLine();
e=Integer.parseInt(a);
k=e;
if(k<8)
{
System.out.print("\nYou have worked undertime");
g=e * 30;
h=g * 500;
i=h-200;
System.out.print("\nYour payment (per month) is: " +i);
}
if(k>8)
{
System.out.print("\nYou have worked overtime");
g=e*30;
h=g*500;
i=h+200;
System.out.print("\nYour payment (per month) is: " +i);
}
if(k==8)
{
System.out.print("\nYou have worked ontime");
g=e*30;
h=g*500;
System.out.print("\nYour payment (per month) is: " +h);
}
System.out.print("\n\nPress 0 to logout: ");
c=dataIn.readLine();
d=Integer.parseInt(c);
}while(d!=0);
}
catch(Exception j)
{
System.out.print("\nYou probably need to work for more than an hour to start earning");
}
of course I have import java.io.*; and BufferedReader dataIn = new BufferedReader(<arguments>); but when ever I call the body.java that opens in terminal it won't ask for user inputs, but when I try to execute the body.java it asks for user inputs...
I need help right now...
You ask:
okay.. then please tell me how can I do some simple calculations in full GUI?
Again you'll want to avoid trying to mix GUI with console programs since they interact with the user in two very dissimilar ways, and the console can lock up the GUI if you're not careful. Instead consider going all console or all GUI.
If you go all GUI, one possible solution is to create a GUI that is similar to what you're already doing with user name and PIN number:
Give your GUI JTextFields for the user to input his data.
Add a "Calculate" JButton
In the button's ActionListener, extract the data from the JTextFields, convert any Strings to numbers that need converting, calculate your value and display it in another JTextField or JLabel.
Other side recommendations:
Don't call deprecated methods since they're deprecated for a good reason. Instead the Java API will usually tell you what alternatives to use.
Avoid over-use of static variables and methods, since this leads to rigid code that is difficult to test or enhance.
Try to give your variables names that have meaning so that your code becomes "self-commenting".
Your log-in window should be a modal dialog of some type, such as a modal JDialog, not a JFrame, since
Closing it will not close the entire GUI
It will prevent interacting with the main GUI until it has been fully dealt with.

How to make part of a JTextField uneditable

I wanted to develop a console-like interface, similar to IDLE. That involved determining how to prevent a certain part of the text in a JTextField from being edited. For example:
>>> help
Where the ">>> " is uneditable. The caret must never move behind a certain position, and the text behind that position cannot be edited in any way.
I looked at NavigationFilter, but it doesn't seem to prevent keyboard driven manipulation of the caret.
This shows how to do it with a NavigationFilter:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class NavigationFilterPrefixWithBackspace extends NavigationFilter
{
private int prefixLength;
private Action deletePrevious;
public NavigationFilterPrefixWithBackspace(int prefixLength, JTextComponent component)
{
this.prefixLength = prefixLength;
deletePrevious = component.getActionMap().get("delete-previous");
component.getActionMap().put("delete-previous", new BackspaceAction());
component.setCaretPosition(prefixLength);
}
#Override
public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias)
{
fb.setDot(Math.max(dot, prefixLength), bias);
}
#Override
public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias)
{
fb.moveDot(Math.max(dot, prefixLength), bias);
}
class BackspaceAction extends AbstractAction
{
#Override
public void actionPerformed(ActionEvent e)
{
JTextComponent component = (JTextComponent)e.getSource();
if (component.getCaretPosition() > prefixLength)
{
deletePrevious.actionPerformed( null );
}
}
}
private static void createAndShowUI()
{
JTextField textField = new JTextField("Prefix_", 20);
textField.setNavigationFilter( new NavigationFilterPrefixWithBackspace(7, textField) );
JFrame frame = new JFrame("Navigation Filter Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(textField);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Spent a little while figuring this out, so I thought I would share my solution for anyone else with the same dilemma. I don't know if it's optimal, but it does seem to work.
It prevents the user from using backspace behind the postion n. It also moves the caret back to n for any other events, such as (illegally) changing the caret position with the arrow keys or mouse. Finally, it resets the text and caret position after a entry is processed.
EDIT: While I'm leaving this answer here for posterity, see the accepted answer for the best way to solve this problem.
JTextField in = new JTextField();
final String protectMe = ">>> "; //protect this text
final int n = protectMe.length();
in.setText(protectMe);
in.setCaretPosition(n);
in.addCaretListener(new CaretListener()
{
#Override
public void caretUpdate(CaretEvent e)
{
if (e.getDot() < n)
{
if (!(in.getText().length() < n))
in.getCaret().setDot(n);
}
}
});
in.addKeyListener(new KeyListener()
{
#Override
public void keyPressed(KeyEvent arg0)
{
if (in.getCaret().getDot() <= n)
{
in.setText(protectMe + in.getText().substring(n));
arg0.consume();
}
}
#Override
public void keyReleased(KeyEvent arg0){}
#Override
public void keyTyped(KeyEvent arg0){}
});
in.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
String input = in.getText().substring(n).trim();
//do something
in.setText(protectMe);
in.setCaretPosition(n);
}
});
As usual, let me know if there's anything I missed!

Is it Possible to Add ActionListener in the JFormattedTextField?

Hello I'm currently working in my java file.
I'd like to add an event on JFormattedTextField when I press the enter key.
This is my code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.MaskFormatter;
import java.awt.*;
import java.text.ParseException;
public class Test extends JFrame implements ActionListener
{
JFormattedTextField phoneField;
Test()
{
setTitle("JFormatted Text");
setLayout(null);
MaskFormatter mask = null;
try {
mask = new MaskFormatter("##########");
} catch (ParseException e) {
e.printStackTrace();
}
phoneField = new JFormattedTextField(mask);
phoneField.setBounds(20, 20, 150, 30);
phoneField.addActionListener(this);
setVisible(true);
setSize(200, 200);
getContentPane().add(phoneField);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new Test();
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()== phoneField)
{
System.out.println("The numbers you enter are "+phoneField.getText());
}
}
}
it works but their the user needs to enter 10 digits.
Add an ActionListener to the field. It is better than using the (low level) KeyListener and will conform to whatever that OS accepts as 'end of entry'.
Don't use KeyListener instead use DocumentListener.
It has the following methods which captures the changes in the JTextField
JTextField textField = new JTextField();
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent arg0) {
// Gives notification that a portion of the document has been removed.
}
#Override
public void insertUpdate(DocumentEvent arg0) {
// Gives notification that there was an insert into the document.
}
#Override
public void changedUpdate(DocumentEvent arg0) {
// Gives notification that an attribute or set of attributes changed.
}
});
You could add a keyListener instead.
phonefield.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
if(evt.getKeyCode() == evt.VK_ENTER){
System.out.println("The numbers you enter are "+phoneField.getText());
}
}
});
If this isn't your problem, you should expand a little and clarify.
EDIT:
As comments and other answers pointed out, you should go for an ActionListener instead. Reasoning can be found below.

Categories