2
votes

I have a JScrollPane that contains a vertical Box. I'm inserting new JPanel's at the top of Box. If I use the scrollbar to scroll down I'd like for the current view to remain where I scrolled down to. For example, if I have 50 panels in the box and use the scrollbar to view panel 20, I'd like the view to remain on box 20 even though other boxes are added on top. Additionally, if I use the scrollbar to scroll back up to the top I'd like the view to display new panels as they are added. Any idea how to do this?

BTW, it isn't necessary to use a JScrollPane or a Box. The example code is just to help explain what I am trying to do.

Example code:

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

public class TestScrollPane extends JFrame {

    JScrollPane scrollPane;
    Box box;
    private static int panelCount = 0;

    public TestScrollPane() {
        setPreferredSize(new Dimension(200, 400));
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        scrollPane = new JScrollPane();
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.getVerticalScrollBar().setUnitIncrement(15);
        box = Box.createVerticalBox();
        scrollPane.getViewport().add(box);

        this.add(scrollPane);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);

        Timer t = new Timer(500, new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                box.add(new TestPanel(), 0);
                scrollPane.validate();
            }
        });
        t.setRepeats(true);
        t.start();
    }

    public class TestPanel extends JPanel {

        int myId = panelCount++;

        public TestPanel() {
            this.setLayout(new GridBagLayout());
            this.setBorder(BorderFactory.createBevelBorder(1));
            JLabel label = new JLabel("" + myId);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setVerticalAlignment(JLabel.CENTER);

            this.setMaximumSize(new Dimension(100, 100));
            this.setPreferredSize(new Dimension(100, 100));

            this.add(label);
        }
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                TestScrollPane testScrollPane = new TestScrollPane();
            }
        });
    }
}

EDIT: This is how I ended up changing the code. I feel somewhat foolish for not seeing the obvious. Anyways, thanx to those that helped.

            public void actionPerformed(ActionEvent ae) {
                Point view = scrollPane.getViewport().getViewPosition();
                TestPanel panel = new TestPanel();
                box.add(panel, 0);
                scrollPane.validate();
                if (view.y != 0) {
                    view.y += panel.getHeight();
                    scrollPane.getViewport().setViewPosition(view);
                }
            }

BTW, I had cross posted this question to http://www.coderanch.com/t/528829/GUI/java/JScrollPane-adding-JPanels-at-top#2398276 Just FYI for those that might care.

2
I give you the idea for the code that you use to solve your problem and you take credit for the solution. Good luck getting help the next time you have a question.camickr
@camickr Are you trying to take credit for JB Nizet's solution? Anyways, I hadn't read your post until I had already written code based on JB's idea. I think you where several hours late to the party. Read down. Thanx anyways though.coreshift
my solution was posted three hours before your edited solution. I have yet to see a solution posted by anyone else.camickr

2 Answers

0
votes

You could get the bounds of the component you want to make visible (using JComponent's getBounds method), and use that as an input to JViewPort's scrollRectToVisible method.

0
votes

Something like:

    Timer t = new Timer(1000, new ActionListener() {

        public void actionPerformed(ActionEvent ae) {
            TestPanel panel = new TestPanel();
            box.add(panel, 0);
            JViewport vp = scrollPane.getViewport();
            Point p = vp.getViewPosition();
            p.y += panel.getPreferredSize().height;
            scrollPane.revalidate();
            vp.setViewPosition(p);
        }
    });