简体   繁体   English

滚动到焦点文本字段

[英]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.我的意思是,用户将按 TAB 或 ENTER 键跳转到下一个文本字段,但如果不滚动自己将无法看到它。 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.当最后一个文本字段具有焦点时,我可以模拟按下向下箭头或 PageDown,但这会很难看,即使它会做我需要的。

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();
            };

        }

Two things arise. 出现两件事。

Firstly, JTextField#scrollRectToVisible has being overridden and does something slightly different from other components...annoying.... 首先, JTextField#scrollRectToVisible已被覆盖,并且与其他组件有些不同……令人讨厌。

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... 其次,您需要转换相对于其父级的字段位置,然后使用父级的scrollRectToVisible方法,例如...

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);
            }
        });
    }

}

Check out the FormScroller . 检出FormScroller It is a simple class you can use to make sure the component will be visible when you tab to the component. 这是一个简单的类,可用于确保在您选择组件时可以看到该组件。 The FormScroller can be used with any scrollpane and there is no need to add FocusListeners to every component on the form. FormScroller可以与任何滚动窗格一起使用,并且无需将FocusListeners添加到表单上的每个组件。

It provides a few options that allows you do control exactly how the scrolling works. 它提供了一些选项,使您可以精确控制滚动的工作方式。

I solved this with a custom focus traversal policy.我用自定义焦点遍历策略解决了这个问题。 It wraps the container's original traversal policy and queues scroll requests when the next or previous component is requested:它包装了容器的原始遍历策略,并在请求下一个或上一个组件时对滚动请求进行排队:

private static class FocusTraversalPolicyAdapter extends FocusTraversalPolicy {
    FocusTraversalPolicy focusTraversalPolicy;

    FocusTraversalPolicyAdapter(FocusTraversalPolicy focusTraversalPolicy) {
        this.focusTraversalPolicy = focusTraversalPolicy;
    }

    @Override
    public Component getComponentAfter(Container container, Component component) {
        var nextComponent = focusTraversalPolicy.getComponentAfter(container, component);

        scrollToVisible(nextComponent);

        return nextComponent;
    }

    @Override
    public Component getComponentBefore(Container container, Component component) {
        var previousComponent = focusTraversalPolicy.getComponentBefore(container, component);

        scrollToVisible(previousComponent);

        return previousComponent;
    }

    @Override
    public Component getFirstComponent(Container container) {
        return focusTraversalPolicy.getFirstComponent(container);
    }

    @Override
    public Component getLastComponent(Container container) {
        return focusTraversalPolicy.getLastComponent(container);
    }

    @Override
    public Component getDefaultComponent(Container container) {
        return focusTraversalPolicy.getDefaultComponent(container);
    }

    void scrollToVisible(Component component) {
        var parent = component.getParent();

        if (parent instanceof JComponent) {
            SwingUtilities.invokeLater(() -> {
                ((JComponent)parent).scrollRectToVisible(SwingUtilities.convertRectangle(parent, component.getBounds(), parent));
            });
        }
    }
}

Note that this does rely on existing behavior and could theoretically break in the future.请注意,这确实依赖于现有行为,理论上将来可能会中断。

Following up on my previous answer, a simpler and possibly more reliable approach would be to define a custom keyboard focus handler.根据我之前的回答,一种更简单且可能更可靠的方法是定义自定义键盘焦点处理程序。 Any time a component receives the input focus, the manager dispatches the event and scrolls the component into view:每当组件接收到输入焦点时,管理器就会调度事件并将组件滚动到视图中:

public class ScrollingKeyboardFocusManager extends DefaultKeyboardFocusManager {
    @Override
    public boolean dispatchEvent(AWTEvent event) {
        var dispatched = super.dispatchEvent(event);

        if (dispatched && event.getID() == FocusEvent.FOCUS_GAINED) {
            var component = (Component)event.getSource();
            var parent = component.getParent();

            if (parent instanceof JComponent) {
                ((JComponent)parent).scrollRectToVisible(SwingUtilities.convertRectangle(parent, component.getBounds(), parent));
            }
        }

        return dispatched;
    }
}

The focus manager can be installed as follows:可以按如下方式安装焦点管理器:

KeyboardFocusManager.setCurrentKeyboardFocusManager(new ScrollingKeyboardFocusManager());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM