JScrollPane и JList с автоматической прокруткой - PullRequest
14 голосов
/ 25 января 2010

У меня есть следующий код:

    listModel = new DefaultListModel();
    listModel.addElement(dateFormat.format(new Date()) + ": Msg1");
    messageList = new JList(listModel);
    messageList.setLayoutOrientation(JList.VERTICAL);

    messageScrollList = new JScrollPane(messageList);
    messageScrollList.setPreferredSize(new Dimension(500, 200));

    messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {  
        public void adjustmentValueChanged(AdjustmentEvent e) {  
            e.getAdjustable().setValue(e.getAdjustable().getMaximum());  
        }
    }); 

Это автоматически прокручивается вниз. Но если я попытаюсь прокрутить назад вверх, чтобы перечитать сообщение, оно заставит прокрутить вниз. Как я могу это исправить?

Ответы [ 7 ]

10 голосов
/ 25 января 2010

При добавлении нового сообщения, вызовите scrollRectToVisible() для JList, используя Rectangle, имеющего те же размеры, что и предпочитаемая панель сообщений размер. Учитывая вертикальную ориентацию, может быть удобно сделать предпочтительный размер JScrollPane JViewport целым кратным высоте панели сообщений. См. Также: Как использовать панели прокрутки .

Приложение: Это убедительное обсуждение Прокрутка текстовой области также может быть полезным.

1 голос
/ 31 марта 2014

@ вопросник. Пожалуйста, измените ваш код с

messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {  
        public void adjustmentValueChanged(AdjustmentEvent e) {  
            e.getAdjustable().setValue(e.getAdjustable().getMaximum());  
        }
    });

до

messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {  
        public void adjustmentValueChanged(AdjustmentEvent e) {  
            e.getAdjustable().setValue(e.getAdjustable().getValue());  
        }
    }); 

То есть изменение getMaximum() на getValue() Тогда оно работает как требуется. getMaximum() выводит скроллер на максимум; в то время как getValue() принимает его везде, где происходит событие.

Вы можете полностью отказаться от использования этого фрагмента кода, если поставить одну строку

messageScrollList.setViewportView(messageList);

Это работает как add(component) для jList и получает присущее ему поведение.

1 голос
/ 15 июня 2010

Я нашел это действительно полезным: http://forums.sun.com/thread.jspa?threadID=623669 (сообщение от 'inopia')
Отлично работает

Как он говорит: «Проблема здесь в том, что может стать немного трудно найти событие, которое срабатывает после обновления ListModel, JList и JScrollPane».

1 голос
/ 31 марта 2010
this.list = blah blah... 
this.list.setSelectedValue(whatever);   
final JScrollPane sp = new JScrollPane(this.list); // needs to be after the parent is the sp 
this.list.ensureIndexIsVisible(this.list.getSelectedIndex());
0 голосов
/ 27 сентября 2018

Я использовал JScrollPane с JTextArea. Я избегал принудительной прокрутки вниз, прокручивая только когда значение JScrollBar max изменилось:

        JScrollPane scrollPane = new JScrollPane(jTextArea);

        verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum();
        scrollPane.getVerticalScrollBar().addAdjustmentListener(
                e -> {
                    if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0)
                        return;
                    e.getAdjustable().setValue(e.getAdjustable().getMaximum());
                    verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum();
                });

Полагаю, есть лучшее решение для фильтрации событий без дополнительных переменных, и было бы полезно, если бы кто-нибудь опубликовал его.

0 голосов
/ 06 ноября 2013

Для автоматической прокрутки я использую очень простую концепцию статической переменной и list.makeVisible (int index)

    public class autoScrollExample
    {
     static int index=0;
     private void someFunction()
     /*   
     * 
     */
     list1.add("element1");
     list1.makeVisible(index++);
     /*
     *
     */

     private void someOtherFunction()
     /*   
     * 
     */
     list1.add("element2");
     list1.makeVisible(index++);
     /*
     *
     */


    }
0 голосов
/ 25 января 2010

Я думаю, что вы хотите сделать это прокрутить вниз, когда вы добавляете материал в свой messageList, а не на настройку. Итак, ваш код может выглядеть так:

Adjustable sb = messageScrollList.getVerticalScrollBar()
boolean onBottom = sb.getValue() == sb.getMaximum();
//
// add your message to the JList.
//
if(onBottom)  sb.setValue(sb.getMaximum());

В противном случае вам нужно будет сказать, была ли корректировка вызвана изменением модели или мышью, и просматривая документы API. Я не уверен, есть ли способ сделать это легко. Хотя вы могли видеть, возвращает ли AdjustmentEvent.getAdjustmentType() другие значения в этих случаях, если это так, то вы можете просто использовать оператор if в своем анонимном внутреннем классе.

Еще одна вещь, которую вы могли бы попробовать - это иметь где-то логическую переменную, которая устанавливается при добавлении чего-либо в список. Затем в вашем обработчике вы проверяете, установлена ​​ли переменная. Если это так, вы выполняете настройку (и отменяете переменную), в противном случае вы игнорируете ее. Таким образом, будет добавлена ​​только одна прокрутка вниз для каждого элемента, добавляемого в список.

...