Изменить размер 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
с поддержкой многострочного вывода в графический интерфейс, чтобы использовать JTextArea
(в JScrollPane
) а не простой JTextField