JScrollPane добавляет JPanels вверху и сохраняет текущий вид прокрутки

У меня есть JScrollPane, содержащий вертикальный блок. Я вставляю новую панель JPanel в верхнюю часть окна. Если я использую полосу прокрутки для прокрутки вниз, я бы хотел, чтобы текущее представление оставалось там, где я прокручиваю вниз. Например, если у меня есть 50 панелей в поле и я использую полосу прокрутки для просмотра панели 20, я бы хотел, чтобы представление оставалось в поле 20, даже если другие поля добавлены сверху. Кроме того, если я использую полосу прокрутки для обратной прокрутки вверх, я бы хотел, чтобы в представлении отображались новые панели по мере их добавления. есть идеи как это сделать?

Кстати, нет необходимости использовать JScrollPane или Box. Код примера просто помогает объяснить, что я пытаюсь сделать.

Пример кода:

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();
            }
        });
    }
}

РЕДАКТИРОВАТЬ: Вот как я закончил изменение кода. Я чувствую себя глупо из-за того, что не вижу очевидного. В любом случае, спасибо тем, кто помог.

            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);
                }
            }

Кстати, я разместил этот вопрос на странице http://www.coderanch.com/t/528829/GUI/java/JScrollPane-adding-JPanels-at-top#2398276 К вашему сведению.


person coreshift    schedule 27.02.2011    source источник
comment
Я даю вам идею кода, который вы используете для решения своей проблемы, и вы принимаете решение. Удачи в получении помощи в следующий раз, когда у вас возникнет вопрос.   -  person camickr    schedule 28.02.2011
comment
@camickr Вы пытаетесь отдать должное решению JB Nizet? В любом случае, я не читал ваш пост, пока не написал код, основанный на идее JB. Я думаю, ты опоздал на вечеринку на несколько часов. Прочтите. В любом случае, спасибо.   -  person coreshift    schedule 01.03.2011
comment
мое решение было опубликовано за три часа до вашего отредактированного решения. Мне еще предстоит увидеть решение, опубликованное кем-либо еще.   -  person camickr    schedule 02.03.2011


Ответы (2)


Вы можете получить границы компонента, который хотите сделать видимым (используя метод getBounds JComponent), и использовать их в качестве входных данных для метода scrollRectToVisible JViewPort.

person JB Nizet    schedule 27.02.2011
comment
Это возможно, но это приведет к тому, что представление перейдет на панель. Я бы предпочел, чтобы представление оставалось таким, каким его видел пользователь при прокрутке вниз. - person coreshift; 27.02.2011
comment
Затем вы могли бы, возможно, вызвать getViewRect () в области просмотра перед добавлением панели, перевести полученный прямоугольник в нижнюю часть, добавив высоту недавно добавленной панели, а затем прокрутитьRectToVisible, чтобы вернуться туда, где область просмотра была до добавления панели. - person JB Nizet; 27.02.2011
comment
Да, просто, и ответ был очевиден задним числом. Спасибо, очень признателен. - person coreshift; 27.02.2011

Что-то типа:

    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);
        }
    });
person camickr    schedule 27.02.2011