SwingWorker обновляет несколько комбинаций, списков, таблиц с помощью одной карты

Следуя предыдущему вопросу, который был решен, я могу заполнить несколько полей со списком с SwingWorker, используя один HashMap. Теперь я хочу заполнить/обновить несколько выпадающих списков И списков И таблиц, которые содержатся в разных панелях приложения с графическим интерфейсом, используя одну карту (если возможно). В javadocs я увидел, что и DefaultListModel, и DefaultComboBoxModel расширяют AbstractListModel, поэтому я изменил карту с

Map<String, DefaultComboBoxModel>

to

Map<String, AbstractListModel>

который затем передается в SwingWorker. Следующий код работает, и он может заполнить множество комбинаций и списков, используя одну карту.

SSCCE:

public class TestPanel extends JPanel {

    private final Map<String, AbstractListModel> map = new HashMap<String, AbstractListModel>();

    private TestPanel() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JComboBox combo1 = new JComboBox();
        JComboBox combo2 = new JComboBox();
        JList list1 = new JList(new DefaultListModel());
        JList list2 = new JList(new DefaultListModel());
        add(combo1);
        add(combo2);
        add(new JLabel("LIST 1:"));
        add(list1);
        add(new JLabel("LIST 2:"));
        add(list2);
        map.put("ComboBox1", (DefaultComboBoxModel)combo1.getModel());
        map.put("ComboBox2", (DefaultComboBoxModel)combo2.getModel());
        map.put("List1", (DefaultListModel)list1.getModel());
        map.put("List2", (DefaultListModel)list2.getModel());
        new MyWorker(map).run();
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(new TestPanel());
                frame.setSize(200, 300);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private class MyWorker extends SwingWorker<Void, Object[]> {
        private final int COMBO_BOX_MODEL = 1;
        private final int LIST_MODEL = 2;
        private final Map<String, AbstractListModel> map;

        public MyWorker(Map<String, AbstractListModel> map) {
            this.map = map;
        }

        @Override
        protected Void doInBackground() throws Exception {
            // just a random way to fill the combos and the lists
            for (int i = 0; i < 20; i++) {
                Object[] cell = new Object[3];
                if (i>=0 && i<=4) {
                    cell[0] = "ComboBox1";
                    cell[1] = COMBO_BOX_MODEL;
                } else if (i>=5 && i<=9) {
                    cell[0] = "ComboBox2";
                    cell[1] = COMBO_BOX_MODEL;
                } else if (i>=10 && i<=14) {
                    cell[0] = "List1";
                    cell[1] = LIST_MODEL;
                } else if (i>=15 && i<=20) {
                    cell[0] = "List2";
                    cell[1] = LIST_MODEL;
                }
                cell[2] = "value " + i;
                publish(cell);
            }
            return null;
        }

        @Override
        protected void process(List<Object[]> chunks) {
            for (Object[] chunk : chunks) {
                if (chunk[1] == Integer.valueOf(COMBO_BOX_MODEL)) {
                    DefaultComboBoxModel model = (DefaultComboBoxModel)map.get(chunk[0]);
                    model.addElement(chunk[2]);
                }
                else if (chunk[1] == Integer.valueOf(LIST_MODEL)) {
                    DefaultListModel model = (DefaultListModel)map.get(chunk[0]);
                    model.addElement(chunk[2]);
                }
            }
        }
    };

}

Вопрос 1: Хотя приведенный выше код работает, мне не нравится, как он выглядит (в частности, проверка в методе process()). Есть ли лучший и/или более умный способ сделать все это?

Вопрос 2: Есть ли способ заставить SwingWorker обновлять таблицы вместе с комбо и списками, используя одну карту? Я не мог найти способ, так как DefaultTableModel расширяет AbstractTableModel, который отличается от AbstractListModel, используемого картой.

Я надеюсь, что я был понятен, любая помощь будет оценена по достоинству.


person Rempelos    schedule 08.09.2012    source источник


Ответы (1)


  1. Ваш источник данных, несомненно, имеет систему типов, отличную от Java; код для сопоставления этих типов с типами Java не будет красивее, но, по крайней мере, вы его инкапсулируете. enum может помочь.

  2. Да, вы можете расширить AbstractTableModel и реализовать другие интерфейсы, делегировав их реализации по умолчанию. Схема есть здесь. Вам придется решить, имеет ли смысл такое узкое место в вашем приложении.

    public class SharedModel extends AbstractTableModel
        implements ComboBoxModel, ListModel
    

Приложение: Альтернативой является написание трех моделей (MyTableModel, MyListModel, MyComboBoxModel), каждая из которых ссылается на общую модель данных.

Вы имеете в виду общий интерфейс, реализованный тремя моделями?

Да, интерфейс, реализованный классом, скажем, ApplicationDataModel, который считывает базу данных во внутренний формат. Затем клиентские модели могут запрашивать у ApplicationDataModel данные, необходимые каждой из них для выполнения своего собственного контракта интерфейса.

person trashgod    schedule 09.09.2012
comment
Спасибо, это то, что я хотел. SharedModel нельзя привести к DefaultComboBoxModel или DefaultListModel, поскольку он расширяет AbstractTableModel. Поэтому проверка должна быть перенесена в SharedModel, где я должен добавить методы с двумя версиями (например, addElement) в зависимости от типа компонента (комбо или список). Или, по крайней мере, я так это понимаю. Я прав? Если да, то вы правы насчет узкого места. SharedModel может усложниться, пытаясь решить, какую версию использовать. - person Rempelos; 09.09.2012
comment
Я не уверен, что понимаю это. Вы имеете в виду сделать общий интерфейс, реализуемый тремя моделями? - person Rempelos; 09.09.2012
comment
понятно, так лучше я думаю - person Rempelos; 09.09.2012
comment
Я пошел вперед и продвинул резюме комментариев к ответу. - person trashgod; 10.09.2012