Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JScrollPane:重新验证后的滚动位置_Java_Swing_Jscrollpane - Fatal编程技术网

Java JScrollPane:重新验证后的滚动位置

Java JScrollPane:重新验证后的滚动位置,java,swing,jscrollpane,Java,Swing,Jscrollpane,我的问题与此非常相似: 不同之处在于,我不想滚动回0,而是要滚动到更新子组件之前保存的位置,如下所示: final int oldPos = scrollPanel.getVerticalScrollBar().getValue(); removeAll(); // Removes all components from the JPanel add(mList()); // Adds a bunch of content revalidate(); SwingUtilities.invoke

我的问题与此非常相似:

不同之处在于,我不想滚动回0,而是要滚动到更新子组件之前保存的位置,如下所示:

final int oldPos = scrollPanel.getVerticalScrollBar().getValue();
removeAll(); // Removes all components from the JPanel
add(mList()); // Adds a bunch of content
revalidate();
SwingUtilities.invokeLater(new Runnable()
{
    @Override
    public void run()
    {
        ml.getVerticalScrollBar().setValue(oldPos);
    }
});
此代码在另一个组件的鼠标运动侦听器中触发,因此它被频繁调用

即使最初jscrollpane滚动到顶部,有时oldPos也不是零,这会导致窗格向下滚动,尽管设置了值

即使我强制滚动到顶部并只记录oldPos值,它也不总是0:

final int oldPos = scrollPanel.getVerticalScrollBar().getValue();
removeAll();
add(mList());
revalidate();
SwingUtilities.invokeLater(new Runnable()
{
    @Override
    public void run()
    {
        System.out.println(oldPos); // Sometimes this is > 2000
        ml.getVerticalScrollBar().setValue(0); // scroll to the top
    }
});
我猜如果在调用前一次执行的invokeLater块之前执行
oldPos=…
代码,就会发生这种情况。我怎样才能解决这个问题

更新:

我按照@mKorbel的建议创建了一个sscce:

更新2:我更新了sscce以允许在jTextArea/jLabel之间切换,启用/禁用侦听器的重新绑定,并在jTextArea和从jTextArea继承的自定义类之间切换,覆盖scrollRectToVisible方法

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

public class Main {
  static class MyTextArea extends JTextArea {
    @Override
    public void scrollRectToVisible(final Rectangle aRect) {
      // supress scrollToRect in textarea
    }
  }

  static final Box inner = Box.createVerticalBox();

  // if the jtextarea should contain text
  private static boolean textEnabled = true;
  private static boolean usejLabel = false;
  private static boolean useRebinding = false;
  private static boolean useLock = true;
  private static boolean customTextarea = false;

  private static boolean _locked = false;

