JList未在工作线程模型中更新

时间:2017-05-31 20:44:08

标签: java multithreading jlist

使用工作线程,Java运行我的方法,并在其中一个方法中填充JList。问题是,当我运行程序时,JList没有得到更新,但通过Netbeans调试,列表得到了正确更新!!

如何证明这一点?

代码看起来像

public class TheFrame extends javax.swing.JFrame {
    public TheFrame() {
      theFile = new ExcelFile();
      initComponents();
    }

    @SuppressWarnings("unchecked")
    private void initComponents() {
        model = new DefaultListModel();
        effectList = new javax.swing.JList<>();
        effectList.setModel(model);
        pack();
    }                       
    /* worker threads is here */
    private ExcelFile theFile;
    private DefaultListModel<String> model;
    private javax.swing.JList<String> effectList;
}

worker的实现是

    private void Load(JFileChooser fc, int i)
    {
        /* i is an identifier which shows which button has been pressed */
        /* stuffs for creating a please wait window */
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws InterruptedException {
                if ( i == 1 ) {
                  List< String > ls  = theFile.updateEffectList();
                  for (int i = 0; i < ls.size(); i++) {
                      // The following line works fine in the debug mode
                      // but By running the project, it will be empty
                      model.addElement(ls.get(i));
                  }
                  effectList.setVisible(true);
                }
                return null;
            }
            @Override
            protected void done() {
                loading.dispose(); // this is the please wait window
            }
        };
        worker.addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            //System.out.println(evt.getPropertyName());
            Object value = evt.getNewValue();
            if (value instanceof SwingWorker.StateValue) {
                SwingWorker.StateValue state = (SwingWorker.StateValue) value;
                switch (state) {
                    case DONE: {
                        try {
                            worker.get();
                        } catch (InterruptedException | ExecutionException ex) {
                            JOptionPane.showMessageDialog(null, "Failed");
                            ex.printStackTrace();
                        }
                    }
                    break;
                }
            }
        }
        });
        worker.execute();
        loading.setVisible(true); // this is the please wait window
    }

有一些讨论,但我没有得到答案。

1 个答案:

答案 0 :(得分:0)

这里有一个Minimal, Complete, and Verifiable example(可能不是 最小)!

我还强烈建议您研究SwingWorker's documentation并查看Swing's Threading Policy

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;


public class TheFrame  {

    public static void main(String[] args) {
        new TheFrame();
    } 


    private JFrame frame;

    private JList<String> list;
    private DefaultListModel<String> model;

    private JButton load;


    private TheFrame() {
        SwingUtilities.invokeLater(this::initGUI);
    }

    private void initGUI() {
        // runs on EDT
        model = new DefaultListModel<>();

        list = new JList<>(model);

        // for testing
        load = new JButton("Load");
        load.addActionListener(ev -> load());

        frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.add(new JScrollPane(list), BorderLayout.CENTER);
        frame.add(load, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        frame.validate();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void load() {
        // runs on EDT
        frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                // runs on worker Thread
                List<String> ls = updateList();
                for (String string : ls) {
                    simulateDelay(200);
                    publish(string);
                }
                return null;
            }
            @Override
            protected void process(List<String> chunks) {
                // runs on EDT
                for (String string : chunks) {
                    model.addElement(string);
                }
            }
            @Override
            protected void done() {
                // runs on EDT
                try {
                    get();  // check for Exceptions
                } catch (InterruptedException | ExecutionException ex) {
                    ex.printStackTrace();
                } finally {
                    frame.setCursor(Cursor.getDefaultCursor());
                }
            }
        };
        worker.execute();
    }

    // generate some sample data
    private List<String> updateList() {
        simulateDelay(500);
        List<String> data = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
        Collections.shuffle(data);  // just fun.. erh, testing
        return data;
    }

    // for testing only, do not use this in production/real code
    private static void simulateDelay(long delay) {
        try { 
            Thread.sleep(delay); 
        } catch (@SuppressWarnings("unused") InterruptedException ignored) {
        }
    }
}