I have to extend the size of JTextField on KeyPressed event as user enter the text in textfield.please give me some idea how to achieve this?
thanks in advance
1) never to use KeyListener
for JTextComponent
, use DocumentListener
, nothing else
2) you can to use FontMetrics
, TextLayout
, SwingUtilities
3) after resize you have to notify LayoutManager
,
4) if is there only JTextField
then to use pack()
for Top-Level Container
,
5) otherwise (in the case that there is more than one JPanel
nested other JComponents
) you have to re_layout whole Container with revalidate()
and repaint()
then
call pack()
to the Top-Level Container
if you want to resize continiously with its contens
don't call pack()
to the Top-Level Container
if you don't want to resize, but required usage of JScrollPane
6) in the case that value of String could be very long, then to use proper JTextComponent
with supporting multiline output to the GUI, to use JTextArea
(in JScrollPane
) rather than plain JTextField
The best way I can think of is to add one CaretListener to the JTextField
concerned, and with the change in the length of the Document
, you Increase/Decrease
the columns of the said JTextField
by calling it's setColumns(...), which inturn will Increase/Decrease
the size of the JTextField
Here is one example to show you, how to achieve this :
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();
}
});
}
}
Okay, jumping for it :-)
Let's assume the question is
How to adjust a JTextField's width to always fit its content width?
Usual collaborators
Quick example:
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);
type ... and nothing happens: size remains at initial size. That's surprise: for some reason, the field's auto-validation simply doesnt't happen. In fact, a manual revalidate of the field on receiving a change notification (Note: the only correct listener type here is a DocumentListener) doesn't change the field as well:
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 found out that it's the parent that needs to be revalidated:
private void updateField(JTextField field) {
field.getParent().revalidate();
}
Unexpected, so the next question is the notorious why? Here: why doesn't the invalidate bubble up the container hierarchy until it finds a validateRoot? The answer is in the api doc:
Calls to revalidate that come from within the textfield itself will be handled by validating the textfield, unless the textfield is contained within a JViewport, in which case this returns false.
Or in other words: it's not bubbled up because the field itself is a validateRoot. Which leaves the other option to override and unconditionally return 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);
The price to pay for this, is that the scrolling doesn't work - which isn't a big deal in this context, as the text always fits into the field. Or implement slightly more intelligent, and return true if the actual width is less than the pref.
Depends if you are using a LayoutManager or not. If not, attach a KeyListener
to the JTextField
and on keyRelease
you need to calculate the length of the String (in pixels) and determine if the field needs to be updated
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();
}
});
Possibly a more sensible solution might be:
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());
}
});
I would also pay attention to what kleopatra & mKorbel have to say. While KeyListener
might seem like a good idea, there are just to many situation's where it won't be notified - setText
is the major one.