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

Sim*_*ews 3 java swing model jlist

我有一个反复出现的问题,我有一个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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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

dhb*_*lah 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);
    }

}
Run Code Online (Sandbox Code Playgroud)

由SwingWorker实现.工作顺利.


Bor*_*oro 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();
Run Code Online (Sandbox Code Playgroud)

这就是使用它的原因,因为在类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."