2

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

4

1 回答 1

3
  • 将您的模型映射到逻辑名称,以便您可以将数据从 excel 附加到 UI 的逻辑部分。
  • 将您希望与之交互的 UI 元素(在本例中为模型)传递给工作人员
  • 尽快关闭 UI 线程(在本例中为操作)并让SwingWorker同步 UI 更新为您。
  • SwingWorker批处理为您更新,同时将它们映射到 UI 中的逻辑函数。

编码:

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();
            }
        });
    }
}
于 2012-08-19T17:01:11.400 回答