SwingWorker更新多个面板中的多个组合框

时间:2012-08-19 16:18:44

标签: java swing combobox swingworker comboboxmodel

我有一个小的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中组合框的正确方法还是应该从其他地方调用工作者?

1 个答案:

答案 0 :(得分:3)

  • 将模型映射到逻辑名称,这样您就可以将excel中的数据附加到UI的逻辑部分。
  • 将您想要与之交互的UI元素(在本例中为模型)传递给工作者
  • 尽快离开UI线程(在这种情况下是操作),让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();
            }
        });
    }
}