Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

updating DefaultListModel on another thread

I have a program that need to update the content of JList, which is DefaultListModel on another thread. Since the number of contents may change from time to time, so I just clear all content and add new content into DefaultListModel when updating. But seems I ran into an issue that JFrame starts refreshing while my thread is doing update. I got exceptions like this

Exception in thread "AWT-EventQueue-0" 
java.lang.ArrayIndexOutOfBoundsException: 3

Here is an example of the code

    DefaultListModel model;
    JList jList;
    JScrollPane jScrollPane;

    Thread thread;
    public Frame() {
        this.setTitle("ASM_SIMULATOR");
        this.setBounds(100, 100, 500, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.getContentPane().setLayout(null);

        model = new DefaultListModel();
        jList = new JList(model);
        jScrollPane = new JScrollPane(jList);

        jList.setBounds(50, 50, 300, 200);
        jScrollPane.setBounds(50, 50, 300, 200);

        this.getContentPane().add(jScrollPane);

        this.setVisible(true);

        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {

                    makeData();
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        });

        thread.start();
    }

    public void makeData() {
        System.out.println("makeData()");
        model.clear();

        for (int i = 0; i < 20; i++) {
            model.addElement((int) (Math.random() * 100));
        }

    }

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

    }
like image 250
user1387622 Avatar asked Feb 18 '23 16:02

user1387622


1 Answers

You violate the basic "all Swing component should be accessed/modified on the Event Dispatch Thread (=EDT), and on the EDT only" twice in that code snippet.

  1. Your main method should wrap the new Frame() call in an SwingUtilities#invokeLater or some similar method
  2. Your model-update thread changes the model on a background thread. Updating the model will fire events which are received by the JList, on which the JList updates itself (again, on the wrong thread).

Two possible solutions:

  • create a new DefaultListModel on your background thread, and replace it in one go on the EDT.
  • keep updating the existing model, but make sure the updates happen on the EDT.
like image 160
Robin Avatar answered Feb 21 '23 05:02

Robin