Search code examples
javaswingjscrollpanejtextareakey-bindings

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


If the text area has the focus, of course the PgUp and PgDn keys work fine, but I was hoping to scroll it up or down using key bindings, leaving the focus where it is instead of moving it to text area and back.

So I've mapped VK_PAGEDOWN with CTRL_DOWN_MASK to a menu items in hopes that when the user presses Ctrl+PgDn the program would scroll the text area by 20 lines.

But while txaOutput.getLineCount() returns number of lines in text area, I can't find a way to set the caret line to that number minus 20. txaOutput.setCaretPosition(int i) sets caret at BYTE number i.

What I've done is bogus, but it does scroll (Page Up is identical except - 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){}
      }
    };

Is there a way to set the caret to a particular line number in a JTextArea in a JScrollPane?

EDIT

The text area contains single words of 3 to 11 letters per line.

EDIT 2

Here's why it's action and not 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);

      }
    }

EDIT 3

Could have used this instead of KeyBoundMenuItem:

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

But had code in place for the analogous class KeyBoundButton. Easy change to make late in day.

EDIT 4

Here's the sort of text needing scrolling up or down:

enter image description here


Solution

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

    Check out the Text Utilities class. Methods like:

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

    should allow you to do what you want. That is to scroll down you can do:

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