如何解决JScrollBars 值变化不保持最大值不变
所以我有 JScrollPane view
像这样(这是我最小的可重现示例),
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) {
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(1000,1000));
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,SpringLayout.HORIZONTAL_CENTER,base);
layout.putConstraint(SpringLayout.VERTICAL_CENTER,SpringLayout.VERTICAL_CENTER,base);
base.add(view); //add scrollpane to base jpanel
frame.add(base);
frame.setVisible(true);
frame.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
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;
}
}
@Override
public void keyTyped(KeyEvent e) {
// Todo Auto-generated method stub
}
@Override
public void keyreleased(KeyEvent e) {
// Todo Auto-generated method stub
}
}
我将 JScrollPane 滚动条设置为具有如上所示的新最大值,但我将在此处再次输入。 (这样做是为了我可以在相同的视图大小下滚动得更慢(我的单位增量 1 对我来说仍然滚动得太快))
view.getHorizontalScrollBar().setMaximum(10*800);
view.getVerticalScrollBar().setMaximum(10*800);
所以我启动了程序,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 改变它们的最大尺寸?我的目标是使用 W、A、S 和 D 键滚动整个 jlabel map
,并将最大值设置为 jscrollbars。
解决方法
JScrollBar
使用 DefaultBoundedRangeModel
来跟踪值。
在 BasicScrollPaneUI
内部是调用 syncScrollPaneWithViewport()
的方法 hsb.setValues(...)
。
setValues(...) 方法调用 BoundedRangeModel 的 setRangeProperties(...)
方法。
不幸的是,最大值是根据添加到视口的面板宽度重置的。
所以我的建议是您需要创建自己的自定义 BoundedRangeModel 并确保“max”值没有被重置(到一个较小的值)?不知道会不会影响滚动。
您可以在以下位置查看 DefaultBoundedRangeModel 和 BasicScrollPaneUI 的源代码:
https://github.com/openjdk/jdk/tree/master/src/java.desktop/share/classes/javax
这是我用来验证最大值是否被 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,SpringLayout.HORIZONTAL_CENTER,base);
layout.putConstraint(SpringLayout.VERTICAL_CENTER,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。
这是我对如何解决问题的最佳猜测。不知道行不行。
,我终于让你的例子在某种程度上起作用了。我可以使用 WASD 键移动滚动条。
我从 JScrollPane
类字段中删除了静态。
我通过调用 SwingUtilities
invokeLater
方法启动了 Swing 应用程序。此方法可确保在 Event Dispatch Thread 上创建和执行 Swing 组件。
我将键侦听器添加到 JScrollPane
,而不是 JFrame
。
我将 JScrollPane
设为可聚焦,因此按键实际上会记录。 Key bindings 会轻松很多。
这是完整的可运行代码。
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,base);
layout.putConstraint(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) {
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。