Le Le problème de base que vous avez, c'est que le text
que vous vérifiez a été rejeté et n'a jamais été appliqué à quoi que ce soit
Par exa mple, si le texte entré est (en supposant un caractère à la fois) 123456789
, alors 8
sera ignoré, car 9
sera envoyé à l'autre champ.
Ce que vous devez faire, est de définir manuellement le texte du champ suivant avec le texte que vous allez ignorer. Maintenant, votre courant a deux défauts fondamentaux.
- Il ne tient pas compte du fait que
replace
devrait supprimer tous les caractères sélectionnés
- ne prend pas en compte ce qui serait arrivé si le texte a été ajouté au champ
- ne prend pas en compte si le texte était inséré dans un autre décalage à la fin du champ
Cet exemple tente de répondre à toutes ces questions
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
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.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);
((AbstractDocument) field1.getDocument()).setDocumentFilter(new LimitDocumentFilter(field2));
add(field1);
add(field2);
}
}
public class LimitDocumentFilter extends DocumentFilter {
private JTextField next;
public LimitDocumentFilter(JTextField next) {
this.next = next;
}
@Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
super.insertString(fb, offset, text, attr);
String textValue = fb.getDocument().getText(0, fb.getDocument().getLength());
if (textValue.length() > 7) {
remove(fb, 7, fb.getDocument().getLength() - 7);
String overflow = textValue.substring(7);
next.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
next.setText(overflow);
next.setCaretPosition(overflow.length());
}
});
}
}
@Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
fb.remove(offset, length);
insertString(fb, offset, text, attrs);
}
}
}
Ce que cela a vraiment besoin est un modèle de délégué, où par la place de l'DocumentFilter
changement d'orientation sur le terrain, il délègue cette responsabilité à un autre observateur, faisant passer le texte de trop-plein
Mise à jour
Ok, donc c'est une version mise à jour qui fournit trois façons que le texte peut être réglé:
- directement via
setText
- Collé du presse-papiers
- coups clés injectés dans la mémoire tampon du clavier via
Robot
Cela fournit le meilleur exemple possible de la façon dont un scanner de code-barres « pourrait » travailler
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
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.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);
LimitDocumentFilter filter = new LimitDocumentFilter();
filter.add(new LimitListener() {
@Override
public void limitReached(LimitDocumentFilter filter, String overflow) {
// This is to overcome the issue of MacOS autoselecting the
// text when it gets focus ... dumb
FocusListener[] listeners = field2.getFocusListeners();
for (FocusListener listener : listeners) {
field2.removeFocusListener(listener);
}
field2.setText(overflow);
field2.requestFocusInWindow();
field2.setCaretPosition(overflow.length());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (FocusListener listener : listeners) {
field2.addFocusListener(listener);
}
}
});
}
});
((AbstractDocument) field1.getDocument()).setDocumentFilter(filter);
add(field1);
add(field2);
JButton sim = new JButton("Simulate");
sim.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
field1.setText(null);
field2.setText(null);
field1.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Thread t = new Thread(new Simulator());
t.start();
}
});
}
});
JButton paste = new JButton("Paste");
paste.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
field1.setText(null);
field2.setText(null);
String text = "1234567abcdefg";
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(text), null);
field1.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
field1.paste();
}
});
}
});
JButton set = new JButton("Set");
set.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
field1.setText(null);
field2.setText(null);
field1.setText("1234567abcdefghijklmnopqrstuvwxyz");
}
});
add(sim);
add(paste);
add(set);
}
}
public class Simulator implements Runnable {
@Override
public void run() {
try {
Robot bot = new Robot();
type(KeyEvent.VK_1, bot);
type(KeyEvent.VK_2, bot);
type(KeyEvent.VK_3, bot);
type(KeyEvent.VK_4, bot);
type(KeyEvent.VK_5, bot);
type(KeyEvent.VK_6, bot);
type(KeyEvent.VK_7, bot);
type(KeyEvent.VK_A, bot);
type(KeyEvent.VK_B, bot);
type(KeyEvent.VK_C, bot);
type(KeyEvent.VK_D, bot);
type(KeyEvent.VK_E, bot);
type(KeyEvent.VK_F, bot);
type(KeyEvent.VK_G, bot);
} catch (AWTException ex) {
ex.printStackTrace();
}
}
protected void type(int keyStoke, Robot bot) {
bot.keyPress(keyStoke);
bot.keyRelease(keyStoke);
}
}
public interface LimitListener {
public void limitReached(LimitDocumentFilter filter, String overflow);
}
public class LimitDocumentFilter extends DocumentFilter {
private List<LimitListener> listeners = new ArrayList<>(25);
public LimitDocumentFilter() {
}
public void add(LimitListener listener) {
listeners.add(listener);
}
public void remove(LimitListener listener) {
listeners.remove(listener);
}
protected void limitReached(String overflow) {
for (LimitListener listener : listeners) {
listener.limitReached(this, overflow);
}
}
@Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
super.insertString(fb, offset, text, attr);
String textValue = fb.getDocument().getText(0, fb.getDocument().getLength());
if (textValue.length() > 7) {
remove(fb, 7, fb.getDocument().getLength() - 7);
String overflow = textValue.substring(7);
limitReached(overflow);
}
}
@Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
fb.remove(offset, length);
insertString(fb, offset, text, attrs);
}
}
}
Le point où vous décidez de transférer le focus, la valeur ('1' dans ce cas) est maintenant ignoré, mais il a déjà été lu.Vous devez utiliser la valeur 'text' transmise à la méthode' replace' et l'appliquer au champ suivant. – MadProgrammer
Vous devez également savoir que si le champ a une valeur de '12345' et que j'ajoute' 56789' (en le collant pour exemple), votre code va rejeter le texte entier – MadProgrammer