Can you link values for two JFormattedTextFields? - java

I've got an interface with 2 JFormattedTextFields for which I need the values (not just the displayed text) to be identical. Ideally they should both be editable, with a change in one being mirrored in the other.
I started by just sharing a single Document between the two, but quickly ran into the problem that this only links the displayed text, not the underlying value. (Silly me!)
I haven't tried adding reciprocal PropertyChangeListeners for the "value" property because I would expect that to set up an infinite loop of modification.
Am I missing something? Is there some way to do this? Or am I stuck with only allowing users to edit one of the two and only having the value propagate in one direction?
Thank you!

I need the values (not just the displayed text) to be identical.
Ideally they should both be editable, with a change in one being
mirrored in the other.
use DocumentListener,
for example (only the one directions)
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class TextLabelMirror {
private JPanel mainPanel = new JPanel();
private JTextField field = new JTextField(20);
private JTextField field1 = new JTextField(20);
public TextLabelMirror() {
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
updateLabel(e);
}
private void updateLabel(DocumentEvent e) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
field1.setText(field.getText());
}
});
}
});
mainPanel.setLayout(new GridLayout(1, 0, 10, 0));
mainPanel.add(field);
mainPanel.add(field1);
}
public JComponent getComponent() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("TextLabelMirror");
frame.getContentPane().add(new TextLabelMirror().getComponent());
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() {
#Override
public void run() {
createAndShowUI();
}
});
}
}

You can use a key listener. You simply add a key listener to both fields using the below code. the reason you need the other events is it will throw errors unless you have them in the code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CreateGrid
{
JFrame thisframe;
JFormattedTextField jFormattedTextField1, jFormattedTextField2;
public CreateGrid()
{
GridLayout thislayout = new GridLayout(0,2);
thisframe = new JFrame();
thisframe.setLayout(thislayout);
jFormattedTextField1 = new JFormattedTextField();
jFormattedTextField2 = new JFormattedTextField();
jFormattedTextField1.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField2.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
jFormattedTextField2.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField1.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
thisframe.add(jFormattedTextField1);
thisframe.add(jFormattedTextField2);
thisframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisframe.setVisible(true);
thisframe.pack();
}
public static void main(String args[])
{
new CreateGrid();
}
}
I have tested this out and it works perfectly what ever you type into one field will show up in the other as you type it.

Related

Custom maximize, minimize buttons