  public static void main(final String[] args) {
    final JFrame frame = new JFrame();

    final JPanel insideScroll = insideScroll();
    final JScrollPane scrollpane = new JScrollPane(insideScroll);
    scrollpane.setAutoscrolls(false);
    scrollpane
        .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    final JPanel rightPanel = new JPanel();
    rightPanel.setPreferredSize(new Dimension(300, 300));

    final MouseMotionAdapter listener = new MouseMotionAdapter() {

      @Override
      public void mouseDragged(final MouseEvent e) {
        super.mouseDragged(e);
        final boolean rebind = useRebinding;

        final MouseMotionAdapter self = this;
        if (rebind) {
          rightPanel.removeMouseMotionListener(self);
        }
        final int pos = scrollpane.getVerticalScrollBar().getValue();
        if (!useLock || !_locked) {
          if (useLock) {
            _locked = true;
          }
          update();
          SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
              if (rebind) {
                rightPanel.addMouseMotionListener(self);
              }
              if (useLock) {
                _locked = false;
              }
            }
          });
        }

      }
    };
    rightPanel.addMouseMotionListener(listener);

    // Add labels describing the problem
    rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
    final JButton toggleButton = new JButton("Toggle text");
    final JButton toggleButtonLabel = new JButton("Toggle JLable/JTextArea");
    final JButton toggleButtonRebind = new JButton("Turn rebinding on");
    final JButton toggleButtonCustomTextArea = new JButton(
        "Toggle Custom Textarea");
    rightPanel.add(toggleButton);
    rightPanel.add(toggleButtonLabel);
    rightPanel.add(toggleButtonRebind);
    rightPanel.add(toggleButtonCustomTextArea);
    rightPanel
        .add(new JLabel(
            "<html>If the text is disabled, you can press/drag<br> your mouse on on right side of the<br> window and the scrollbar will<br> stay in its position."));

    rightPanel
        .add(new JLabel(
            "<html><br/>If the text is enabled, the scrollbar<br> will jump around when dragging<br> on the right side."));

    rightPanel
        .add(new JLabel(
            "<html><br/>The problem does not occur when using JLabels instead of JTextArea"));

    // enable/disable the text when the button is clicked.
    toggleButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent e) {
        textEnabled = !textEnabled;
        update();
      }
    });

    toggleButtonLabel.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent e) {
        usejLabel = !usejLabel;
        update();
      }
    });
    toggleButtonRebind.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent e) {
        useRebinding = !useRebinding;
        toggleButtonRebind.setText(useRebinding ? "Turn rebinding off"
            : "Turn rebinding on");
        update();
      }
    });
    toggleButtonCustomTextArea.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent e) {
        customTextarea = !customTextarea;
        update();
      }
    });

    final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        scrollpane, rightPanel);

    frame.add(split);

    // initialize the scrollpane content
    update();

    frame.pack();
    frame.setVisible(true);

    frame.setLocationRelativeTo(null);

  }

  // initializes the components inside the scrollpane
  private static JPanel insideScroll() {
    final JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    panel.add(inner, BorderLayout.NORTH);

    return panel;
  }

  // replaces all components inside the scrollpane
  private static void update() {
    inner.removeAll();

    for (int i = 0; i < 30; i++) {
      inner.add(buildRow(i));
    }

    inner.revalidate();
  }

  // build a single component to be inserted into the scrollpane
  private static JPanel buildRow(final int i) {
    final JPanel row = new JPanel();

    final Color bg = i % 2 == 0 ? Color.DARK_GRAY : Color.LIGHT_GRAY;

    row.setBackground(bg);
    row.setPreferredSize(new Dimension(300, 80));
    row.setLayout(new BorderLayout());

    row.add(textarea(bg), BorderLayout.CENTER);

    return row;
  }

  // build the textarea to be inserted into the cells in the scroll pane
  private static Component textarea(final Color bg) {
    final String text = String.format("%d", (int) (1000 * Math.random()))
        + " Lorem ipsum dolor si amet. Lorem ipsum dolor si amet. Lorem ipsum dolor si amet";
    if (usejLabel) {
      final JLabel textarea = new JLabel();

      textarea.setBackground(bg);
      if (textEnabled) {
        textarea.setText(text);
      }

      return textarea;
    } else {
      final JTextArea textarea;
      if (customTextarea) {
        textarea = new MyTextArea();
        textarea.setDisabledTextColor(Color.cyan);

      } else {
        textarea = new JTextArea();
        textarea.setDisabledTextColor(Color.black);

      }

      textarea.setEnabled(false);
      textarea.setLineWrap(true);
      textarea.setBackground(bg);
      textarea.setEditable(false);
      if (textEnabled) {
        textarea.setText(text);
      }

      return textarea;
    }

  }
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.Dimension;
导入java.awt.Rectangle;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseEvent;
导入java.awt.event.MouseMotionAdapter;
导入javax.swing.Box;
导入javax.swing.BoxLayout;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.JSplitPane;
导入javax.swing.JTextArea;
导入javax.swing.ScrollPaneConstants;
导入javax.swing.SwingUtilities;
公共班机{
静态类MyTextArea扩展了JTextArea{
@凌驾
public void scrollRectToVisible(最终矩形aRect){
//Suppress scrollToRect在文本区域
}
}
静态最终框内部=Box.createVerticalBox();
//如果jtextarea应该包含文本
私有静态布尔textEnabled=true;
私有静态布尔usejLabel=false;
私有静态布尔useRebinding=false;
私有静态布尔useLock=true;
私有静态布尔值customTextarea=false;
私有静态布尔值_locked=false;
公共静态void main(最终字符串[]args){
最终JFrame=新JFrame();
最终JPanel insideScroll=insideScroll();
最终JScrollPane滚动窗格=新JScrollPane(内部滚动);
滚动窗格。设置自动滚动(false);
滚动窗格
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HorizontalScrollBar\uNever);
最终JPanel rightPanel=新JPanel();
右面板。设置首选尺寸(新尺寸(300300));
final MouseMotionAdapter listener=new MouseMotionAdapter(){
@凌驾
公共无效鼠标标记(最终鼠标事件e){
超级鼠标标记(e);
最终布尔值重新绑定=useRebinding;
final MouseMotionAdapter self=this;
如果(重新绑定){
右面板。removeMouseMotionListener(self);
}
final int pos=scrollpane.getVerticalScrollBar().getValue();
如果(!useLock | |!| U锁定){
如果(使用锁定){
_锁定=真;
}
更新();
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
如果(重新绑定){
右面板。addMouseMotionListener(self);
}
如果(使用锁定){
_锁定=错误;
}
}
});
}
}
};
rightPanel.addMouseMotionListener(listener);
//添加描述问题的标签
rightPanel.setLayout(新的BoxLayout(rightPanel,BoxLayout.PAGE_轴));
最终JButton toggleButton=新JButton(“切换文本”);
最终JButton toggleButtonLabel=新JButton(“Toggle JLable/JTextArea”);
最终JButton toggleButtonRebind=新JButton(“打开重新绑定”);
最终JButton toggleButtonCustomTextArea=新JButton(
“切换自定义文本区域”);
右面板。添加(切换按钮);
右面板。添加(toggleButtonLabel);
右面板。添加(toggleButtonRebind);
添加(toggleButtonCustomTextArea);
右面板
.add(新JLabel)(
“如果文本被禁用,您可以按/拖动
窗口右侧的鼠标,滚动条将保持在其位置。”); 右面板 .add(新JLabel)( “
如果文本已启用,则拖动右侧的
时,滚动条将跳转。”); 右面板 .add(新JLabel)( “
使用JLabels而不是JTextArea时不会出现问题”); //单击按钮时启用/禁用文本。 addActionListener(新ActionListener()){ @凌驾 已执行的公共无效行动(最终行动事件e){ textEnabled=!textEnabled; 更新(); } }); toggleButtonLabel.addActionListener(新ActionListener(){ @凌驾 已执行的公共无效行动(最终行动事件e){ usejLabel=!usejLabel; 更新(); } }); toggleButtonRebind.addActionListener(新ActionListener(){ @凌驾 已执行的公共无效行动(最终行动事件e){ useRebinding=!useRebinding; toggleButtonRebind.setText(useRebinding?“关闭重新绑定” :“打开重新绑定”); 更新(); } }); toggleButtonCustomTextArea.addActionListener(新ActionListener(){ @凌驾 已执行的公共无效行动(最终行动事件e){ customTextarea=!customTextarea; 更新(); } }); 最终JSplitPane拆分=新JSplitPane(JSplitPane.HORIZONTAL_拆分, 滚动窗格,右面板); 帧。添加(拆分); //初始化滚动窗格内容 更新(); frame.pack(); frame.setVisible(true); frame.setLocatio
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

