Search code examples
javaswingjlistlistselectionlistener

Locking selection in JList


After almost a whole afternoon of attempts and search on the web/SO, I'm asking advices, and my question is:

How to programmatically freeze the current selection in a JList and revert back to normal behaviour?

First of all a bit of context: I've got a JList with a list of item, on each can be fired a computation that could take long time (60 secs), that is performed asynchronously by a SwingWorker. A progress bar shows that the program is actually computing and it is not freezed. While the thread is working, I don't want the user to be able to change the selected element in my list. When the thread finishes I would like to revert back to the normal behaviour of the list.

I list out my attempts:

1) testing my "condition" (isComputing() method) in the ListSelectionListener and simply returning if it is computing:

@Override
public void valueChanged(ListSelectionEvent e) {
    if(e.getSource().equals(listSCCs)){
        if(isComputing())
            return;
[...]
}

The problem is that I realized the listener is fired after any selection change, so it is not helping.

2) Add a completely empty MouseListener implementation on the list when computing, removing it at the end of the computation. In my idea it would have catched the mouse events of the list and voided them, but the list seems unaffected by this.

3) My last chance is to change back to the "original" selection when computing status is active in the ListSelectionListener (if the new selection is different from the "original" one, to avoid infinite recursion on the change event), but I really don't like this solution and I hope there are more elegant ones.


Solution

  • Just disable the JList while computing. Here's a demo where you can mark a JCheckBox to simulate when your computation starts, and uncheck when done. The selection is maintained.

    package swing;
    
    import java.awt.*;
    import java.awt.event.*;
    
    import javax.swing.*;
    
    public class JListDisabledListDemo implements Runnable
    {
      private static final String ITEMS[] =
        { "Black", "Blue", "Green", "Orange", "Purple", "Red", "White"};
    
      private JList jList;
      private JCheckBox chkEnable;
    
      public static void main(String args[])
      {
        SwingUtilities.invokeLater(new JListDisabledListDemo()); 
      }
    
      public void run()
      {
        jList = new JList(ITEMS);
        jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        JScrollPane scroll = new JScrollPane(jList);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    
        chkEnable = new JCheckBox("Enable", true);
        chkEnable.addItemListener(new ItemListener()
        {
          public void itemStateChanged(ItemEvent e)
          {
            jList.setEnabled(chkEnable.isSelected());
          }
        });
    
        JFrame f = new JFrame("Colors");
        Container contentPane = f.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(scroll, BorderLayout.CENTER);
        contentPane.add(chkEnable, BorderLayout.NORTH);
    
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(180, 220);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }