Java JScrollBars值更改不保持最大值不变

Java JScrollBars值更改不保持最大值不变,java,max,setvalue,jscrollbar,Java,Max,Setvalue,Jscrollbar,因此,我有JScrollPane视图这样(这是我的最小可复制示例) 我将JScrollPane滚动条设置为具有新的最大值,可以在上面看到,但我将在这里再次键入。(这样做是为了在相同的视图大小下滚动得更慢(我的单位增量1对我来说仍然滚动得太快)) 所以我启动了这个程序,jscrollbars的最大尺寸明显增加了,这就是我想要的。有了这些,我还有下面的代码来使用keylistener更改jscrollbars值,这也可以在上面看到 case KeyEvent.VK_W: view.getVe

因此,我有JScrollPane
视图
这样(这是我的最小可复制示例)

我将JScrollPane滚动条设置为具有新的最大值,可以在上面看到,但我将在这里再次键入。(这样做是为了在相同的视图大小下滚动得更慢(我的单位增量1对我来说仍然滚动得太快))

所以我启动了这个程序,jscrollbars的最大尺寸明显增加了,这就是我想要的。有了这些,我还有下面的代码来使用keylistener更改jscrollbars值,这也可以在上面看到

case KeyEvent.VK_W:
    view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() - 10*0.3));
    break;
case KeyEvent.VK_S:
    view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() + 10*0.3));
    break;
case KeyEvent.VK_A:
    view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() - 10*0.3));
    break;
case KeyEvent.VK_D:
    view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() + 10*0.3));
    break;
问题:

当我按下这些键中的任何一个时,滚动条的最大值不再是我设置的值,而是将它们的最大值默认为首选大小
map
(我通过在按下任何键之前和之后打印滚动条的最大值进行了测试,结果它们发生了变化)。我相信这个问题源于
bar.setValue()
方法,不知道为什么


那么,如何防止jscrollbars更改其最大大小呢?我的目标是滚动整个jlabel
map
,仅使用W、A、S和D键,并将设置的最大值滚动到jscrollbars。

我终于让您的示例在某种程度上起作用了。我可以用WASD键移动滚动条

我从
JScrollPane
类字段中删除了static

我通过调用
SwingUtilities
invokeLater
方法启动了Swing应用程序。此方法确保在上创建和执行Swing组件

我将键侦听器添加到
JScrollPane
,而不是
JFrame

我将
JScrollPane
设置为可聚焦,这样按键就可以注册了。这样会容易得多

下面是完整的可运行代码

import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;

public class JScrollPaneTest implements KeyListener {
    private JScrollPane view;   