public class Main {
  // custom Textarea class
  static class MyTextArea extends JTextArea {
    @Override
    public void scrollRectToVisible(final Rectangle aRect) {
      // supress scrollToRect in textarea
    }
  }

  static final Box inner = Box.createVerticalBox();

  public static void main(final String[] args) {
    final JFrame frame = new JFrame();

    final JPanel insideScroll = insideScroll();
    final JScrollPane scrollpane = new JScrollPane(insideScroll);
    scrollpane.setAutoscrolls(false);
    scrollpane
    .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    final JPanel rightPanel = new JPanel();
    rightPanel.setPreferredSize(new Dimension(300, 300));

    final MouseMotionAdapter listener = new MouseMotionAdapter() {

      @Override
      public void mouseDragged(final MouseEvent e) {
        super.mouseDragged(e);

        update();
      }
    };
    rightPanel.addMouseMotionListener(listener);

    // Add labels describing the problem
    rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));

    final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        scrollpane, rightPanel);

    frame.add(split);

    // initialize the scrollpane content
    update();

    frame.pack();
    frame.setVisible(true);

    frame.setLocationRelativeTo(null);

  }

  // initializes the components inside the scrollpane
  private static JPanel insideScroll() {
    final JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    panel.add(inner, BorderLayout.NORTH);

    return panel;
  }

  // replaces all components inside the scrollpane
  private static void update() {
    inner.removeAll();

    for (int i = 0; i < 30; i++) {
      inner.add(buildRow(i));
    }

    inner.revalidate();
  }

  // build a single component to be inserted into the scrollpane
  private static JPanel buildRow(final int i) {
    final JPanel row = new JPanel();

    final Color bg = i % 2 == 0 ? Color.DARK_GRAY : Color.LIGHT_GRAY;

    row.setBackground(bg);
    row.setPreferredSize(new Dimension(300, 80));
    row.setLayout(new BorderLayout());

    row.add(textarea(bg), BorderLayout.CENTER);

    return row;
  }

  // build the textarea to be inserted into the cells in the scroll pane
  private static Component textarea(final Color bg) {
    final String text = String.format("%d", (int) (1000 * Math.random()))
        + " Lorem ipsum dolor si amet. Lorem ipsum dolor si amet. Lorem ipsum dolor si amet";

    final JTextArea textarea = new MyTextArea();
    textarea.setDisabledTextColor(Color.cyan);

    textarea.setEnabled(false);
    textarea.setLineWrap(true);
    textarea.setBackground(bg);
    textarea.setEditable(false);
    textarea.setText(text);

    return textarea;
  }

}