简体   繁体   中英

Swing JList freezes when I delete and add while 0 index was selected

This is an example where you press a button and jList1 is refilled with items from a1 to a1000.:

//variable
private List<String> list = new ArrayList<>();

...

//main method
jList1.setModel(new DefaultListModel());
for(int i = 0; i < 1000; i++) {
    list.add("a"+i);
}

...

//button action - jList1 refill
DefaultListModel dtm = (DefaultListModel)jList1.getModel();
dtm.removeAllElements();
for(String s : list) {
    dtm.addElement(s);
}

If I fill the jList1 , then select (with mouse) 0 index (first element in jList) and then press the button the program freezes while refilling the list. If I select any other element or do not select any item in the list at all then it fills just fine.

PS This example is done without any swing or EWT threads, because the main reason was found using them.

SSCCE:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lt;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;

/**
 *
 * @author Minutis
 */
public class Window {

    public static void main(String[] args) {
        final List<String> list = new ArrayList<>();


        JFrame frame = new JFrame("BorderLayout Frame");
        JPanel panel = new JPanel();
        final JList jList1 = new JList();
        JButton refill = new JButton("Refill");

        jList1.setModel(new DefaultListModel());
        for(int i = 0; i < 1000; i++) {
            list.add("a"+i);
        }

        refill.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultListModel dtm = (DefaultListModel)jList1.getModel();
                dtm.removeAllElements();
                for(String s : list) {
                    dtm.addElement(s);
                }
            }

        });

        frame.add(panel);
        panel.setLayout(new BorderLayout());
        panel.add(jList1, BorderLayout.CENTER);
        panel.add(refill, BorderLayout.SOUTH);
        frame.setSize(300, 300);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

The problem is cause by removing all elements in the model when the first element is selected. The way it is implemented, when an index is selected and is removed, for some reason it generates a selectionChanged event. If another index is selected while another is deleted (even if it meant element shifting), it doesn't generate a selectionChanged event.

The removal is implemented in a way that it periodically removes the first element, while the selection index remains unchanged. So for the case of index 0 being selected, it generates 1000 selectionChanged events, which must be handled by the EDT and listeners. If you select another index, only 1 event is generated. That is significantly less overhead.

Before the repopulating while index 0 is selected, try manually setting the selection to index 1:

if(jList1.getSelectedIndex() == 0){
     jList1.setSelectedIndex(1);
}

I think there is no need to worry if there is only one element in the list - it shouldn't do anything to set index greater that element count. But that may be implementation-specific.

For some reason, clearSelection() will cause selectionChanged events to be generated for repopulating an empty list.

  • logical & better could (just to avoiding mistakes from typos) be to add / remove / modify Items directly in XxxListModel ,

for example

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

public class Testing extends JFrame {

    private static final long serialVersionUID = 1L;
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private int currentSelectedRow = 0;
    private int xX = 0;

    public Testing() {
        setLocation(400, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        for (int x = 0; x < 51; x++) {
            listModel.addElement("" + x);
            xX++;
        }
        JScrollPane sp = new JScrollPane(list);
        final JViewport vp = sp.getViewport();
        add(sp, BorderLayout.CENTER);
        /*JButton btn = new JButton("Get Row:");
        add(btn, BorderLayout.SOUTH);
        btn.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent ae) {
        try {
        int goToRow = Integer.parseInt(JOptionPane.showInputDialog(getContentPane(), "Go To Row:"));
        Rectangle r = list.getCellBounds(goToRow, goToRow);
        if (goToRow > currentSelectedRow) {
        r = list.getCellBounds(goToRow - 1, goToRow - 1);
        int vph = vp.getExtentSize().height;
        r.y += vph;
        }
        list.scrollRectToVisible(r);
        list.setSelectedIndex(goToRow);
        currentSelectedRow = goToRow;
        } catch (Exception e) {

        }
        }
        });*/
        JButton btn1 = new JButton("Reset Model CastingModel");
        add(btn1, BorderLayout.NORTH);
        btn1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                DefaultListModel model = (DefaultListModel) list.getModel();
                model.removeAllElements();
                for (int x = 0; x < 51; x++) {
                    model.addElement("" + (x + xX));
                    xX++;
                }
                //list.setModel(model);
            }
        });

        JButton btn2 = new JButton("Reset Model directly from Model");
        add(btn2, BorderLayout.SOUTH);
        btn2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                listModel.removeAllElements();
                for (int x = 0; x < 51; x++) {
                    listModel.addElement("" + (x + xX));
                    xX++;
                }
            }
        });

        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Testing().setVisible(true);
            }
        });
    }
}

EDIT list.clearSelection() ; hasn't any issue, everything moreover than 1k rows caused with desribed issue by OPs

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

public class Testing extends JFrame {

    private static final long serialVersionUID = 1L;
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private int currentSelectedRow = 0;
    private int xX = 0;

    public Testing() {
        setLocation(400, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        for (int x = 0; x < 999; x++) {
            listModel.addElement("" + x);
            xX++;
        }
        JScrollPane sp = new JScrollPane(list);
        final JViewport vp = sp.getViewport();
        add(sp, BorderLayout.CENTER);

        JButton btn1 = new JButton("Reset Model CastingModel");
        add(btn1, BorderLayout.NORTH);
        btn1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                list.clearSelection();
                DefaultListModel model = (DefaultListModel) list.getModel();
                model.removeAllElements();
                for (int x = 0; x < 999; x++) {
                    model.addElement("" + (x + xX));
                    xX++;
                }
                //list.setModel(model);
            }
        });

        JButton btn2 = new JButton("Reset Model directly from Model");
        add(btn2, BorderLayout.SOUTH);
        btn2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                list.clearSelection();
                listModel.removeAllElements();
                for (int x = 0; x < 999; x++) {
                    listModel.addElement("" + (x + xX));
                    xX++;
                }
            }
        });

        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Testing().setVisible(true);
            }
        });
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM