如何在JTextField中分发字符

时间:2015-05-29 12:29:33

标签: java swing jtextfield multiple-columns kerning

是否可以像这样在JTextField中分发字符串:(" bruno"在蓝色文本字段中)。

JTextField自动划分为许多等间距位置作为最大列值 enter image description here

我编写此代码来解释为什么字体跟踪对我不起作用:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.font.TextAttribute;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class SpacedFieldTest extends JFrame{

    Map<TextAttribute, Object> fontAttributes = new HashMap<TextAttribute,     Object>();
    int maxColumn;
    String text;
    public SpacedFieldTest(String text, int maxColumn) {
        this.text = text;
        this.maxColumn = maxColumn;
        addContent();
        pack();
    }

    private void addContent() {
        setLayout(new FlowLayout());
        final SpacedField field = new SpacedField();
        configureField(field, "Arial", 20f);
        getContentPane().add(field);

        JSpinner spinner = createSpinner(field);
        getContentPane().add(spinner);

        JLabel tracking = new JLabel("Tracking");
        getContentPane().add(tracking);
    }

    private JSpinner createSpinner(final SpacedField field) {
        float min = 0.0f;
        float value = 0.1f;
        float max = 3.0f;
        float stepSize = 0.1f;
            SpinnerNumberModel model = new SpinnerNumberModel(value, min,     max, stepSize);
            JSpinner spinner = new JSpinner(model){
                @Override
                public Object getValue() {
                    fontAttributes.put(TextAttribute.TRACKING,     super.getValue());
                        field.setFont(field.getFont().deriveFont(fontAttributes));
                    return super.getValue();
                }

            };
        spinner.setPreferredSize(new Dimension(50,25));
        JSpinner.NumberEditor editor =     (JSpinner.NumberEditor)spinner.getEditor();
        DecimalFormat format = editor.getFormat();
        format.setMinimumFractionDigits(1);
        return spinner;
    }

    private void configureField(JTextField field, String family, float     fontSize) {

        fontAttributes.put(TextAttribute.SIZE, fontSize);
        fontAttributes.put(TextAttribute.FAMILY, family);
        Font font = Font.getFont(fontAttributes);
        field.setFont(font);
        field.setText(text);
    }

    class SpacedField extends JTextField{
        final int WIDTH = 300;
        final int HEIGHT = 25;
        int gridWidth;
        public SpacedField() {

            gridWidth = WIDTH/maxColumn;
            setPreferredSize(new Dimension(WIDTH, HEIGHT));
            setDocument(new SpacedFieldDocument());
        }
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            paintGrid(g);
        }
        private void paintGrid(Graphics g) {
            for(int i=1; i<=maxColumn; i++){
                g.drawLine(i*gridWidth, HEIGHT/2, i*gridWidth, HEIGHT);
            }

        }
    }

    class SpacedFieldDocument extends PlainDocument{
        public void insertString(int offs, String str, AttributeSet a)
                throws BadLocationException {

            if(getLength()>maxColumn)
                return;
            super.insertString(offs, str, a);
        }
    }

    public static void main(String args[]){

        final SpacedFieldTest sf = new SpacedFieldTest("abcde", 5);
        sf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                sf.setVisible(true);
            }
        });
    }
}

1 个答案:

答案 0 :(得分:0)

可能的肥胖型。

您要做的是为每个可用字符设置单独的JTextField。这最好作为一个独立的类实现,扩展JComponent,但这取决于你。

我建议在初始化程序中抛出这些:

private final LinkedList<JTextField> fields = new LinkedList<>();
private KeyListener fieldKeyListener = new KeyListener(){

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() != KeyEvent.VK_BACK_SPACE && e.getKeyCode() != KeyEvent.VK_DELETE) {
            System.out.println("Key code: " + e.getKeyCode());
            int index = fields.indexOf(e.getSource());
            int newIndex = index + 1;
            if(newIndex < fields.size()) fields.get(newIndex).requestFocus();
            else
                System.out.println(gatherString());
                //or use whichever action should retrieve the string
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

};

对于它的肉,你会想要这样做。我继续在JFrame的中间即时构建它,但如果你可以想象不止一次这样做,你会想要将它改编为构造函数的初始化器。

private JComponent getDistField() {
    JPanel panel = new JPanel();
    panel.setLayout(new GridLayout(1, charCount));

    for(int i = 0; i < charCount; i++) {
        fields.add(new JTextField(1));

        /* All customizations to look and feel, for each component, go here */

        //document must be unique for each field, or text will duplicate.
        fields.getLast().setDocument(new PlainDocument(){
            @Override
            public void insertString(int offs, String str, AttributeSet a)
                    throws BadLocationException {
                if(getLength() + str.length() <= 1)
                    super.insertString(offs, str, a);
            }
        });
        fields.getLast().addKeyListener(fieldKeyListener);
        panel.add(fields.getLast());
    }

    return panel;
}

我假设&#34; charCount&#34;为字段接受的字符数提前设置(或甚至作为参数传入)。迭代器创建一系列子文本字段;每个都将处理一个字符并立即更新插入符号的位置。请注意,文档需要对每个字段都是唯一的,否则文本将在整个过程中自行复制!

理论上,您也可以使用插入符号侦听器而不是键侦听器来执行此操作;然而,它们与按键相切并且完全不知道哪个键刚刚关闭。并不意味着它无法弄清楚,但我找不到一个干净的方法去做。

当您准备好输入所输入字符串的完整内容时,请调用以下内容:

public String gatherString() {
    StringBuilder builder = new StringBuilder();
    for(JTextField field : fields) {
        builder.append(field.getText());
    }
    return builder.toString();
}

它从每个字段的内容汇集字符串。值得庆幸的是,空字段没有贡献;如果你想要它们也是不可编辑的,你可以尝试将它们设置为禁用并触发它们在它们之前的字段的填充;甚至添加一个鼠标监听器,找到最后一个未编辑的字段,并在任何点击时突出显示它。这完全是关于听众(/观察者)的。

希望这会为你做到,我相信你可以明白为什么你可能希望这是它自己的模块。祝你好运!

此外,如果您将来查看问题的正确格式,它将非常有用。我无法在当前条件下对其进行投票,社区将更好地收到它。它可以帮助您研究"How do I ask a good question?"