I created custom buttons for maximize, minimize and exit. And everything is working, with one exception, program does not remember in which state window was, before minimization. So my question is, is there a way, program to remember window state before minimization, and restore that state, and not to return only on NORMAL state?
My solution for:
maximize:
JButton btnO = new JButton("O");
btnO.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (frame.getExtendedState() == JFrame.MAXIMIZED_BOTH) {
frame.setExtendedState(JFrame.NORMAL);
} else {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
});
and Minimize:
JButton btnMinimize = new JButton("-");
btnMinimize.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setExtendedState(JFrame.ICONIFIED);
}
});
You can take the ComponentListener approach and restore its state when the component (in your case, the frame), is resized. Some extra comments inside the code.
Take a look at this example:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class FrameState extends JFrame {
private static final long serialVersionUID = 1965751967944243251L;
private int state = -1; // Variable to keep the last state.
public FrameState() {
super("Nothing :)");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton b = new JButton("-");
b.addActionListener(e -> {
state = getExtendedState(); //Store the state before "-" is pressed
setExtendedState(JFrame.ICONIFIED);
});
JButton o = new JButton("O");
o.addActionListener(e -> {
if (getExtendedState() == JFrame.MAXIMIZED_BOTH) {
setExtendedState(JFrame.NORMAL);
} else {
setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
getContentPane().setLayout(new FlowLayout());
getContentPane().add(o);
getContentPane().add(b);
setSize(new Dimension(300, 300));
setLocationRelativeTo(null);
addComponentListener(new ComponentListener() {
#Override
public void componentShown(ComponentEvent arg0) {
}
#Override
public void componentResized(ComponentEvent arg0) {
if (state != -1) {
setExtendedState(state); //Restore the state.
state = -1; //If it is not back to -1, window won't be resized properly by OS.
}
}
#Override
public void componentMoved(ComponentEvent arg0) {
}
#Override
public void componentHidden(ComponentEvent arg0) {
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
FrameState f = new FrameState();
f.setVisible(true);
});
}
}
You can use this code in JButton to maximize and restore JFrame.
In order to perform this function, you have import JFrame even though the JFrame has been extended in your java class.
if(getExtendedState()==NORMAL)
{
setExtendedState(MAXIMIZED_BOTH);
}
else
{
setExtendedState(NORMAL);
}

How to Change Default Inputs for JComboBox and JButton

How do I make the Enter key trigger a JComboBox or JButton in a GUI rather than having to hit the Space key? I have an assortment of text fields and check boxes with buttons and combo boxes in between. I'd like to avoid having to switch between hitting space and enter and rather only have to hit enter for all components.
package koning.personal.dungeonsanddragons;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class test {
JFrame window = new JFrame("testGUI");
JPanel windowPanel = new JPanel();
public static JLabel labelSize;
public static JComboBox<String> comboSize;
public static JLabel labelButton;
public static JButton buttonButton;
public test () {
super();
labelSize = new JLabel("Monster Size:");
String[] sizeChoices = { "None", "Tiny", "Small", "Medium", "Large", "Huge", "Colossal"};
comboSize = new JComboBox<String>(sizeChoices);
comboSize.setToolTipText("The creature's size.");
labelButton = new JLabel("Button:");
buttonButton = new JButton();
windowPanel.setLayout(new FlowLayout());
windowPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
windowPanel.add(labelSize);
windowPanel.add(comboSize);
windowPanel.add(labelButton);
windowPanel.add(buttonButton);
windowPanel.setVisible(true);
window.setSize(500, 500);
window.setLayout(new FlowLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.add(windowPanel);
comboSize.addActionListener(handler);
buttonButton.addActionListener(handler);
}
ActionHandler handler = new ActionHandler();
public class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent eventFocus){
if (eventFocus.getSource() == comboSize){
buttonButton.requestFocusInWindow();
}
if (eventFocus.getSource() == buttonButton){
comboSize.requestFocusInWindow();
}
}
}
#SuppressWarnings("unused")
public static void main(String[] args) {
test GUITest = new test();
}
}
You can add a KeyListener and execute doClick
JButton btn = new JButton();
btn.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER)
btn.doClick();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
});
If the goal is to have something happen when the enter button is pressed (pressed once and something happens with all the components) then you can add a KeyListener to the JFrame:
JFrame frame = new JFrame("Examplpe");
//here you create and add the components to the frame
and then you can add a KeyListener:
frame.addKeyListener(new KeyListener(
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode == KeyEvent.VK_ENTER){//this is the if block I'm refering to in the following explanation
//do something with all the components
}
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {}
}
and then when you press Enter, the code inside the if block will be executed.
Hope this helps :)

Twoway connection between two swing Documents