    public JScrollPaneTest() { 
        create();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                 new JScrollPaneTest();
            }
        });
    }

    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();  //make panel for the scrollpane
       map.setPreferredSize(new Dimension(1000, 1000));
       
       
       view = new JScrollPane(map);  //initialize scrollpane and add to base with a SpringLayout
       view.setFocusable(true);
       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);
       view.addKeyListener(this);
       
       view.getHorizontalScrollBar().setMaximum(10*800); //set wanted max sizes of each scroll bar
       view.getVerticalScrollBar().setMaximum(10*800);
    }

    public void keyPressed(KeyEvent event) { // W, A, S, D keys to change values of jscrollbars
        int verticalValue = view.getVerticalScrollBar().getValue();
        int horizontalValue = view.getHorizontalScrollBar().getValue();
        
        switch (event.getKeyCode()) {
        case KeyEvent.VK_W:
            view.getVerticalScrollBar().setValue(verticalValue - 10);
            break;
        case KeyEvent.VK_S:
            view.getVerticalScrollBar().setValue(verticalValue + 10);
            break;
        case KeyEvent.VK_A:
            view.getHorizontalScrollBar().setValue(horizontalValue - 10);
            break;
        case KeyEvent.VK_D:
            view.getHorizontalScrollBar().setValue(horizontalValue + 10);
            break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
 
}

JScrollBar
使用
DefaultBoundedRangeModel
跟踪值

BasicScrollPaneUI
中是调用
hsb.setValues(…)
的方法
syncScrollPaneWithViewport()

setValues(…)方法调用BoundedRangeModel的
setRangeProperties(…)
方法

不幸的是,最大值是根据添加到视口的面板宽度重置的

因此,我的建议是,您需要创建自己的自定义BoundedRangeModel,并确保“max”值未重置(为较小的值)?我不知道这是否会影响滚动

您可以在以下位置查看DefaultBoundedRangeModel和BasicScrollPaneUI的源代码:

下面是我用来验证max值是否由setValue(…)语句本身之外的方法更改的测试代码。但是,此语句显然会导致视口同步:

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

public class Test implements KeyListener {
           private static JScrollPane view;

           public Test() {
               create();
           }

           public static void main(String[] args) {
                SwingUtilities.invokeLater( () -> 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();  //make panel for the scrollpane
              map.setPreferredSize(new Dimension(1200, 1200));


              view = new JScrollPane(map);  //initialize scrollpane and add to base with a SpringLayout
              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

                view.getHorizontalScrollBar().setModel( new MyBoundedRangeModel() );
                System.out.println("default value");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


              frame.add(base);
              frame.setVisible(true);
              frame.addKeyListener(this);

                System.out.println("after Visible");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


               view.getHorizontalScrollBar().setMaximum(10*800); //set wanted max sizes of each scroll bar
               view.getVerticalScrollBar().setMaximum(10*800);

                System.out.println("after changing maximum");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


           }

           public void keyPressed(KeyEvent event)
           {
                System.out.println("Before");
                System.out.println(view.getHorizontalScrollBar().getValue());
                System.out.println(view.getHorizontalScrollBar().getMaximum());

               switch(event.getKeyCode()) {
              case KeyEvent.VK_W:
                   view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() - 10*0.9));
                   break;
              case KeyEvent.VK_S:
                   view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() + 10*0.9));
                   break;
              case KeyEvent.VK_A:
                   view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() - 10*0.9));
                   break;
              case KeyEvent.VK_D:
                   view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() + 10*0.9));
                   break;
               }

                System.out.println("after");
                System.out.println(view.getHorizontalScrollBar().getValue());
                System.out.println(view.getHorizontalScrollBar().getMaximum());
           }

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

        }

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

        }

        class MyBoundedRangeModel extends DefaultBoundedRangeModel
        {
            @Override
            public void setValue(int i)
            {
                System.out.println("setValue");
                super.setValue(i);
            }

            @Override
            public void setMaximum(int i)
            {
                System.out.println("setMaximum");
                super.setMaximum(i);
            }
            @Override
            public void setMinimum(int i)
            {
                System.out.println("setMinimum");
                super.setMinimum(i);
            }

            @Override
            public void setExtent(int i)
            {
                System.out.println("setExtent");
                super.setExtent(i);
            }

            @Override
            public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting)
            {
                System.out.println("setRangeProperties");
                System.out.println(newValue + " : " + newExtent + " : " + newMax);
                super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
            }

        }
}
编辑:

上面的代码演示了如何扩展DefaultBoundedRangeModel。目前,它仅显示在更新模型时调用每个方法以尝试理解逻辑流的情况

请注意,在“setMaximum”之后,将使用正确的最大值调用“setRangeProperties”

但是,“setRangeProperties”会被第二次调用(这是在BasicScrollPaneUI中找到的逻辑的结果,正如我试图在回答的顶部解释的那样)。只有这一次,它是以面板宽度(1200)作为最大值调用的,而不是最初指定的8000

因此,您似乎需要重写
setRangeProperties(…)
方法的代码,以便始终使用8000作为最大值。因此,当您创建
MyBoundedRangeModel
的实例时,可能会传入您想要使用的最大值

我提供了一个链接,您可以在其中找到DefaultBoundedRangeModel的源代码。从
setRangeProperties(…)
方法复制代码作为起点开始。然后您需要自定义代码,以确保最大值始终为8000


这是我对你如何解决这个问题的最好猜测。我不知道它是否有效。

我们又一次提出了一个没有答案的问题。如果人们没有读过你最后的3或4个问题,他们就不知道你想做什么。@camickr对不起,让我把它做好now@camickr好的,在顶部我声明代码是我的最小可复制示例。我已经包括了主类的所有内容,下面我还有Map类的代码。我认为这就足够了。发布的代码无法编译。因此,这不是一个问题。我们应该能够复制/粘贴/编译和测试以查看所描述的行为。另外,您不需要Map类。您只需创建一个JPanel并设置首选大小。我通过在按下任何键之前和之后打印出滚动条的最大大小来测试它-这应该是MRE的一部分,这样我们就可以确切地看到您是如何测试的。@camickr好的,我编辑了我的帖子,我编辑了代码并亲自测试了它-它再现了我的问题。很抱歉在这里如此无知,谢谢你对我的耐心。我会在以后的帖子上投入更多的精力。@camickr你完全正确。我睡了一夜,然后立即醒来测试,忘记了我的最大值需要保持不变,并在意识到之前关闭了电脑。我刚刚回到这里,是想对你的评论进行评论,也是想看看你的评论。还有,如果你以前尝试过这个问题,你运气好吗?@ Gilbert Le Blanc,所以我的帖子应该已经和W,A,S和D键一起移动了。问题是,我设置滚动条的最大值在按下这些键后改变了它们的最大值。在您发布的示例中,我设置的最大值被忽略,并采用默认的滚动条大小。虽然这不完全是我想要的,但我感谢你的尝试
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;

