我有一个小的gui程序,在启动时从Excel文件中读取数据,其中一些数据需要转到相关的组合框。我知道如何通过为每个组合框使用单独的SwingWorker来实现这一点:
public class ExcelReader extends SwingWorker<DefaultComboBoxModel, String> {
private final DefaultComboBoxModel model;
// Constructor called from a panel that has a combobox
public ExcelReader(DefaultComboBoxModel model) {
this.model = model;
}
@Override
protected DefaultComboBoxModel doInBackground() throws Exception {
///// code to read data from Excel file
///// publish(someString) used here
return model;
}
@Override
protected void process(List<String> chunks) {
for(String row : chunks)
model.addElement(row);
}
}
这很好用,但是如何使用一个SwingWorker类来填充多个组合框呢?这样可以只读取一次文件。只要找到需要进入组合框的东西,就会更新相关的组合框,然后程序继续读取下一行,直到文件结束。
所以我试图在一个JPanel中更新2个组合框的情况下使用布尔标志,但这似乎没有按预期工作。它也不是一个好的解决方案,因为将来我计划在多个面板中更新2个以上的组合框。
public class ExcelReader extends SwingWorker<DefaultComboBoxModel[], String> {
private boolean isData1 = false;
private final DefaultComboBoxModel model1;
private final DefaultComboBoxModel model2;
private final DefaultComboBoxModel[] models = new DefaultComboBoxModel[2];
// Constructor called from a panel that has 2 comboboxes
public ExcelReader(DefaultComboBoxModel model1, DefaultComboBoxModel model2) {
this.model1 = model1;
this.model2 = model2;
}
@Override
protected DefaultComboBoxModel[] doInBackground() throws Exception {
///// some code .....
///// some code .....
// If data that needs to go to combobox1 is found
if (someExpression)
isData1 = true;
publish(someString);
///// some code .....
///// some code .....
models[0] = model1;
models[1] = model2;
return models;
}
@Override
protected void process(List<String> chunks) {
for (String row : chunks) {
if (isData1) {
model1.addElement(row);
isData1 = false;
}
else
model2.addElement(row);
}
}
那么如何才能使用一个SwingWorker来填充许多组合框(可能包含在不同的面板中)?
顺便说一下上面的例子,我从我的一个面板(扩展JPanel的类)调用了ExcelReader。在第一种情况下,调用工作者的面板只有一个组合框,第二种情况有2.虽然第一个例子工作正常,这是更新gui中组合框的正确方法还是应该从其他地方调用工作者?
答案 0 :(得分:3)
SwingWorker
为您同步UI更新。SwingWorker
批量更新,同时将它们映射到用户界面中的逻辑功能。代码:
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class TestPanel extends JPanel {
private TestPanel() {
super();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Map<String, DefaultComboBoxModel> map = new HashMap<String, DefaultComboBoxModel>();
for (int i = 0; i < 5; i++) {
JComboBox combo = new JComboBox();
add(combo);
map.put("combo" + i, (DefaultComboBoxModel) combo.getModel());
}
add(new JButton(new AbstractAction("fill me") {
@Override
public void actionPerformed(ActionEvent e) {
new MyWorker(map).run();
}
}));
}
private class MyWorker extends SwingWorker<Void, String[]> {
private final Map<String, DefaultComboBoxModel> map;
public MyWorker(Map<String, DefaultComboBoxModel> map) {
this.map = map;
}
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < 20; i++) {
String[] cell = new String[2];
cell[0] = "combo" + i % 5;
cell[1] = "value " + i;
publish(cell);
}
return null;
}
@Override
protected void process(List<String[]> chunks) {
for (String[] chunk : chunks) {
map.get(chunk[0]).addElement(chunk[1]);
}
}
};
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("SwingWorker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new TestPanel();
frame.setContentPane(panel);
// Display the window.
frame.setSize(200, 300);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
}