Автоматическая прокрутка JScrollPane и JList

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

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

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


person dododedodonl    schedule 25.01.2010    source источник


Ответы (6)


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

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

person trashgod    schedule 25.01.2010

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

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

person mohsenof    schedule 15.06.2010
comment
Ссылка мертва. Можешь освежить? - person Cengiz Can; 15.10.2011

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

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

to

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 и имеет присущее ему поведение.

person Any Body    schedule 31.03.2014

Я использовал 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();
    }
);

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

person user9999    schedule 27.09.2018

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

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 в своем анонимном внутреннем классе.

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

person Chad Okere    schedule 25.01.2010
comment
Тип регулировки одинаков в обоих случаях. Я пробовал это, чтобы прокрутить вниз, если сообщение добавлено. Но если я это сделаю, последнее добавленное сообщение не будет видно. Он прокручивается недостаточно вниз. Как я могу это решить? - person dododedodonl; 25.01.2010
comment
Хм... Ну, одна вещь, которую вы могли бы сделать, это иметь где-нибудь логическую переменную, которая устанавливается, когда вы добавляете что-то в список. Затем в своем обработчике вы проверяете, установлена ​​ли переменная. Если это так, вы выполняете настройку (и сбрасываете переменную), в противном случае вы ее игнорируете. Таким образом, для каждого элемента, добавляемого в список, будет только одна прокрутка вниз. - person Chad Okere; 25.01.2010

Для автоматической прокрутки я использую очень простую концепцию статической переменной и 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++);
     /*
     *
     */


    }
person Jay Dharmendra Solanki    schedule 06.11.2013