public class JScrollPaneTest implements KeyListener {
    private JScrollPane view;   

    public JScrollPaneTest() { 
        create();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                 new JScrollPaneTest();
            }
        });
    }

    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();  //make panel for the scrollpane
       map.setPreferredSize(new Dimension(1000, 1000));
       
       
       view = new JScrollPane(map);  //initialize scrollpane and add to base with a SpringLayout
       view.setFocusable(true);
       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);
       view.addKeyListener(this);
       
       view.getHorizontalScrollBar().setMaximum(10*800); //set wanted max sizes of each scroll bar
       view.getVerticalScrollBar().setMaximum(10*800);
    }

    public void keyPressed(KeyEvent event) { // W, A, S, D keys to change values of jscrollbars
        int verticalValue = view.getVerticalScrollBar().getValue();
        int horizontalValue = view.getHorizontalScrollBar().getValue();
        
        switch (event.getKeyCode()) {
        case KeyEvent.VK_W:
            view.getVerticalScrollBar().setValue(verticalValue - 10);
            break;
        case KeyEvent.VK_S:
            view.getVerticalScrollBar().setValue(verticalValue + 10);
            break;
        case KeyEvent.VK_A:
            view.getHorizontalScrollBar().setValue(horizontalValue - 10);
            break;
        case KeyEvent.VK_D:
            view.getHorizontalScrollBar().setValue(horizontalValue + 10);
            break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
 
}
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class Test implements KeyListener {
           private static JScrollPane view;

           public Test() {
               create();
           }

           public static void main(String[] args) {
                SwingUtilities.invokeLater( () -> 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();  //make panel for the scrollpane
              map.setPreferredSize(new Dimension(1200, 1200));


              view = new JScrollPane(map);  //initialize scrollpane and add to base with a SpringLayout
              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

                view.getHorizontalScrollBar().setModel( new MyBoundedRangeModel() );
                System.out.println("default value");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


              frame.add(base);
              frame.setVisible(true);
              frame.addKeyListener(this);

                System.out.println("after Visible");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


               view.getHorizontalScrollBar().setMaximum(10*800); //set wanted max sizes of each scroll bar
               view.getVerticalScrollBar().setMaximum(10*800);

                System.out.println("after changing maximum");
                System.out.println(view.getHorizontalScrollBar().getMaximum());


           }

           public void keyPressed(KeyEvent event)
           {
                System.out.println("Before");
                System.out.println(view.getHorizontalScrollBar().getValue());
                System.out.println(view.getHorizontalScrollBar().getMaximum());

               switch(event.getKeyCode()) {
              case KeyEvent.VK_W:
                   view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() - 10*0.9));
                   break;
              case KeyEvent.VK_S:
                   view.getVerticalScrollBar().setValue((int) (view.getVerticalScrollBar().getValue() + 10*0.9));
                   break;
              case KeyEvent.VK_A:
                   view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() - 10*0.9));
                   break;
              case KeyEvent.VK_D:
                   view.getHorizontalScrollBar().setValue((int) (view.getHorizontalScrollBar().getValue() + 10*0.9));
                   break;
               }

                System.out.println("after");
                System.out.println(view.getHorizontalScrollBar().getValue());
                System.out.println(view.getHorizontalScrollBar().getMaximum());
           }

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

        }

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

        }

        class MyBoundedRangeModel extends DefaultBoundedRangeModel
        {
            @Override
            public void setValue(int i)
            {
                System.out.println("setValue");
                super.setValue(i);
            }

            @Override
            public void setMaximum(int i)
            {
                System.out.println("setMaximum");
                super.setMaximum(i);
            }
            @Override
            public void setMinimum(int i)
            {
                System.out.println("setMinimum");
                super.setMinimum(i);
            }

            @Override
            public void setExtent(int i)
            {
                System.out.println("setExtent");
                super.setExtent(i);
            }

            @Override
            public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting)
            {
                System.out.println("setRangeProperties");
                System.out.println(newValue + " : " + newExtent + " : " + newMax);
                super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
            }

        }
}