【问题标题】:Barcode scanning using DocumentFilter in Java在 Java 中使用 DocumentFilter 进行条码扫描
【发布时间】:2017-03-15 01:45:16
【问题描述】:

我的条形码包括"1039723170303CC15-78" 我使用 DocumentFilter 的原因是我只想将数字限制为7 digit。 其余数字自动转到第二个文本字段。

我的代码仅适用于 7 位数字,并非所有其余数字都进入下一个文本字段。 (即,"1039723" 转到第一个 textField 和 "70303CC15-78" 转到第二个 textFiled。"1" 在第二个 textFiled 中丢失。

我该如何解决这个问题?

lblTest = new JLabel("Testing : ");
panel.add(lblText, "cell 0 1,alignx trailing");

txtTest = new JTextField(7);

 AbstractDocument d = (AbstractDocument) txtTest.getDocument();
 d.setDocumentFilter(new DocumentFilter() {
     @Override  
        public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException  
        {
            if(fb.getDocument().getLength()+string.length()>7)
            {                       
                return;                     
            }
            fb.insertString(offset, string, attr);                  
        }  


        @Override  
        public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException 
        {                   
            fb.remove(offset, length);
        }


        @Override  
        public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs)throws BadLocationException 
        {  
                 if(fb.getDocument().getLength()+text.length()>7)
                 {
                     txtTest.transferFocus();
                    System.out.println("print.." +txtTest.getText());
                    return;
                }
                fb.insertString(offset, text, attrs);
        }
 });

打印输出:

print Mo No.:1039723
print Mo No.:1039723
print Mo No.:1039723

【问题讨论】:

  • 您决定转移焦点的点,即值(在本例中为1)现在被忽略,但它已经被读取。您应该使用传递给replace 方法的text 值并将其应用于下一个字段
  • 您还应该知道,如果该字段的值为 12345 并且我附加了 56789(例如通过粘贴),您的代码将拒绝整个文本

标签: java swing barcode-scanner documentfilter


【解决方案1】:

您遇到的基本问题是,您正在检查的 text 已被丢弃并且从未应用于任何内容。

例如,如果输入的文本是(假设一次一个字符)123456789,则 8 将被忽略,因为 9 将被发送到另一个字段。

你需要做的,是手动设置下一个字段的文本与你要忽略的文本。

现在,您的当前有两个根本缺陷。

  1. 它没有考虑replace 应该删除任何选定的字符这一事实
  2. 不考虑如果将文本附加到字段会发生什么
  3. 不考虑是否在字段末尾以外的偏移处插入文本

这个例子试图回答所有这些问题

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);
        }
    }

}

这真正需要的是一个委托模型,而不是 DocumentFilter 改变字段焦点,它将责任委托给其他观察者,并将溢出文本传递给它

更新

好的,这是一个更新版本,它提供了三种设置文本的方式:

  1. 直接通过setText
  2. 从剪贴板粘贴
  3. 通过Robot 注入键盘缓冲区的击键

这提供了条形码扫描器“可能”如何工作的最佳示例

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);
        }
    }

}

【讨论】:

  • ....."String overflow = textValue.substring(7);" 出现溢出错误,所以我必须像"final String overflow = textValue.substring(7);" 那样做
  • 仍在使用 Java 6?这就是委托模型可以提供帮助的地方;)
  • @MadProgrammer...它只限制前 7 位数字,在 7 位数字之后,所有数字随机跳到然后下一个文本字段....=(
  • 没有条码扫描器很难测试:P
  • @Augustine 我已经完成了更新,这个“应该”接近正确,MacOS(我正在测试)存在问题,因为它会在字段获得焦点时自动选择文本我似乎无法阻止它
猜你喜欢
  • 2021-04-05
  • 2012-07-17
  • 2014-11-04
  • 1970-01-01
  • 2022-11-08
  • 2020-10-06
  • 1970-01-01
  • 2017-01-30
  • 1970-01-01
相关资源
最近更新 更多