views:

36

answers:

3

I have a JList component which should be emptied and repopulated. The following code (based on my original code) shows a simple window with a JList and a 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 );
    }
}

If I press the button the insertion (10000 items) is very fast. If I press it again and again it is still very fast.

If I select the third item and press the button, the result is the same, the insertion is very fast.

If I select the first item and press the button, the program becomes very slow (actually I have to stop it).

Why the selection of the first item slows down the execution?

I've tested it using JDK 1.5 and 1.6.

+1  A: 

You should not be adding lots of elements into the model in a the event loop like that. Far better would be to have your action listener spawn off a thread to add the items, and have that thread invoke a SwingUtilities.invokeLater() to fire the change event to the list.

Note that as per the comment below, you need to make an AbstractListModel (or a subclass of it) and make it the model, and call fireContentsChanged on it in the invokeLater.

Paul Tomblin
You can't add items to a connected `DefaultListModel` off EDT (and expect it to work).
Tom Hawtin - tackline
+2  A: 

I'd suggest to write your own model which allows to add a bunch of values at once. I guess it's not the addition to the model but the GUI things triggered by this that kill the performance.

Landei
Thx for the tip. My own model class was based on DefaultListModel, I modified it to use AsbtractListModel and created a method which adds a bunch of values. The slowdown is eliminated. Still do not fully understand this strange behaviour of DefaultListModel.
asalamon74
+1  A: 

I'm not sure why selecting an item causes the performance problem. But everytime you add an item an event is fired which tells the list to repaint itslef. So maybe the fact that an item is selected causes extra repainting.

Anyway a better way to do this would be to create a new model and then just add it to the list:

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

This way events are not fired as every new item is added.

camickr