2011-05-06 46 views
3

我有一个反复出现的问题,我有一个JList,我希望用新内容更新。我使用了一个DefaultListModel,它提供了向列表中添加新内容的方法,但是当使用这些方法时,我发现某些比例的调用会导致完全空白的JList。更新是否工作似乎是随机的,并且与发送的数据无关。为什么我在通过列表模型更新内容后有时会出现空白的JLists?

下面是一个简单的程序,它演示了这个问题。它只是生成一个增加大小的列表来更新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); 
    } 

} 

任何指针都会受到欢迎。

回答

8

看看这个代码:

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<String> entries) { 
     model.removeAllElements(); 
     for (String entry : entries) { 
      model.addElement(entry); 
     } 
    } 
    private class UpdateRunner extends SwingWorker<List<String>, List<String>>{ 

     @Override 
     public List<String> 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.length;i++) { 
        entries[i] = "Entry "+i; 
       } 

       publish(Arrays.asList(entries)); 

       try { 
        Thread.sleep(1000); 
       } 
       catch (InterruptedException e) {} 
      } 
      return null; 
     } 
     @Override 
     protected void process(List<List<String>> entries) { 
      for (List<String> 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实现。工作顺利。

+0

但再次与睡眠(int); – mKorbel 2011-05-06 13:32:41

+0

是的,但那个睡眠不接触EDT或主线程,它暂停了Swing Worker线程。所以没有冻结或空的屏幕。 – dhblah 2011-05-06 13:34:16

+0

+1我相信这是如何正确委托这样的工作流程。 – mre 2011-05-06 13:47:32

4

,从来没有调用无效updateList(...),但里面我错过了sleep(int),对于Swing是更好的使用java.swing.Timer http://download.oracle.com/javase/tutorial/uiswing/misc/timer.html

+1

是的,但在一个非常复杂的方式。但是你是对的,更新列表应该在'EDT'上完成。 – mre 2011-05-06 12:24:49

+0

+1定时器。定时器在swing重绘线程中运行,因此,在每次射击时都会正确更新UI。 – spot35 2011-05-06 12:37:06

+0

我同意@sthupahsmaht无论如何+1作为答案。 – Boro 2011-05-06 12:37:15

6

是啊,你应该确保它运行在美国东部时间要求。 我不知道你没有注意到任何例外BTW? 我第一次拿到一个。

代码,改为使用(删除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<entries.length;i++) { 
        entries[i] = "Entry "+i; 
       }  
       updateList(entries); 
      } 
     }); 
     t.setRepeats(true); 
     t.start(); 

这就是为什么它被保存到使用它,因为它是在the class 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."

+0

+1,http://download.oracle.com/javase/7/docs/api/javax/swing/Timer.html#setDelay%28int%29 – mKorbel 2011-05-06 13:08:17

+0

尽管我的示例只是使用了一个简单的计时器,但在我的真实代码中,我因为它以更复杂的方式收集数据,所以需要单独的线程来执行更新。是否有一个等价的定时器来创建一个单独的线程不会与Swing更新机制冲突? – 2011-05-06 13:19:50

+0

您必须查找由@ gasan发布的SwingWorker,但请注意Executor + SwingWorker for Java <1.6.022 bug http://bugs.sun.com/view_bug.do;jsessionid=c58515ce3f702ffffffffeef2e80af23ef74?bug_id=6880336 – mKorbel 2011-05-06 13:36:59

0

虽然试图在我的程序中实现上面的答案,但它没有工作,所以我想出了简单的方法,以下简单的方法添加到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故障是由于在这elemets是timerate以避免它在我的代码上面减少的时间我上面我使用不到1秒t.sleep(100)它工作正常低线程延迟可能会导致故障

相关问题