Reputation: 3
When I enter the TextField 7 character, the cursor moved automatically moved to next TextField. But in my code, my cursor did not goes to nextField. (I knew i can't use the addKeyListener, so tried to use DocumentListener for this code)
lbltext1 = new JLabel("Text1");
panel.add(lbltext1, "cell 0 1,alignx trailing");
final int maxSize =7 ;
for (int i = 0; i < 1; i++) {
final JTextField txtText1 = new JTextField();
NavigationFilter filter = new NavigationFilter() {
@Override
public void setDot(FilterBypass fb, int dot, Bias bias) {
if (dot >= maxSize) {
fb.setDot(0, bias);
txtText1.transferFocus();
return;
}
fb.setDot(dot, bias);
}
@Override
public void moveDot(FilterBypass fb, int dot, Bias bias) {
if (dot >= maxSize) {
fb.setDot(0, bias);
txtText1.transferFocus();
return;
}
fb.moveDot(dot, bias);
}
};
txtText1.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent arg0) {
if (txtText1.getText().equals("")) {
txtDate.setText("");
} else {
SwingWorker<?, ?> job = new UIQuery();
job.execute();
}
}
});
txtText1.setNavigationFilter(filter);
((AbstractDocument) txtText1.getDocument()).setDocumentFilter(new DocumentSizeFilter(maxSize));
panel.add(txtText1, "cell 1 1,growx");
txtText1.setColumns(10);
}
JLabel lblText2 = new JLabel("Production Date");
panel.add(lblText2, "cell 0 2,alignx trailing");
txtText2 = new JTextField();
panel.add(txtText2, "flowx,cell 1 2,growx");
txtText2.setColumns(10);
txtText2.addFocusListener(new TextBoxGainedFocusEventSinglePreview());
txtText2.getDocument().addDocumentListener(new TextBoxDataChangedEventSinglePreview());
Please advise how should I modify it. Thanks
Upvotes: 0
Views: 243
Reputation: 324147
Don't know what the better design is:
You have a solution for the first approach.
For the second approach you can check out:
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
import javax.swing.text.JTextComponent;
/**
* A DocumentFilter that allows you to control the maximum number of
* characters that can be added to the Document. When the Document is
* full you can optionally tab to the next component to speed data entry.
*
* This class can also be used as a generic size filter for JTextFields. In
* this case when a size of 0 is speicifed for the size of the Document the
* getColumns() method of JTextField will be used to determine the size
* restriction.
*/
public class TabDocumentFilter extends DocumentFilter
{
private int size;
private boolean autoTab = true;
/**
* Generic constructor for use with JTextFields only. The size of the
* Document will be determined by the value of the getColumns() method.
*/
public TabDocumentFilter()
{
this(0);
}
/**
* Constructor to set the size for this filter
*
* @param size maximum number of characters to be added to the Document
*/
public TabDocumentFilter(int size)
{
setSize( size );
}
/**
* Get the auto tab property
*
* @return the auto tab property
*/
public boolean getAutoTab()
{
return autoTab;
}
/**
* Set the auto tab property
*
* @param autoTab the default is true
*/
public void setAutoTab(boolean autoTab)
{
this.autoTab = autoTab;
}
/**
* Get the maximum size for any Document using this filter
*
* @return
*/
public int getSize()
{
return size;
}
/**
* Set maximum size for a Document using this filter. Dynamically changing
* the size will not affect existing Documents. Characters will not be
* removed from any Document. The filter will only be invoked on new
* additions to the Document.
*
* @param size the maximum number of character allowed in the Document
*/
public void setSize(int size)
{
this.size = size;
}
/**
* Install this filter on the AbstractDocument
*
* @param components the text components that will use this filter
*/
public void installFilter(JTextComponent... components)
{
for (JTextComponent component : components)
{
Document doc = component.getDocument();
if (doc instanceof AbstractDocument)
{
((AbstractDocument)doc).setDocumentFilter( this );
}
}
}
/**
* Make sure the insertion of text will not cause the Document to exceed
* its size limit. Also, potentially tab to next component when full.
*/
@Override
public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
throws BadLocationException
{
int possibleSize = fb.getDocument().getLength() + str.length();
int allowedSize = getAllowedSize( fb );
if (possibleSize <= allowedSize)
{
super.insertString(fb, offs, str, a);
handleAutoTab(possibleSize, allowedSize, fb);
}
else
{
Toolkit.getDefaultToolkit().beep();
}
}
/**
* Make sure the replacement of text will not cause the Document to exceed
* its size limit. Also, potentially tab to next component when full.
*/
@Override
public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
throws BadLocationException
{
int possibleSize = fb.getDocument().getLength() + str.length() - length;
int allowedSize = getAllowedSize( fb );
if (possibleSize <= allowedSize)
{
super.replace(fb, offs, length, str, a);
handleAutoTab(possibleSize, allowedSize, fb);
}
else
{
Toolkit.getDefaultToolkit().beep();
}
}
/**
* When a size isn't specified then we assume the desired size can be
* obtained from the associated text field. Otherwise, use the class
* size property.
*/
private int getAllowedSize(FilterBypass fb)
{
return (size == 0) ? getColumns(fb) : size;
}
/*
* Use the value returnd by invoking the getColumns() method of JTextField
*/
private int getColumns(FilterBypass fb)
{
// Find the text field that currently has focus
// and make sure it is using the Document that will be updated
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (c != null && c instanceof JTextField)
{
JTextField textField = (JTextField)c;
Document doc = textField.getDocument();
if (doc.equals( fb.getDocument() ))
{
return textField.getColumns();
}
}
return 0;
}
/*
* When the Document is full tab to the next component.
*/
protected void handleAutoTab(int possibleSize, int allowedSize, FilterBypass fb)
{
if (autoTab == false
|| possibleSize != allowedSize)
return;
// Find the text field that currently has focus
// and make sure it is using the Document that has been updated
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (c != null && c instanceof JTextComponent)
{
JTextComponent component = (JTextComponent)c;
Document doc = component.getDocument();
if (doc.equals( fb.getDocument() ))
{
c.transferFocus();
}
}
}
}
To use it you can do something like:
TabDocumentFilter tf = new TabDocumentFilter();
tf.installFilter( textField1, textField2 );
The characters of each text field will be limited based on the number of columns specified for the text field and auto tabbing will occur.
The above solution was based on the solution proposed in Text Field Auto Tab, which provided an approach for nesting DocumentFilters.
Upvotes: 1
Reputation: 347314
So, this is a simple proof of concept, which will move focus from the current component to the next when than field's Document
length > 6
import java.awt.KeyboardFocusManager;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JTextField field1 = new JTextField(7);
JTextField field2 = new JTextField(7);
add(field1);
add(field2);
field1.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
if (e.getDocument().getLength() > 6) {
//field1.transferFocus();
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
}
}
@Override
public void removeUpdate(DocumentEvent e) {
}
@Override
public void changedUpdate(DocumentEvent e) {
if (e.getDocument().getLength() > 6) {
//field1.transferFocus();
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
}
}
});
}
}
}
When something doesn't work, start by removing everything that's not needed to test it (ie the DocumentFilter
and NavigationFilter
), get it working in as an isolated state as you can, once you know it's working, re-introduce the other elements one at a time and ensure nothing breaks.
It's possible that the DocumentSizeFilter
might be interfering with it, but I don't have enough context to be 100% sure
Upvotes: 2