2

起動時にExcelファイルからデータを読み取る小さなGUIプログラムがあり、これらのデータの一部は関連するコンボボックスに移動する必要があります。コンボボックスごとに個別の 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);
    }
}

これは問題なく動作しますが、1 つの SwingWorker クラスを使用して複数のコンボボックスを埋めるにはどうすればよいでしょうか? これには、ファイルを一度だけ読み取るという利点があります。コンボボックスに移動する必要があるものが見つかると、関連するコンボボックスが更新され、プログラムはファイルの最後まで次の行を読み続けます。

そのため、1 つの 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);

    }
}

では、1 つの SwingWorker だけを使用して、多くのコンボボックス (異なるパネルに含まれる可能性がある) を埋めるにはどうすればよいでしょうか?

ところで、上記の例では、パネルの 1 つ (JPanel を拡張するクラス) から ExcelReader を呼び出しています。最初のケースでは、ワーカーを呼び出すパネルにはコンボボックスが 1 つしかありませんが、2 つ目の例では 2 つしかありません。

4

1 に答える 1

3
  • モデルを論理名にマップして、Excel から UI の論理部分にデータを添付できるようにします。
  • 操作したい UI 要素 (この場合はモデル) をワーカーに渡します。
  • できるだけ早く UI スレッド (この場合はアクション) から離れてSwingWorker、UI の更新を同期させます。
  • SwingWorkerUI の論理関数にマッピングしながら、バッチ更新を行います。

コード:

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 に答える