I am writing a simple Java swing application. I have two JTextPanes. On the first one I can write a html code and on the second one I see the appearience defined by the code. My goal is to provide two-way connection between this textpanes, so that if I type some characters in one pane, I see the changes in the second pane. And that must work in two ways: I can type in both code pane and content pane and changes should be automatically applied to the other pane.
I have tried to use two DocumentListener objects to handle DocumentEvents, but if I change the content of one pane it fires an event and second pane is modifing and also fires an event and this is repeating all the time, so it's not a good way. Setting the same document instance on both text panes also doesn't work.
What should I do? Here is my code. I have an exception IllegalStateException now.
public class TestEditor extends JFrame {
public TestEditor(){
createConnection();
createGUI();
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
JScrollPane scroll1=new JScrollPane(text);
JScrollPane scroll2=new JScrollPane(html);
JSplitPane split=new JSplitPane();
split.setLeftComponent(scroll1);
split.setRightComponent(scroll2);
split.setDividerLocation(0.5);
split.setResizeWeight(0.5);
getContentPane().add(split);
setTitle("Test");
setPreferredSize(new Dimension(600,300));
pack();
}
private void createConnection(){
text=new JTextPane();
html=new JTextPane();
html.setContentType("text/html");
html.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
text.setText(html.getText());
}
#Override
public void removeUpdate(DocumentEvent e) {
text.setText(html.getText());
}
#Override
public void changedUpdate(DocumentEvent e) {
text.setText(html.getText());
}
});
text.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
html.setText(text.getText());
}
#Override
public void removeUpdate(DocumentEvent e) {
html.setText(text.getText());
}
#Override
public void changedUpdate(DocumentEvent e) {
html.setText(text.getText());
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditor().setVisible(true);
}
});
}
private JTextPane text;
private JTextPane html;
}
Try this
import javax.swing.JTextPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JSplitPane;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.text.html.HTMLDocument;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
public final class TwoWayEditor extends JFrame{
private JTextPane textPane;
private JTextPane viewPane;
private JSplitPane contentPane;
private static DocumentListener textPaneDocumentListener;
private static DocumentListener viewPaneDocumentListener;
#Override
protected void frameInit(){
super.frameInit();
this.setVisible(true);
this.setBounds(0,0,500,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.selfInitialize();
}
private void selfInitialize(){
textPane = new JTextPane();
textPane.setContentType("text/plain");
textPane.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e){ textPane.getStyledDocument().addDocumentListener(textPaneDocumentListener);}
#Override
public void focusLost(FocusEvent e){ textPane.getStyledDocument().removeDocumentListener(textPaneDocumentListener); }
});
viewPane = new JTextPane();
viewPane.setContentType("text/html");
viewPane.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e){viewPane.getStyledDocument().addDocumentListener(viewPaneDocumentListener);}
#Override
public void focusLost(FocusEvent e){viewPane.getStyledDocument().removeDocumentListener(viewPaneDocumentListener);}
});
viewPaneDocumentListener = new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent e){
textPane.setText(viewPane.getText());
}
#Override
public void insertUpdate(DocumentEvent e){ textPane.setText(viewPane.getText());}
#Override
public void removeUpdate(DocumentEvent e){ textPane.setText(viewPane.getText());}
};
textPaneDocumentListener = new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent e){
viewPane.setText(textPane.getText());
}
#Override
public void insertUpdate(DocumentEvent e){ viewPane.setText(textPane.getText()); }
#Override
public void removeUpdate(DocumentEvent e){ viewPane.setText(textPane.getText()); }
};
contentPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,textPane,viewPane);
this.setContentPane(contentPane);
contentPane.setDividerLocation(this.getWidth()/2);
}
public static void main(final String [] args){
SwingUtilities.invokeLater(()->{ TwoWayEditor editor = new TwoWayEditor(); });
}
}

No up state JButton

