我有一个反复出现的问题,我有一个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);
}
}
任何指示都会非常受欢迎。
答案 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实现。工作顺利。
答案 1 :(得分:6)
是的,你应该确保它在EDT上运行。 我不知道你没有注意到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."
答案 2 :(得分:4)
从不调用void updateList(...),但在内部我错过sleep(int)
,因为Swing更好,并且需要使用java.swing.Timer http://download.oracle.com/javase/tutorial/uiswing/misc/timer.html
答案 3 :(得分: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中存在毛刺的实际原因是由于添加元素的时间速度,所以为了避免在上面的代码中减少时间我使用不到1秒 t.sleep (100)并且工作正常,线程延迟可能会导致故障