JScrollPane 使用方向键滚动

发布于 2024-10-04 11:02:22 字数 104 浏览 7 评论 0原文

我在 JScrollPane 中有一个 JTextArea 组件,并且文本区域不可编辑。我想使用向上和向下箭头键启用文本区域的滚动(即按箭头键将使文本区域滚动一行)。有什么想法如何实现这一目标?

I've a JTextArea component inside JScrollPane and the text area is not editable. I would like to enable scrolling of the text area with up and down arrow keys (i.e. pressing the arrow keys will scroll the text area by one line). Any ideas how to achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

美羊羊 2024-10-11 11:02:22

是的,键绑定是可行的方法,但您并不总是需要创建自己的操作。 Swing 组件附带了您经常可以重用的默认操作。

有关这些操作的完整列表,请参阅按键绑定

现在您知道了 Action 名称,您可以将其绑定到 keyStroke:

JScrollBar vertical = scrollPane.getVerticalScrollBar();
InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");

Yes Key Bindings is the way to go, but you don't always need to create your own actions. Swing components come with default Actions that you can often reuse.

See Key Bindings for a complete list of these Actions.

Now that you know the Action name you can just bind it to a keyStroke:

JScrollBar vertical = scrollPane.getVerticalScrollBar();
InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
沧桑㈠ 2024-10-11 11:02:22

如果 JTextArea 不可编辑且不可聚焦,则它将不会响应箭头键。我不确定是否有一种规范的方法来解决这个问题,但使其响应的一种方法是设置其键绑定,以在 JTextArea 位于可聚焦窗口中时响应向上和向下键。示例如下:

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;
import javax.swing.text.JTextComponent;

@SuppressWarnings("serial")
public class TestScrollingArea extends JPanel {
    private static final String UP = "Up";
    private static final String DOWN = "Down";
    private JTextArea area = new JTextArea(20, 40);
    private JScrollPane scrollPane = new JScrollPane(area);

    public TestScrollingArea() {
        // make textarea non-editable and non-focusable
        area.setEditable(false);
        area.setFocusable(false);
        area.setWrapStyleWord(true);
        area.setLineWrap(true);
        add(scrollPane);

        // fill area with letters
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 100; j++) {
                area.append("abcdefg ");
            }
        }

        // have JTextArea tell us how tall a line of text is.
        int scrollableIncrement = area.getScrollableUnitIncrement(scrollPane.getVisibleRect(), 
                    SwingConstants.VERTICAL, 1);

        // add key bindings to the JTextArea 
        int condition = JTextComponent.WHEN_IN_FOCUSED_WINDOW;
        InputMap inMap = area.getInputMap(condition);
        ActionMap actMap = area.getActionMap();

        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
        actMap.put(UP, new UpDownAction(UP, scrollPane.getVerticalScrollBar().getModel(), 
                    scrollableIncrement));
        actMap.put(DOWN, new UpDownAction(DOWN, scrollPane.getVerticalScrollBar().getModel(), 
                    scrollableIncrement));

    }

    // Action for our key binding to perform when bound event occurs
    private class UpDownAction extends AbstractAction {
        private BoundedRangeModel vScrollBarModel;
        private int scrollableIncrement;
        public UpDownAction(String name, BoundedRangeModel model, int scrollableIncrement) {
            super(name);
            this.vScrollBarModel = model;
            this.scrollableIncrement = scrollableIncrement;
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            String name = getValue(AbstractAction.NAME).toString();
            int value = vScrollBarModel.getValue();
            if (name.equals(UP)) {
                value -= scrollableIncrement;
                vScrollBarModel.setValue(value);
            } else if (name.equals(DOWN)) {
                value += scrollableIncrement;
                vScrollBarModel.setValue(value);
            }
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("TestScrollingArea");
        frame.getContentPane().add(new TestScrollingArea());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}

If the JTextArea is non-editable and non-focuseable, it will not respond to the arrow keys. I'm not sure if there is a canonical way to get around this, but one way to make it respond is to set its key binding to respond to the up and down keys when the JTextArea is in the focusable window. An example of this is as follows:

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;
import javax.swing.text.JTextComponent;

@SuppressWarnings("serial")
public class TestScrollingArea extends JPanel {
    private static final String UP = "Up";
    private static final String DOWN = "Down";
    private JTextArea area = new JTextArea(20, 40);
    private JScrollPane scrollPane = new JScrollPane(area);

    public TestScrollingArea() {
        // make textarea non-editable and non-focusable
        area.setEditable(false);
        area.setFocusable(false);
        area.setWrapStyleWord(true);
        area.setLineWrap(true);
        add(scrollPane);

        // fill area with letters
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 100; j++) {
                area.append("abcdefg ");
            }
        }

        // have JTextArea tell us how tall a line of text is.
        int scrollableIncrement = area.getScrollableUnitIncrement(scrollPane.getVisibleRect(), 
                    SwingConstants.VERTICAL, 1);

        // add key bindings to the JTextArea 
        int condition = JTextComponent.WHEN_IN_FOCUSED_WINDOW;
        InputMap inMap = area.getInputMap(condition);
        ActionMap actMap = area.getActionMap();

        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
        actMap.put(UP, new UpDownAction(UP, scrollPane.getVerticalScrollBar().getModel(), 
                    scrollableIncrement));
        actMap.put(DOWN, new UpDownAction(DOWN, scrollPane.getVerticalScrollBar().getModel(), 
                    scrollableIncrement));

    }

    // Action for our key binding to perform when bound event occurs
    private class UpDownAction extends AbstractAction {
        private BoundedRangeModel vScrollBarModel;
        private int scrollableIncrement;
        public UpDownAction(String name, BoundedRangeModel model, int scrollableIncrement) {
            super(name);
            this.vScrollBarModel = model;
            this.scrollableIncrement = scrollableIncrement;
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            String name = getValue(AbstractAction.NAME).toString();
            int value = vScrollBarModel.getValue();
            if (name.equals(UP)) {
                value -= scrollableIncrement;
                vScrollBarModel.setValue(value);
            } else if (name.equals(DOWN)) {
                value += scrollableIncrement;
                vScrollBarModel.setValue(value);
            }
        }
    }

    private static void createAndShowUI() {
        JFrame frame = new JFrame("TestScrollingArea");
        frame.getContentPane().add(new TestScrollingArea());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}
