在KeyPress上更改JTextField的大小



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

提前感谢

好的,跳起来:-)

假设问题是

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

通常的合作者

  • 一个LayoutManager,按照其子级的首选大小(例如FlowLayout)对其进行大小调整
  • JTextField报告其符合内容的pref大小
  • 应自动调整魔法大小

快速示例:

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之前,invalidate不弹出容器层次结构?答案在api文档中:

来自文本字段本身的重新验证调用将通过验证文本字段来处理,除非文本字段包含在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。

我能想到的最好的方法是向相关的JTextField添加一个CaretListener,随着Document长度的变化,通过调用它的setColumns(…)来Increase/Decrease所述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();
            }
        });
    }
}

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

2) 您可以使用FontMetricsTextLayoutSwingUtilities

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

4) 如果只有JTextField,则将pack()用于Top-Level Container

5) 否则(在有多个JPanel嵌套其他JComponents的情况下),您必须重新布局带有revalidate()repaint()的整个容器,然后是

  • 如果您想与内容连续调整大小,请将pack()调用到Top-Level Container

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

6) 在String的值可能很长的情况下,使用适当的JTextComponent并支持到GUI的多行输出,使用JTextArea(在JScrollPane中)而不是普通的JTextField

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

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&科贝尔先生不得不说。虽然KeyListener看起来是个好主意,但在很多情况下它都不会得到通知——setText是主要的。

相关内容

  • 没有找到相关文章

最新更新