简体   繁体   English

JScrollPane中的JPanel,如何防止自动滚动

[英]A JPanel in JScrollPane, How to prevent Auto Scroll

I have a Auto Scroll Problem with JScrollPane. 我有一个JScrollPane的自动滚动问题。 For example, in the following code, if we change the value of the Spinner, all TextAreas's value will be Changed. 例如,在以下代码中,如果我们更改Spinner的值,则所有TextAreas的值都将更改。 Then JScrollPane auto scroll to the latest changed JComponent. 然后JScrollPane自动滚动到最新更改的JComponent。

Can I prevent this kind of Auto Scroll? 我可以阻止这种自动滚动吗?

Some one marked that this question is "duplicate" but not at all. 有人指出这个问题是“重复”但根本没有。 This question Java / Swing : JTextArea in a JScrollPane, how to prevent auto-scroll? 这个问题Java / Swing:JScrollPane中的JTextArea,如何防止自动滚动? is a JTextArea in a JScrollPane, so we can use DefaultCaret to solve this problem, because JTextArea has DefaultCaret. 是JScrollPane中的JTextArea,因此我们可以使用DefaultCaret来解决此问题,因为JTextArea具有DefaultCaret。 But in my question, it is a JPanel in a JScrollPane, a JPanel has not a DefaultCaret. 但在我的问题中,它是JScrollPane中的JPanel,JPanel没有DefaultCaret。 So we cannot use the same way to solve this problem. 所以我们不能用同样的方法来解决这个问题。

import java.awt.BorderLayout

import javafx.scene.layout.Pane;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ScrollControl {
    static JFrame main_frame = new JFrame();
    static JScrollPane scroll_pane = new JScrollPane();
    static JPanel pane = new JPanel();
    static JSpinner spinner = new JSpinner();
    static JTextArea text1 = new JTextArea();
    static JTextArea text2 = new JTextArea();
    static JTextArea text3 = new JTextArea();
    static JTextArea text4 = new JTextArea();
    static JTextArea text5 = new JTextArea();
    static JTextArea text6 = new JTextArea();
    static JTextArea text7 = new JTextArea();

    public static void main(String args[]){
        main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
        spinner.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent arg0) {
                text1.setText(spinner.getValue().toString());
                text2.setText(spinner.getValue().toString());
                text3.setText(spinner.getValue().toString());
                text4.setText(spinner.getValue().toString());
                text5.setText(spinner.getValue().toString());
                text6.setText(spinner.getValue().toString());
                text7.setText(spinner.getValue().toString());
            }
        });
        pane.add(spinner);
        pane.add(text1);
        pane.add(text2);
        pane.add(text3);
        pane.add(text4);
        pane.add(text5);
        pane.add(text6);
        pane.add(text7);
        scroll_pane = new JScrollPane(pane);
        main_frame.setSize(300, 100);
        main_frame.getContentPane().add(scroll_pane, BorderLayout.CENTER);

        main_frame.setVisible(true);
    }
}

I don't know how to prevent the scrolling, but you can reset the scrollbar back to its original position: 我不知道如何阻止滚动,但您可以将滚动条重置回原始位置:

spinner.addChangeListener(new ChangeListener()
{
    @Override
    public void stateChanged(ChangeEvent arg0)
    {
        final JScrollBar vertical = scroll_pane.getVerticalScrollBar();
        final int value = vertical.getValue();

        text1.setText(spinner.getValue().toString());
        text2.setText(spinner.getValue().toString());
        text3.setText(spinner.getValue().toString());
        text4.setText(spinner.getValue().toString());
        text5.setText(spinner.getValue().toString());
        text6.setText(spinner.getValue().toString());
        text7.setText(spinner.getValue().toString());

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                vertical.setValue( value );
            }
        });
    }
});

The invokeLater() will add the code to the end of the Event Dispatch Thread so it will execute after all the automatic scrolling has occurred so it looks like the scrollbar never moved. invokeLater()会将代码添加到Event Dispatch Thread的末尾,这样它将在所有自动滚动发生后执行,因此看起来滚动条从未移动过。

The accepted answer did not work reliably for my case. 接受的答案对我的案子不起作用。

I am currently using a JPanel subclass that can prevent the autoscroll requests as a workaround: 我目前正在使用一个JPanel子类,它可以阻止自动滚动请求作为一种解决方法:

class AutoScrollSafeJPanel extends JPanel {
  boolean preventAutroscroll;   

  @Override
  public void scrollRectToVisible(Rectangle rect) {
    if (!preventAutoscroll) {
      super.scrollRectToVisible(rect);
    }
  }
}

Where I resize the component, I do the following: 在我调整组件大小的地方,我执行以下操作:

container.preventAutoscroll = true;
container.setSize(Math.round(width), Math.round(height));
container.setPreferredSize(container.getSize());
container.revalidate();

SwingUtilities.invokeLater(() -> {
  container.preventAutoscroll = false;
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM