在KeyPress上更改JTextField的大小

时间:2012-07-30 07:06:47

标签: java swing layout graphics jtextfield

当用户在textfield中输入文本时,我必须在KeyPressed事件上扩展JTextField的大小。请告诉我如何实现这个目标?

提前致谢

4 个答案:

答案 0 :(得分:5)

好的,跳过它: - )

让我们假设问题是

  

如何调整JTextField的宽度以始终适合其内容宽度?

通常的合作者

  • 一个LayoutManager,它将其子节点的大小调整为f.i.的FlowLayout
  • JTextField报告其内容大小符合内容
  • 预计会自动调整魔法大小

快速举例:

JTextField field = new JTextField("something");
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

键入...并且没有任何反应:大小保持初始大小。令人惊讶的是:出于某种原因,该领域的自动验证根本不会发生。实际上,在接收更改通知时手动重新验证字段(注意:此处唯一正确的侦听器类型是DocumentListener)也不会更改字段:

final JTextField field = new JTextField("something");
DocumentListener l = new DocumentListener() {

    private void updateField(JTextField field)
        // has no effect
        field.revalidate();
    }


    @Override
    public void removeUpdate(DocumentEvent e) {
        updateField(field);
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        updateField(field);
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
   }
};

field.getDocument().addDocumentListener(l);
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

@Gagandeep Bali发现它是需要重新验证的

private void updateField(JTextField field) {
    field.getParent().revalidate();
}

出乎意料,所以下一个问题是臭名昭着的为什么?这里:为什么在找到validateRoot之前,容器层次结构中的无效泡沫是什么?答案在api doc中:

  

来自textfield本身的重新验证调用将通过验证textfield来处理,除非textfield包含在JViewport中,在这种情况下返回false。

或换句话说:它没有冒泡,因为字段本身 是validateRoot。这使得另一个选项覆盖并无条件地返回false:

JTextField field = new JTextField("something") {

    @Override
    public boolean isValidateRoot() {
        return false;
    }
};
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

为此付出的代价是滚动不起作用 - 在这种情况下这并不重要,因为文本总是适合该领域。或者实现稍微更智能,如果实际宽度小于pref,则返回true。

答案 1 :(得分:3)

我能想到的最好方法是向相关的JTextField添加一个CaretListener,并且Document的长度发生变化,Increase/Decrease通过调用setColumns(...)来表示所述JTextField的列,其中Increase/Decrease的大小将JTextField

以下是向您展示如何实现此目标的一个示例:

import java.awt.*;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

public class JTextFieldColumnExample
{
    private int columns = 1;
    private JTextField tfield;

    private void displayGUI()
    {
        JFrame frame =  new JFrame("JTextField Columns Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel contentPane = new JPanel();
        tfield = new JTextField();
        tfield.setColumns(columns);
        tfield.addCaretListener(new CaretListener()
        {
            public void caretUpdate(CaretEvent ce)
            {
                int len = tfield.getDocument().getLength();
                if (len > columns)
                    tfield.setColumns(++columns);
                else
                {
                    if (--columns != 0)
                        tfield.setColumns(columns);
                    else
                    {
                        columns = 1;
                        tfield.setColumns(columns);
                    }   
                }   
                contentPane.revalidate();
                contentPane.repaint();
            }
        });

        contentPane.add(tfield);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new JTextFieldColumnExample().displayGUI();
            }
        });
    }
}

答案 2 :(得分:2)

取决于您是否使用LayoutManager。如果没有,请将KeyListener附加到JTextFieldkeyRelease,您需要计算字符串的长度(以像素为单位)并确定是否需要更新字段

addDocumentListener(new DocumentListener() {

    public void changedUpdate(DocumentEvent e) {
        updateField();
    }

    public void insertUpdate(DocumentEvent e) {
        updateField();
    }

    public void removeUpdate(DocumentEvent e) {
        updateField();
    }

    public void updateField() {

        FontMetrics fm = getFontMetrics(getFont());
        String text = getText();

        int length = fm.stringWidth(text);

        Dimension size = getPreferredSize();
        Insets insets = getInsets();
        if (length < min) {

            size.width = min;

        } else {

            size.width = length + (insets.left + insets.right);

        }

        setSize(size);
        invalidate();
        repaint();

    }

});

可能更合理的解决方案可能是:

addDocumentListener(new DocumentListener() {

    public void changedUpdate(DocumentEvent e) {
        updateField();
    }

    public void insertUpdate(DocumentEvent e) {
        updateField();
    }

    public void removeUpdate(DocumentEvent e) {
        updateField();
    }

    public void updateField() {

        setColumns(getText().length());

    }

});

我也会关注什么是kleopatra&amp; mKorbel不得不说。虽然KeyListener似乎是一个好主意,但在很多情况下,它不会被通知 - setText是主要的。

答案 3 :(得分:2)

1)永远不要将KeyListener用于JTextComponent,使用DocumentListener,其他任何内容

2)您可以使用FontMetricsTextLayoutSwingUtilities

3)调整大小后,您必须通知LayoutManager

4)如果只有JTextField,那么pack()使用Top-Level Container

5)否则(如果有多个JPanel嵌套的其他JComponents),您必须使用revalidate()repaint()重新布局整个Container

  • 如果您想继续使用其竞争对象调整pack(),请致电Top-Level Container

  • 如果您不想调整大小,请不要致电pack() Top-Level Container,但需要使用JScrollPane

6)如果String的值可能很长,那么使用适当的JTextComponent支持多行输出到GUI,使用JTextArea(在JScrollPane中)比普通JTextField