锁定JList中的选择

时间:2014-02-07 17:43:06

标签: java swing jlist listselectionlistener

经过近一整天的尝试和网上搜索/ SO,我正在提出建议,我的问题是:

如何以编程方式冻结JList中的当前选择并恢复正常行为?

首先是一些上下文: 我有一个带有项目列表的JList,每个都可以触发一个可能需要很长时间(60秒)的计算,这是由SwingWorker异步执行的。进度条显示程序实际上正在计算并且不会冻结。当线程正在运行时,我不希望用户能够更改列表中的选定元素。线程完成后,我想恢复到列表的正常行为。

我列出我的尝试

1)在ListSelectionListener中测试我的“condition”(isComputing()方法)并在计算时返回:

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

问题是我意识到在任何选择更改后,侦听器被解雇,所以它没有帮助。

2)计算时在列表中添加一个完全空的MouseListener实现,在计算结束时将其删除。根据我的想法,它会捕获列表中的鼠标事件并将其排除,但列表似乎不受此影响。

3)我最后一次机会是在ListSelectionListener中计算状态处于活动状态时更改回“原始”选择(如果新选择与“原始”选择不同,以避免对change事件进行无限递归),但我真的不喜欢这个解决方案,我希望有更优雅的解决方案。

2 个答案:

答案 0 :(得分:2)

只需在计算时禁用JList。这是一个演示,您可以在其中标记JCheckBox以模拟计算何时开始,并在完成时取消选中。选择得以保留。

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

答案 1 :(得分:1)

您可以在执行JList之前禁用SwingWorker(当然在Event Dispatch Thread中执行此操作)并启用列表覆盖done()方法:

protected void done()
     

doInBackground方法之后在事件调度线程上执行   完了。默认实现什么都不做。子类可以   覆盖此方法以对事件执行完成操作   发送线程。请注意,您可以查询内部的状态   执行此方法以确定此任务的结果或   是否已取消此任务。

假设您有一个触发计算的按钮,那么您的代码将如下所示:

final JProgressBar progressBar = new JProgressBar();
final JList list = new JList();
final JButton button = new JButton("Process...");

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        if(list.getSelectedValue() != null) {
            list.setEnabled(false);
            button.setEnabled(false);
            progressBar.setValue(0);

            SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
                @Override
                protected Void doInBackground() throws Exception {
                    // your code here
                    return null;                       
                }

                @Override
                protected void process(List<Integer> chunks) {
                    progressBar.setValue(chunks.get(chunks.size() - 1));
                }

                @Override
                protected void done() {
                    list.setEnabled(true);
                    button.setEnabled(true);
                }
            };                    
            worker.execute();
        }
    }
});