0

So I have asked a previous question and this is a follow up to it, and I think it deserves its own question. I have this code where a JPanel of a certain size exists in a JScrollPane. The thing is, I want to set my own maximum values to the scroll bars of the JScrollPane which is easy using the bar.setMaximum(value) method. However, there is a weird problem occurring when I scroll the bars without using my mouse itself but rather with the W, A, S, D keys.

The problem is that I set the scroll bars to new maximums, and make a change listener to update the maximums of the scroll bars (because if you looked at my previous question, the scroll bars values were returning to their default max sizes and not the ones I set them to). I thought I solved the problem to the previous question, but now the scroll bars won't scroll all the way, and stop at a certain point. Any ways to fix this?

Note: I don't want to change the JPanel's size that exists in the scroll pane, I just want making the scrolling longer when going from side to side with the W, A, S, D keys. (My unit increment is 1 which is too large for me, so changing the max size of the scroll bars seemed fit as that would decrease an increment’s size overall)

Here is the minimal reproducible (I drew a rectangle in the JPanel map to help see what's going on):


import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import java.awt.event.*;
import java.awt.*;

public class Test implements KeyListener, ChangeListener {
           private static JScrollPane view;   

           public Test() { 
               create();
           }

           public static void main(String[] args) {
               new Test();
           }

           public void create() {
              JFrame frame = new JFrame(); //make frame
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              frame.setSize(1000, 1000);
              frame.setLocationRelativeTo(null);
              frame.setResizable(false);

              SpringLayout layout = new SpringLayout(); 
              JPanel base = new JPanel();
              base.setPreferredSize(new Dimension(1000, 1000));
              base.setLayout(layout);
                
              JPanel map = new JPanel() {
                public void paint(Graphics g) {
                    super.paint(g);
                    g.drawRect(0, 0, 995, 100);
                }
              };
              map.setPreferredSize(new Dimension(1000, 1000));
              
              
              view = new JScrollPane(map);
              
              view.setFocusable(true);
              view.addKeyListener(this);
              view.setPreferredSize(new Dimension(300, 300));
              layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, view, 0, SpringLayout.HORIZONTAL_CENTER, base);
              layout.putConstraint(SpringLayout.VERTICAL_CENTER, view, 0,  SpringLayout.VERTICAL_CENTER, base);
              base.add(view); //add scrollpane to base jpanel

              frame.add(base);
              frame.setVisible(true);
              
              JScrollBar hBar = view.getHorizontalScrollBar();
              JScrollBar vBar = view.getVerticalScrollBar();
              
              hBar.getModel().addChangeListener(this);
              vBar.getModel().addChangeListener(this);
              
              hBar.getModel().setMaximum(10*800); 
              vBar.getModel().setMaximum(10*800);
           }

           public void stateChanged(ChangeEvent event) { //change max whenever model's max tries to default
                 BoundedRangeModel model = (BoundedRangeModel) event.getSource();
                 model.setMaximum(10*800);
             }
           
           public void keyPressed(KeyEvent event) {  //W, A, S, D keys to change values of jscrollbars
               int verticalValue = view.getVerticalScrollBar().getModel().getValue();
                int horizontalValue = view.getHorizontalScrollBar().getModel().getValue();
                
                switch (event.getKeyCode()) {
                case KeyEvent.VK_W:
                    view.getVerticalScrollBar().getModel().setValue(verticalValue - 10);
                    break;
                case KeyEvent.VK_S:
                    view.getVerticalScrollBar().getModel().setValue(verticalValue + 10);
                    break;
                case KeyEvent.VK_A:
                    view.getHorizontalScrollBar().getModel().setValue(horizontalValue - 10);
                    break;
                case KeyEvent.VK_D:
                    view.getHorizontalScrollBar().getModel().setValue(horizontalValue + 10);
                    break;
                }
           }

        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub
            
        }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
LuckyBandit74
  • 417
  • 1
  • 4
  • 10
  • *My unit increment is 1 which is too fast for me,* - if you are implying that the scrolling is too fast when you press+hold a key, then that is controlled by the OS. That is the OS will determine the repeat rate when a key is held down. The standard solution for this is to use a Swing Timer. With the Timer you can control the repeat rate of the timer which effectively control the scroll rate. Check out the `Keyboard Animation` example in [Mothing Using the Keyboard](https://tips4java.wordpress.com/2013/06/09/motion-using-the-keyboard/) for a working example. The code also uses Key Bindings. – camickr Mar 27 '21 at 18:36
  • @camickr Let me edit that part. What I meant to say was the increment was too large. Sorry for that confusion – LuckyBandit74 Mar 27 '21 at 18:59
  • Here is a question on: [Drawing an image using sub-pixel level accuracy using Graphics2D](https://stackoverflow.com/questions/8676909/drawing-an-image-using-sub-pixel-level-accuracy-using-graphics2d) which might give you some ideas. – camickr Mar 27 '21 at 19:26
  • 1
    @camickr Hey so I looked at this and redesigned my translations completely -- the precision is great! I got rid of trying to translate with scrollbars and just translated my map (if you remember I am trying to make a simple tank game) with the link you provided here. I think this change will help me with future problems. Thanks for all the help :) – LuckyBandit74 Mar 27 '21 at 20:40
  • Yes, that is the first time I've seen the code from the link. I restructured the code from that link so it is not dependent on the classes from the IDE and is it really easy to use the AffineTransform to get sub-pixel movement when doing the translation of the image. – camickr Mar 27 '21 at 23:09

0 Answers0