I'm trying to change to appearance of my JButton so that the button have no up state.
Currently i have something like this:
And i would like something like this:(comming from NetBeans)
In other words, I only want the image of the button to be visible when the button does not have any kind of focus. But when the user click or roll over it, it should act exactly the same as a regular button.
more examples:
no focus
roll over
click
I use a inner class for my button. It look like this:
private class CustumJButton extends JButton
{
public CustumJButton(Icon icon)
{
super(icon);
int size = 30;
setPreferredSize(new Dimension(size, size));
setFocusable(false);
}
}
Thanks ayoye.
You can achieve this using setBorderPainted() and setContentAreaFilled() methods. Here is the short Demo of what you are looking for. I hope it would give you rough figure to how to achieve your task.:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class CustomJButton extends JButton
{
public CustomJButton(String icon)
{
super(icon);
/*int size = 30;
setPreferredSize(new Dimension(size, size));*/
addFocusListener(new ButtonFocusAdapter());
addMouseListener(new ButtonMouseAdapter());
setContentAreaFilled(false);
setBorderPainted(false);
//setFocusable(false);//Don't use this method. This would avoid the focus event on JButton
}
private void decorateButton()
{
setContentAreaFilled(true);
setBorderPainted(true);
}
private void unDecorateButton()
{
setContentAreaFilled(false);
setBorderPainted(false);
}
private class ButtonFocusAdapter extends FocusAdapter
{
#Override
public void focusGained(FocusEvent evt)
{
decorateButton();
}
#Override
public void focusLost(FocusEvent evt)
{
unDecorateButton();
}
}
private class ButtonMouseAdapter extends MouseAdapter
{
#Override
public void mouseEntered(MouseEvent evt)
{
decorateButton();
}
#Override
public void mouseExited(MouseEvent evt)
{
unDecorateButton();
}
}
}
public class ButtonFrame extends JFrame
{
public void createAndShowGUI()
{
Container c = getContentPane();
c.setLayout(new FlowLayout());
for (int i = 0; i < 4 ; i++ )
{
CustomJButton cb = new CustomJButton("Button "+i);
c.add(cb);
}
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
ButtonFrame bf = new ButtonFrame();
bf.createAndShowGUI();
bf.setLocationRelativeTo(null);
}
});
}
}
I guess you need to use these two things to make it work, setBorderPainted(boolean) and setContentAreaFilled(boolean)
buttonObject.setBorderPainted(false);
buttonObject.setContentAreaFilled(false);
as cited in this example for changing appearance of JButton by #mKorbel
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ButtonDemo
{
private JButton demoButton;
private ImageIcon buttonImage;
private void displayGUI()
{
JFrame frame = new JFrame("Button Demo Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
try
{
//buttonImage = new ImageIcon(ImageIO.read(
// getClass().getResource("/image/bulb.gif")));
buttonImage = new ImageIcon(ImageIO.read(
new URL("http://gagandeepbali.uk.to/"
+ "gaganisonline/swing/downloads/"
+ "images/bulb.gif")));
}
catch(Exception e)
{
e.printStackTrace();
}
demoButton = new JButton(buttonImage);
setExceptionalState(demoButton);
demoButton.addMouseListener(new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent me)
{
setNormalState(demoButton);
}
#Override
public void mouseExited(MouseEvent me)
{
setExceptionalState(demoButton);
}
});
contentPane.add(demoButton);
frame.setContentPane(contentPane);
frame.setSize(300, 100);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void setExceptionalState(JButton button)
{
button.setBorderPainted(false);
button.setContentAreaFilled(false);
}
private void setNormalState(JButton button)
{
button.setBorderPainted(true);
button.setContentAreaFilled(true);
}
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
#Override
public void run()
{
new ButtonDemo().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
You would set the default state for the button as:
button.setBorderPainted(false);
Then you would need to use a MouseListener:
on mouseEntered you would use
button.setBorderPainted(true);
and on mouse exited you would use
button.setBorderPainted(false);
You should check out the skinnable "Synth Look and Feel", but also be aware that Swing will be deprecated and replaced by JavaFX in the long run. If you are building a new application, you might want to consider using JavaFX which can be skinned with CSS to achieve the effect you are looking for.

JFormattedTextField issues

1) how can I set Cursor to 0 possition without using Caret or Focus wrapped into invokeLater() (confortly can be solved by using #camickr Formatted Text Field Tips), is there somebody who knows another way
2) How to reset Formatter sometimes (by raising Focus by TAB from keyboard), reset doesn't works and on focusLost (empty field) Formatter returns/reincarnated chars or String back (last know before setText("");),
Note: know code or following code is only this way, about how to reset Formatter from OTN, but their terrible search rulles ...., only code (question or answer by Jeanette???)
import java.awt.event.*;
import java.beans.*;
import java.text.ParseException;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.Document;
public class FormattedNull {
private JFormattedTextField field;
private JButton focusButton;
private JComponent createContent() {
JComponent content = new JPanel();
field = new JFormattedTextField(new Integer(55));
field.setColumns(20);
field.addPropertyChangeListener(getPropertyChangeListener());
field.getDocument().addDocumentListener(getDocumentListener());
content.add(field);
focusButton = new JButton("just something focusable");
focusButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
field.setValue(0);
field.requestFocusInWindow();
}
});
content.add(focusButton);
return content;
}
protected void maybeCommitEdit(Document document) {
try {
field.commitEdit();
} catch (ParseException e) {
// uncomment to map empty string to null
if (field.getText().length() == 0) {
field.setValue(null);
}
}
}
/*public void commitEdit() throws ParseException {
if(allowsNull() && isBlank()) {
setValue(null);
}
else {
super.commitEdit();
}
}*/
private PropertyChangeListener getPropertyChangeListener() {
PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("value".equals(evt.getPropertyName())) {
matchValueChanged(evt.getNewValue());
}
}
};
return propertyChangeListener;
}
protected void matchValueChanged(Object value) {
System.out.println("got new value: " + value);
}
private DocumentListener getDocumentListener() {
DocumentListener documentListener = new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
maybeCommitEdit(e.getDocument());
}
#Override
public void insertUpdate(DocumentEvent e) {
maybeCommitEdit(e.getDocument());
}
#Override
public void changedUpdate(DocumentEvent e) {
}
};
return documentListener;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FormattedNull().createContent());
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
}
attached images are based on my sscce
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.MaskFormatter;
public class TestTest {
private JFormattedTextField myFormattedField1 = new JFormattedTextField(createFormatter("AAAAAAAAAAAA"));
private JFormattedTextField myFormattedField2 = new JFormattedTextField(createFormatter("AAAAAAAAAAAA"));
private JFormattedTextField myFormattedField3 = new JFormattedTextField(createFormatter("AAAAAAAAAAAA"));
private JFormattedTextField myFormattedField4 = new JFormattedTextField(createFormatter("AAAAAAAAAAAA"));
private JButton jb = new JButton("Reset to Default");
private JFrame frame = new JFrame("Text Test");
public TestTest() {
myFormattedField1.setText("ABCDEFGHIJKL");
myFormattedField2.setText("ABCDEFGHIJKL");
myFormattedField3.setText("ABCDEFGHIJKL");
myFormattedField4.setText("ABCDEFGHIJKL");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(150, 150);
frame.setLayout(new GridLayout(5, 0));
frame.add(jb);
frame.add(myFormattedField1);
frame.add(myFormattedField2);
frame.add(myFormattedField3);
frame.add(myFormattedField4);
jb.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFormattedField1.setText("");
myFormattedField2.setText("");
myFormattedField3.setText("");
myFormattedField4.setText("");
}
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
TestTest textTest = new TestTest();
}
protected MaskFormatter createFormatter(String s) {
MaskFormatter formatter = null;
try {
formatter = new MaskFormatter(s);
} catch (java.text.ParseException exc) {
System.err.println("formatter is bad: " + exc.getMessage());
}
return formatter;
}
}
On Mac OS, the default behavior of the UI delegate, com.apple.laf.AquaTextFieldF, is similar to CaretPositionListener:
Tab or Shift-Tab: place the caret at the beginning of the field.
Click: briefly place the caret at the beginning of the field and then move it to the click point.
IMO, the CaretPositionListener does the latter much more smoothly.
The default behavior of JFormattedTextField on focus lost is COMMIT_OR_REVERT. In the example below, Tab though the first, invalid field to see the effect. The formatter can neither commit nor revert to the invalid value, so it substitutes MASK.length() spaces. This value is valid, if a little obscure.
Addendum: I've updated the code below to allow changing the setFocusLostBehavior().
Code:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.text.MaskFormatter;
/** #see http://stackoverflow.com/questions/7378821 */
public class TrashTest {
private static final String MASK = "########";
private static final String DEFAULT = "01234567";
private static final String BOGUS = "0123456";
private JFormattedTextField jtf1 = createField();
private JFormattedTextField jtf2 = createField();
private JFormattedTextField jtf3 = createField();
private JFormattedTextField jtf4 = createField();
private JButton reset = new JButton("Reset to Default");
private JComboBox combo = new JComboBox();
private JFrame frame = new JFrame("Text Test");
public TrashTest() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(150, 150);
frame.setLayout(new GridLayout(0, 1));
frame.add(reset);
frame.add(jtf1);
frame.add(jtf2);
frame.add(jtf3);
frame.add(jtf4);
frame.add(combo);
this.initFields();
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initFields();
}
});
for (Edit e : Edit.values()) {
combo.addItem(e);
}
combo.setSelectedIndex(jtf1.getFocusLostBehavior());
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Edit current = (Edit) combo.getSelectedItem();
jtf1.setFocusLostBehavior(current.value);
}
});
frame.pack();
frame.setVisible(true);
}
private void initFields() {
jtf1.setText(BOGUS);
jtf2.setText(DEFAULT);
jtf3.setText(DEFAULT);
jtf4.setText(DEFAULT);
}
protected JFormattedTextField createField() {
MaskFormatter formatter = null;
try {
formatter = new MaskFormatter(MASK);
} catch (java.text.ParseException e) {
e.printStackTrace(System.out);
}
JFormattedTextField jtf = new JFormattedTextField(formatter);
return jtf;
}
enum Edit {
COMMIT(JFormattedTextField.COMMIT),
COMMIT_OR_REVERT(JFormattedTextField.COMMIT_OR_REVERT),
REVERT(JFormattedTextField.REVERT),
PERSIST(JFormattedTextField.PERSIST);
private int value;
private Edit(int n) {
this.value = n;
}
public static Edit getEnum(int n) {
for (Edit e : Edit.values()) {
if (e.value == n) {
return e;
}
}
return Edit.COMMIT_OR_REVERT;
}
}
public static void main(String[] args) {
TrashTest textTest = new TrashTest();
}
}

Categories