javaswingfocustextfieldscrollpane

Scroll to focused textfield


So,i have a bunch of textfields inside a scrollpane. More textfields are added when the user focuses the last one from the bottom. My question is,how can i make the scrollpane scroll to the focused textfield ? I mean,the user will press TAB or ENTER to jump to the next textfield but he won't be able to see it without scrolling himself. I could simulate pressing the down arrow or PageDown when the last textfield has focus but that would be ugly,even if it would do what i need to.

I tried something like this from what i've found thru searching but i couldn't make it work.

public void focusGained(FocusEvent e) {
            currentview = t1;
            int cons = i - 1;
             Rectangle r = new Rectangle(t1.getX(), t1.getY(), 1, 1);
            jScrollPane1.scrollRectToVisible(r);
            if (t1.getName().equals("prod" + cons)) {

                newproduct();
            };

        }

Solution

  • Two things arise.

    Firstly, JTextField#scrollRectToVisible has being overridden and does something slightly different from other components...annoying....

    Secondly, you need to be converting the fields location relative to the it's parent and then using the parent's scrollRectToVisible method, for example...

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Rectangle;
    import java.awt.event.FocusAdapter;
    import java.awt.event.FocusEvent;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ScrollFocusedField {
    
        public static void main(String[] args) {
            new ScrollFocusedField();
        }
    
        public ScrollFocusedField() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    FocusAdapter fh = new FocusAdapter() {
    
                        @Override
                        public void focusGained(FocusEvent e) {
                            JComponent comp = (JComponent) e.getComponent();
                            System.out.println("FocusGained");
                            Rectangle bounds = comp.getBounds();
                            bounds.setLocation(SwingUtilities.convertPoint(comp, bounds.getLocation(), comp.getParent()));
    
                            JComponent parent = (JComponent) comp.getParent();
                            parent.scrollRectToVisible(comp.getBounds());
                        }
    
                    };
    
                    JPanel panel = new JPanel(new GridBagLayout());
                    GridBagConstraints gbc = new GridBagConstraints();
                    for (int index = 0; index < 100; index++) {
                        gbc.fill = GridBagConstraints.NONE;
                        gbc.weightx = 0;
                        gbc.gridx = 0;
                        gbc.gridy = index;
                        panel.add(new JLabel(Integer.toString(index)), gbc);
    
                        JTextField field = new JTextField();
                        field.addFocusListener(fh);
                        gbc.fill = GridBagConstraints.HORIZONTAL;
                        gbc.weightx = 1;
                        gbc.gridx = 1;
                        panel.add(field, gbc);
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JScrollPane(panel));
                    frame.setSize(200, 400);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
    }