change the size of JTextField on KeyPress

前端 未结 4 1073
臣服心动
臣服心动 2021-01-28 07:12

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

相关标签:
4条回答
  • 2021-01-28 07:40

    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

    0 讨论(0)
  • 2021-01-28 07:41

    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();
                }
            });
        }
    }
    
    0 讨论(0)
  • 2021-01-28 07:42

    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

    • a LayoutManager which sizes its children at their pref size, f.i. FlowLayout
    • JTextField reports its pref size fitted to content
    • auto-magical resize expected

    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.

    0 讨论(0)
  • 2021-01-28 07:46

    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.

    0 讨论(0)
提交回复
热议问题