Why JScrollBar doesn't respond to arrow keystrokes when coexist with editable component?

245 views Asked by At

(Things will be clear in the code after description)

I have a program that contains JScrollBar, JTextArea, JTextFields, JButtons and some other things. (I only added SSCCE codes)

OK, I added key bindings for left and right JButtons of the JScrollBar , I used getInputMap, and getActionMap to achieve that.

If I have the JScrollBar in my GUI program without editable components such as JTextField or JTextArea, then the keyStrokes KeyEvent.VK_LEFT and KeyEvent.VK_RIGHT will work OK (as expected)

But if I have an editable component with the JScrollBar then it will not respond to KeyEvent.VK_LEFT and KeyEvent.VK_RIGHT (not expected) why does that happen!?
The more strange thing is that if I chose different keyStrokes to bind with such as KeyEvent.VK_S for left and KeyEvent.VK_F for right, it will work!! now why?

How to fix, how to make key bindings of left and right arrows for JScrollBar JButtons while editable component coexist?

These are two working codes in SSCCE style. The first contains JScrollBar without editable components, the second contains JScrollBar with JTextArea.

The first will work OK that is it will respond to left and right arrows of the keyboard. (it doesn't contain editable components)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ScrollTest extends JPanel
{

   JPanel panel;
   JScrollBar scrollBar;
   JButton sliderLeftButton;
   JButton sliderRightButton;

   public ScrollTest()
   {
      scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 6, 0, 300);

      sliderLeftButton = (JButton) scrollBar.getAccessibleContext().getAccessibleChild(1);
      sliderLeftButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "leftmove");
      sliderLeftButton.getActionMap().put("leftmove", leftmove);

      sliderRightButton = (JButton) scrollBar.getAccessibleContext().getAccessibleChild(0);
      sliderRightButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "rightmove");
      sliderRightButton.getActionMap().put("rightmove", rightMove);

      panel = new JPanel(new GridLayout(2, 0));
      panel.add(scrollBar);

      this.setLayout(new BorderLayout());
      this.add(panel, BorderLayout.NORTH);
   }
   AbstractAction leftmove = new AbstractAction()
   {
      @Override
      public void actionPerformed(ActionEvent ae)
      {
         int increment = scrollBar.getBlockIncrement();
         int current = scrollBar.getValue();
         current -= increment;
         scrollBar.setValue(current);
         System.out.println("left");
      }
   };
   AbstractAction rightMove = new AbstractAction()
   {
      @Override
      public void actionPerformed(ActionEvent ae)
      {
         int increment = scrollBar.getBlockIncrement();
         int current = scrollBar.getValue();
         current += increment;
         scrollBar.setValue(current);
         System.out.println("right");
      }
   };

   private static void createAndShowGUI()
   {
      JFrame frame;
      frame = new JFrame("Scroll Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(880, 100);
      frame.add(new ScrollTest(), BorderLayout.CENTER);
      frame.setVisible(true);
   }

   public static void main(String[] args)
   {
      SwingUtilities.invokeLater(new Runnable()
      {
         public void run()
         {
            UIManager.put("swing.boldMetal", Boolean.FALSE);
            createAndShowGUI();
         }
      });
   }
}

The second will NOT work that is it will not respond to left and right arrows of the keyboard. (it does contain editable components - one JTextArea)

The more strange thing
Replace KeyEvent.VK_LEFT with KeyEvent.VK_S and replace KeyEvent.VK_RIGHT with KeyEvent.VK_F. Now S will work for left and F will work for right! why didn't it work with left and right arrows.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ScrollTest extends JPanel
{

   JPanel panel;
   JPanel panel2;
   JScrollBar scrollBar;
   JButton sliderLeftButton;
   JButton sliderRightButton;

   public ScrollTest()
   {
      scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 6, 0, 300);

      sliderLeftButton = (JButton) scrollBar.getAccessibleContext().getAccessibleChild(1);
      sliderLeftButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "leftmove");
      sliderLeftButton.getActionMap().put("leftmove", leftmove);

      sliderRightButton = (JButton) scrollBar.getAccessibleContext().getAccessibleChild(0);
      sliderRightButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "rightmove");
      sliderRightButton.getActionMap().put("rightmove", rightMove);

      panel = new JPanel(new GridLayout(2, 0));
      panel.add(scrollBar);

      panel2 = new JPanel(new GridLayout(1, 0));
      panel2.add(new JTextArea(50, 10));

      this.setLayout(new BorderLayout());
      this.add(panel, BorderLayout.NORTH);
      this.add(panel2, BorderLayout.SOUTH);
   }
   AbstractAction leftmove = new AbstractAction()
   {
      @Override
      public void actionPerformed(ActionEvent ae)
      {
         int increment = scrollBar.getBlockIncrement();
         int current = scrollBar.getValue();
         current -= increment;
         scrollBar.setValue(current);
         System.out.println("left");
      }
   };
   AbstractAction rightMove = new AbstractAction()
   {
      @Override
      public void actionPerformed(ActionEvent ae)
      {
         int increment = scrollBar.getBlockIncrement();
         int current = scrollBar.getValue();
         current += increment;
         scrollBar.setValue(current);
         System.out.println("right");
      }
   };

   private static void createAndShowGUI()
   {
      JFrame frame;
      frame = new JFrame("Scroll Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(880, 100);
      frame.add(new ScrollTest(), BorderLayout.CENTER);
      frame.setVisible(true);
   }

   public static void main(String[] args)
   {
      SwingUtilities.invokeLater(new Runnable()
      {
         public void run()
         {
            UIManager.put("swing.boldMetal", Boolean.FALSE);
            createAndShowGUI();
         }
      });
   }
}
1

There are 1 answers

0
serg.nechaev On

This is because JTextArea is stealing your key strokes:

    textPane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "pressed RIGHT");
    textPane.getActionMap().put("pressed RIGHT", rightMove);

Have a look at BasicTextUI.installKeyboardActions()