3

I have a Auto Scroll Problem with JScrollPane. For example, in the following code, if we change the value of the Spinner, all TextAreas's value will be Changed. Then JScrollPane auto scroll to the latest changed 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? is a JTextArea in a JScrollPane, so we can use DefaultCaret to solve this problem, because JTextArea has DefaultCaret. But in my question, it is a JPanel in a JScrollPane, a JPanel has not a 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);
    }
}
Community
  • 1
  • 1
RobyCat
  • 31
  • 4
  • @DavidPostill Not at all, That is a JTextArea in a JScrollPane. JTextArea has a "getCaret()". But JPanel has not the same thing. – RobyCat Aug 03 '14 at 14:53

2 Answers2

1

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Hello Thank you for your answer but it is not enough for me. Because for my program, one time, there are more than 100 objects are changed, so the frame is blinking. I would like to prevent this blinking. But thank you all the same for your answer. – RobyCat Aug 03 '14 at 18:35
  • @RobyCat Why would you have more than 100 object that you update at the same time? Why would you use a JTextArea? What about using a JLabel or maybe even a JTextField. – camickr Aug 03 '14 at 20:32
  • Thanks a lot! I used JTextField and this problem is solved. But Can you explain to you why JTextField works but JTextArea does not work? Thank you very much! – RobyCat Aug 03 '14 at 21:25
  • @RobyCat, A JTextField never has more than one line of text, so I would guess you don't need logic to scroll the text to make it visible. – camickr Aug 03 '14 at 23:46
0

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:

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;
});
Stefan Haustein
  • 18,427
  • 3
  • 36
  • 51