我可以使用按键组合在 JScrollPane 内的 JTextArea 中向上或向下滚动吗?

Can I use a keypress combination to scroll up or down in a JTextArea inside a JScrollPane?

如果文本区域有焦点,当然 PgUpPgDn 键可以正常工作,但我希望滚动它使用键绑定向上或向下,将焦点留在原处,而不是将其移动到文本区域并返回。

所以我将 VK_PAGEDOWN 和 CTRL_DOWN_MASK 映射到菜单项,希望当用户按下 Ctrl+PgDn 时 程序会将文本区域滚动 20 行。

但是当 txaOutput.getLineCount() returns 文本区域中的行数时,我找不到将插入符号 line 设置为该数字减去的方法20. txaOutput.setCaretPosition(int i) 将插入符号设置为字节数 i

我所做的是伪造的,但它确实滚动(Page Up 除了 - scrollBytes 之外是相同的):

    PageDown = new KeyBoundMenuItem("PAGEDOWN", VK_PAGE_DOWN, CTRL_DOWN_MASK) 
    {
      @Override
      public void action(ActionEvent e) {
          scrollBytes = 20 * totalBytesInTextArea / txaOutput.getLineCount();
          try{
              txaOutput.setCaretPosition(txaOutput.getCaretPosition() + scrollBytes);
          }catch(Exception ex){}
      }
    };

有没有办法将插入符设置为 JScrollPane 中的 JTextArea 中的特定行号?

编辑

文本区域包含每行 3 到 11 个字母的单词。

编辑 2

这是 action 而不是 actionPerformed 的原因:

import java.awt.event.ActionEvent;
import javax.swing.*;
import static javax.swing.KeyStroke.getKeyStroke;

public abstract class KeyBoundMenuItem extends JMenuItem{

  public abstract void action(ActionEvent e);


      public KeyBoundMenuItem(String actionMapKey, int key, int mask)
      {
        Action myAction = new AbstractAction()
        {
          @Override public void actionPerformed(ActionEvent e)
          {
            action(e);
          }
        };  

        setAction(myAction);

        getInputMap(WHEN_IN_FOCUSED_WINDOW)
                      .put(getKeyStroke(key, mask),actionMapKey);
        getActionMap().put(                        actionMapKey, myAction);

      }
    }

编辑 3

可以用这个代替 KeyBoundMenuItem:

  public static void shortcut(JMenuItem item, int mnem, int mods, int key)
  {  
    item.setMnemonic(mnem);
    item.setAccelerator(getKeyStroke(key,mods));
  }

但是已经为类似的 class KeyBoundButton 编写了代码。当天晚些时候轻松更改。

编辑 4

以下是需要向上或向下滚动的文本类型:

Is there a way to set the caret to a particular line number

查看 Text Utilities class。方法如:

  1. getLineAtCaret()
  2. gotoStartOfLine(...)

应该允许你做你想做的事。那就是向下滚动你可以这样做:

int currentLine = RXTextUtilities.getLineAtCaret(textArea);
RXTextUtilities.gotoStartOfLine(textArea, currentLine + 10);

感谢@camickr,这是有效的(PAGEUP 的代码是相同的,除了 - 而不是 +

PageDown = new KeyBoundMenuItem("PAGEDOWN", VK_PAGE_DOWN, CTRL_DOWN_MASK) 
{
  @Override
  public void action(ActionEvent e) 
  {
      int currentLine = RXTextUtilities.getLineAtCaret(txaOutput);
      RXTextUtilities.gotoStartOfLine(
        txaOutput, 
        currentLine + RXTextUtilities.maxLinesVisibleInWindow(txaOutput));
  }
};

我可能应该修改此代码以反映他的有效批评,即我不必制作 abstract class 来完成键绑定,但它并没有坏。 (我可能有一天会抽出时间...)

我什至想出了(通过研究他的 Text Utilities)如何在不使用常量的情况下滚动 window(28,参见评论):

  public static int maxLinesVisibleInWindow(JTextComponent component)
  {
      Container container = getAncestorOfClass(JViewport.class, component);

    if (container == null) return 0;

    JViewport   viewport        = (JViewport)container;
    int         extentHeight    = viewport.getExtentSize().height;
    FontMetrics fm              = component.getFontMetrics(component.getFont());
    int         characterHeight = fm.getHeight();

    return (int)extentHeight/characterHeight - 1;
  }