Изменить размер JTextField на KeyPress

Я должен расширить размер JTextField для события KeyPressed, когда пользователь вводит текст в текстовое поле. Пожалуйста, дайте мне некоторую идею, как этого добиться?

заранее спасибо

4 ответа

Хорошо, прыгаю за это:-)

Давайте предположим, что вопрос

Как настроить ширину 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 Бали узнал, что это родитель, который должен быть повторно проверен:

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

Неожиданно, поэтому следующий вопрос пресловутый почему? Здесь: почему не делает недействительным пузырьковую иерархию контейнера, пока не найдет validateRoot? Ответ в api doc:

Вызовы для повторной проверки, поступающие из самого текстового поля, будут обрабатываться путем проверки текстового поля, если текстовое поле не содержится в 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);

Платой за это является то, что прокрутка не работает - что не так уж важно в этом контексте, так как текст всегда вписывается в поле. Или реализовать немного более интеллектуально, и вернуть true, если фактическая ширина меньше, чем pref.

Лучший способ, который я могу придумать, - это добавить один CaretListener к JTextField обеспокоенность, а также с изменением длины Document, вы Increase/Decrease колонны сказанного JTextField вызывая его setColumns (...), который будет 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();
            }
        });
    }
}

Зависит от того, используете ли вы LayoutManager или нет. Если нет, прикрепите KeyListener к JTextField и на 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());

    }

});

Я бы также обратил внимание на то, что говорит Клеопатра и mKorbel. В то время как KeyListener Может показаться, что это хорошая идея, но есть много ситуаций, когда об этом не уведомляют - setText является основным.

1) никогда не использовать KeyListener за JTextComponentиспользовать DocumentListener, ничего больше

2) вы можете использовать FontMetrics, TextLayout, SwingUtilities

3) после изменения размера вы должны уведомить LayoutManager,

4) если есть только JTextField затем использовать pack() за Top-Level Container,

5) в противном случае (в случае, если существует более одного JPanel вложенные другие JComponents) вы должны переустановить весь контейнер с revalidate()а также repaint() затем

  • вызов pack() к Top-Level Container если вы хотите постоянно изменять размер с его содержимым

  • не звони pack() к Top-Level Container если вы не хотите изменять размер, но требуется использование JScrollPane

6) в случае, если значение String может быть очень длинным, использовать JTextComponent с поддержкой многострочного вывода в графический интерфейс, чтобы использовать JTextAreaJScrollPane) а не простой JTextField

Другие вопросы по тегам