3

(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();
         }
      });
   }
}
kiheru
  • 6,588
  • 25
  • 31
Saleh Feek
  • 2,048
  • 8
  • 34
  • 56
  • 1
    [please is there some diffrencies???](http://stackoverflow.com/questions/11183536/scrollbar-movement-not-smooth-in-jscrollpane-in-swing/11183706#11183706) – mKorbel Sep 04 '13 at 17:17
  • 1
    It seems to me that you have to play with this attribute `JComponent.WHEN_IN_FOCUSED_WINDOW` of `InputMap`. Since the same `KeyBindings` thingy is applied to the editable `JTextField/JTextArea` as well, so either you have to leave this thingy blank for `getInputMap().put()`. In simpler terms, the same key is bind to editable `JTextField/JTextArea` as well, so `WHEN_FOCUSED` will have precedence over `WHEN_IN_FOCUSED_WINDOW`, __IMHO__, as already stated in [KeyBindings](http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html) tutorial :-) – nIcE cOw Sep 04 '13 at 17:22
  • 1
    @Andrew It is better to edit it instead of commenting sarcastically on English misusing, because English is not my first language, and this is the way I tried to express things in English. I always try to do the best. Thank you – Saleh Feek Sep 05 '13 at 13:35
  • 1
    Editable component by default would require key based navigation. As detailed by @nIcEcOw, it is counter intuitive to have keybindings for both scrollbar and editable component together (changing scroll to respond to V or S OR changing editable comp scrolling to V or S). Leave the scrollbar movement to be mouse controlled when in an editable component. – sErVerdevIL Sep 11 '13 at 08:57

1 Answers1

0

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

serg.nechaev
  • 1,323
  • 19
  • 26