简体   繁体   中英

Creating a new thread with parameters - Thread is created but it doesn't show the data

I've a class, OutputTable, that is responsible to show a table (jtable) with previously computed results. The results are computed in another class (Class Smooth) and after the results are sent as a parameter to the OutputTable class.

I need to compute data two times and for both of them I need to show a jtable with the results. There is no multi-threading while computing the results.

As I need to show 2 different tables and as soon as one data is computed I want to show the table I decided to create a new thread for each table. So I start the first thread as soon as the first data processing is done and when the second round for data processing is done I start the second thread.

Both data to be processed are in different data structures, one is a ArrayList<Station> while the other is an TreeMap<Integer, ArrayList<Station>>

The problem is that the tables are only populated when the second data processing is done (so is the process free again) which leads me to conclude that there is something wrong with the threads. When the first thread starts it just shows the window layout and nothing else inside. When the second thread starts both tables get populated with results.

I'm using a GUI and when the user presses the start buttom it starts the data processing. The GUI is with

javax.swing.JFrame implements ActionListener, ItemListener

So my code is:

public class OutputTable extends JFrame implements Runnable{

TreeMap<Integer, ArrayList<Station>> map;
ArrayList<Station> arrayStation;

    public OutputTable(TreeMap<Integer, ArrayList<Station>> map, ArrayList<Station> arrayStation) { 
        this.map = map;
        this.arrayStation = arrayStation;
    }

    public void run()
    {
        DefaultTableModel model = new DefaultTableModel() { 
            String[] columnsName = { /* my column names go here*/ }; 

            @Override 
            public int getColumnCount() { 
                return columnsName.length; 
            } 

            @Override 
            public String getColumnName(int index) { 
                return columnsName[index]; 
            } 
        }; 

        JTable table = new JTable(model); 
        add(new JScrollPane(table)); 
        setSize(1300, 700);
        setDefaultCloseOperation(HIDE_ON_CLOSE);
        setVisible(true); 

        if(map != null)
        {
            for (ArrayList<Station> arrayAux : map.values()) 
            {
                for(int a = 0; a<arrayAux.size(); a++)
                {
                    model.addRow(new Object[] { /* here I populate the table with my get methods*/ });
                }
            }
        }

        if(arrayStation != null)
        {
            for(int a = 0; a<arrayStation.size(); a++)
            {
                    model.addRow(new Object[] { /* here I populate the table with my get methods*/ });
            }
        }
    }

}

And this is from the GUI code where I start the threads

/* (where I start processing the data for the first time) */
Runnable r = new OutputTable(null, processme);

new Thread(r).start();

/* (I start processing data for a second time) */
Runnable r2 = new OutputTable(xpto, null);
new Thread(r2).start();

EDIT:

If I wasn't clear, what I pretend is to immediately show the data in the jtable as soon as the jtable is created and not at the end of all processing as it is happening now for some reason that I don't understand.

Swing is a single threaded environment, all updates and interactions to the UI are expected to be executed from within the context of the Event Dispatching Thread.

This also means that any action which blocks the EDT will stop the UI from begin updated/repainted or process any new events that might have occurred.

See Concurrency in Swing for more details.

Instead of using a Thread and Runnable , you should probably use a SwingWorker . It provides a means by which processing can be done in a background thread, but also provides simple to use methods to allow you to process the results within the EDT.

For example...

public class StationListWorker extends SwingWorker<Void, Object[]> {
    // The data to be processed...
    private List<Station> stations;
    // The model the results are to be published to...
    private DefaultTableModel model;
    public StationListWorker(List<Station> stations, DefaultTabelModel model) {
        this.stations = stations;
        this.model = model;
    }

    protected Void doInBackground() throws Exception {
        // Process the data in the background thread...
        for (Station station : stations) {
            // Process the data...
            publish(new Object[]{...});
        }
        return null;
    }

    protected void publish(List<Object[]> rows) {
        // Published in the EDT
        for (Object[] row : rows) {
            model.addRow(row);
        }
    }
}        

Then in your "frame" class...

StationListWorker stationListWorker = new StationListWorker(stations, model);
stationListWorker.execute();

Personally, I would establish two workers, one for each set of data to be processed. This will make it easier to modify the processing and simplifier the logic - IMHO

I would also have a look at The Use of Multiple JFrames, Good/Bad Practice?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM