经过近一整天的尝试和网上搜索/ 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事件进行无限递归),但我真的不喜欢这个解决方案,我希望有更优雅的解决方案。
答案 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();
}
}
});