我要还你自由 2024-10-11 11:02:22

刚刚遇到这个问题,虽然答案对于推动我走向正确的方向很有用,但从那时起,解决方案的某些部分可能已经发生了变化。它对我有用,他进行了以下更改:
- 必须更改 JScrollPane 实例的 InputMap
- actionMapKeys 必须是:“unitScrollX”和/或“scrollX”(X= 下、上、左、右)。它们驻留在 BasicScrollPaneUI 中。

Just came across this problem and while the answers was useful in driving me to the right direction some bits of the solution may have changed since then. It worked for me with he following changes:
- it was the InputMap of JScrollPane instance that had to be changed
- actionMapKeys had to be: "unitScrollX" and/or "scrollX" (X= Down, Up, Left, Right). They reside in BasicScrollPaneUI.

娇纵 2024-10-11 11:02:22

您应该将 KeyListener 添加到 JScrollPane 中。

You should add KeyListener to your JScrollPane.

祁梦 2024-10-11 11:02:22

我所要做的就是使滚动窗格请求聚焦于鼠标输入(如回答)。

var scrollPane = new JScrollBar(jPanelCanvas);
scrollPane.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseEntered(MouseEvent e) {
        // this seems to enable key navigation
        if ((e.getComponent() instanceof JScrollPane)) {
            e.getComponent().requestFocus();
        }
    }
});

但是我不确定如何调整这些键的操作。也许可以按照 tinca 的答案 所述直接调整 JScrollPane 上的操作。

scrollPane.getActionMap() 的调用显示了定义的以下操作

  • "unitScrollRight" -> {BasicScrollPaneUI$Actions@4310}
  • “unitScrollDown”-> {BasicScrollPaneUI$Actions@4312}
  • “scrollDown”-> {BasicScrollPaneUI$Actions@4314}
  • “scrollHome”-> {BasicScrollPaneUI$Actions@4316}
  • “scrollRight”-> {BasicScrollPaneUI$Actions@4318}
  • “scrollUp”-> {BasicScrollPaneUI$Actions@4320}
  • “unitScrollLeft”-> {BasicScrollPaneUI$Actions@4322}
  • “unitScrollUp”-> {BasicScrollPaneUI$Actions@4324}
  • “scrollEnd”-> {BasicScrollPaneUI$Actions@4326}
  • “scrollLeft”-> {BasicScrollPaneUI$Actions@4328}

All I had to do was to make the scroll pane request focus on mouse enter (as explained in this answer).

var scrollPane = new JScrollBar(jPanelCanvas);
scrollPane.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseEntered(MouseEvent e) {
        // this seems to enable key navigation
        if ((e.getComponent() instanceof JScrollPane)) {
            e.getComponent().requestFocus();
        }
    }
});

However I'm not sure on how to tweak the actions of these keys. Maybe by tweaking the actions on the JScrollPane directly as mentioned by tinca's answer.

The call to scrollPane.getActionMap() are showing the following actions defined

  • "unitScrollRight" -> {BasicScrollPaneUI$Actions@4310}
  • "unitScrollDown" -> {BasicScrollPaneUI$Actions@4312}
  • "scrollDown" -> {BasicScrollPaneUI$Actions@4314}
  • "scrollHome" -> {BasicScrollPaneUI$Actions@4316}
  • "scrollRight" -> {BasicScrollPaneUI$Actions@4318}
  • "scrollUp" -> {BasicScrollPaneUI$Actions@4320}
  • "unitScrollLeft" -> {BasicScrollPaneUI$Actions@4322}
  • "unitScrollUp" -> {BasicScrollPaneUI$Actions@4324}
  • "scrollEnd" -> {BasicScrollPaneUI$Actions@4326}
  • "scrollLeft" -> {BasicScrollPaneUI$Actions@4328}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文