我有一个类OutputTable,它负责显示具有先前计算结果的表(jtable)。结果在另一个类(类平滑)中计算,并在结果作为参数发送到OutputTable类之后。
我需要计算两次数据,对于这两种数据,我需要显示结果的jtable。 计算结果时没有多线程。
因为我需要显示2个不同的表,一旦计算出一个数据,我想显示表我决定为每个表创建一个新线程。所以我在第一次数据处理完成后立即启动第一个线程,当第二轮数据处理完成时,我启动第二个线程。
要处理的数据都是不同的数据结构,一个是ArrayList<Station>
而另一个是TreeMap<Integer, ArrayList<Station>>
问题是表只在第二次数据处理完成时填充(因此进程再次释放),这使我得出结论:线程有问题。当第一个线程启动时,它只显示窗口布局而内部没有其他内容。当第二个线程启动时,两个表都会填充结果。
我正在使用GUI,当用户按下开始按钮时,它会启动数据处理。 GUI是
javax.swing.JFrame实现了ActionListener,ItemListener
所以我的代码是:
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*/ });
}
}
}
}
这是来自我启动线程的GUI代码
/* (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();
修改
如果我不清楚,我假装的是,一旦jtable创建就立即在jtable中显示数据,而不是在所有处理结束时,因为它现在正在发生,因为我没有理解。
答案 0 :(得分:4)
Swing是一个单线程环境,所有与UI的更新和交互都应该在Event Dispatching Thread的上下文中执行。
这也意味着阻止EDT的任何操作都将阻止UI开始更新/重新绘制或处理可能发生的任何新事件。
有关详细信息,请参阅Concurrency in Swing。
您应该使用Thread
,而不是使用Runnable
和SwingWorker
。它提供了一种可以在后台线程中完成处理的方法,但也提供了简单易用的方法,使您可以在EDT中处理结果。
例如......
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);
}
}
}
然后在你的“框架”课程中......
StationListWorker stationListWorker = new StationListWorker(stations, model);
stationListWorker.execute();
就个人而言,我会建立两个工作人员,每个工作人员对应一组数据进行处理。这样可以更容易地修改处理并简化逻辑 - 恕我直言