为什么在通过列表模型更新内容后,我有时会得到空白的JLists?

我有一个反复出现的问题,我有一个JList,我希望用新内容更新。 我正在使用DefaultListModel,它提供了向列表中添加新内容的方法,但是当使用这些方法时,我发现有一部分调用会导致一个完全空白的JList。 更新是否有效似乎是随机的,与发送的数据无关。

下面是一个演示问题的简单程序。 它只是生成一个增加大小的列表来更新JList,但是当运行时,列表内容似乎随机出现和消失。

据我所知,我正在遵循正确的API来做到这一点,但我想我必须有一些基本的东西我不知道。

import java.awt.BorderLayout; import javax.swing.*; public class ListUpdateTest extends JPanel { private JList list; private DefaultListModel model; public ListUpdateTest () { model = new DefaultListModel(); list = new JList(model); setLayout(new BorderLayout()); add(new JScrollPane(list),BorderLayout.CENTER); new UpdateRunner(); } public void updateList (String [] entries) { model.removeAllElements(); for (int i=0;i<entries.length;i++) { model.addElement(entries[i]); } } private class UpdateRunner implements Runnable { public UpdateRunner () { Thread t = new Thread(this); t.start(); } public void run() { while (true) { int entryCount = model.size()+1; System.out.println("Should be "+entryCount+" entries"); String [] entries = new String [entryCount]; for (int i=0;i<entries.length;i++) { entries[i] = "Entry "+i; } updateList(entries); try { Thread.sleep(1000); } catch (InterruptedException e) {} } } } public static void main (String [] args) { JDialog dialog = new JDialog(); dialog.setContentPane(new ListUpdateTest()); dialog.setSize(200,400); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setModal(true); dialog.setVisible(true); System.exit(0); } } 

任何指针都会非常受欢迎。

看看这段代码:

 import java.awt.BorderLayout; import javax.swing.*; import javax.swing.SwingWorker; import java.util.Arrays; import java.util.List; public class ListUpdateTest extends JPanel { private JList list; private DefaultListModel model; public ListUpdateTest () { model = new DefaultListModel(); list = new JList(model); setLayout(new BorderLayout()); add(new JScrollPane(list),BorderLayout.CENTER); (new UpdateRunner()).execute(); } public void updateList (List entries) { model.removeAllElements(); for (String entry : entries) { model.addElement(entry); } } private class UpdateRunner extends SwingWorker, List>{ @Override public List doInBackground() { while (true) { int entryCount = model.size()+1; System.out.println("Should be "+entryCount+" entries"); String [] entries = new String [entryCount]; for (int i=0;i> entries) { for (List entry : entries) { updateList(entry); } } @Override protected void done() { updateList(Arrays.asList("done")); } } public static void main (String [] args) { JDialog dialog = new JDialog(); dialog.setContentPane(new ListUpdateTest()); dialog.setSize(200,400); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setModal(true); dialog.setVisible(true); System.exit(0); } } 

由SwingWorker实现。 工作顺利。

是的,你应该确保它在EDT上运行。 我不知道你没有注意到BTW的任何exception吗? 我第一次跑了一个。

要使用的代码(删除UpdateRunner并将其转换为javax.swing.Timer ):

  Timer t = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int entryCount = model.size()+1; System.out.println("Should be "+entryCount+" entries"); String [] entries = new String [entryCount]; for (int i=0;i 

这就是使用它的原因,因为在类doc中很好地解释了它:

"The javax.swing.Timer has two features that can make it a little easier to use with GUIs. First, its event handling metaphor is familiar to GUI programmers and can make dealing with the event-dispatching thread a bit simpler. Second, its automatic thread sharing means that you don't have to take special steps to avoid spawning too many threads. Instead, your timer uses the same thread used to make cursors blink, tool tips appear, and so on."

从来没有调用void updateList(…),但在内部我错过了sleep(int) ,因为Swing更好,需要使用java.swing.Timer http://download.oracle.com/javase/tutorial/uiswing/misc/timer html的

虽然尝试在我的程序中实现上述答案但它没有工作,所以我想出了一个简单的方法,即添加到jList,没有任何故障。

 public static void updateList (String entries, DefaultListModel model) { try { AddElement t = new AddElement(entries, model); t.sleep(100); t.stop(); } catch (InterruptedException ex) { Logger.getLogger(Others.class.getName()).log(Level.SEVERE, null, ex); } } static class AddElement extends Thread { public AddElement(String entries, DefaultListModel model) { model.addElement(entries); } } 

要在模型中添加元素,只需执行此操作或仅在循环中调用updateList

 int entryCount = model.size()+1; updateList("Entry "+entryCount, model); 

jList中存在毛刺的实际原因是由于添加元素的时间速度,所以为了避免在上面的代码中减少时间我使用不到1秒t.sleep(100)并且它工作正常细线下延迟可能会导致故障