Очень медленное заполнение JList

У меня есть компонент JList, который следует очистить и заполнить заново. Следующий код (на основе моего исходного кода) показывает простое окно с JList и JButton:

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

public class JListTest extends javax.swing.JFrame{
    JList jList;
    JButton button;
    DefaultListModel model;

    public JListTest() {
        jList = new JList();
        model = new DefaultListModel();
        jList.setModel( model );
        button = new JButton();

        getContentPane().add(jList, java.awt.BorderLayout.CENTER);

        button.setText("add 10000 items");
        button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                model.clear();
                for( int i=0; i<10000; ++i ) {
                    model.addElement( "aaaa");
                }
            }
        });
        getContentPane().add(button, BorderLayout.PAGE_START);        
        pack();        
    }

    public static void main(String args[]) {
        JListTest jlt =new JListTest();
        jlt.setSize(300, 300);
        jlt.setVisible( true );
    }
}

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

Если выбираю третий пункт и нажимаю кнопку, результат тот же, вставка очень быстрая.

Если я выбираю первый пункт и нажимаю кнопку, программа становится очень медленной (на самом деле мне приходится ее останавливать).

Почему выбор первого элемента замедляет выполнение?

Я тестировал его с помощью JDK 1.5 и 1.6.


person asalamon74    schedule 26.08.2010    source источник


Ответы (3)


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

person Landei    schedule 26.08.2010
comment
Спасибо за совет. Мой собственный класс модели был основан на DefaultListModel, я изменил его, чтобы использовать AsbtractListModel, и создал метод, который добавляет набор значений. Замедление устраняется. До сих пор не до конца понимаю это странное поведение DefaultListModel. - person asalamon74; 27.08.2010

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

В любом случае, лучший способ сделать это — создать новую модель, а затем просто добавить ее в список:

    button.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            DefaultListModel dlm = new DefaultListModel();
            for( int i=0; i<10000; ++i ) {
                dlm.addElement( "aaaa");
            }
            jList.setModel(dlm);
        }
    });

Таким образом, события не запускаются при добавлении каждого нового элемента.

person camickr    schedule 26.08.2010

Вы не должны добавлять много элементов в модель в таком цикле событий. Гораздо лучше было бы, чтобы ваш прослушиватель действий порождал поток для добавления элементов, и чтобы этот поток вызывал SwingUtilities.invokeLater() для запуска события изменения в список.

Обратите внимание, что в соответствии с приведенным ниже комментарием вам нужно создать AbstractListModel (или его подкласс) и сделать его моделью, а также вызвать fireContentsChanged для него в invokeLater.

person Paul Tomblin    schedule 26.08.2010
comment
Вы не можете добавлять элементы в подключенный DefaultListModel вне EDT (и ожидать, что это сработает). - person Tom Hawtin - tackline; 26.08.2010