Swing, Passive View и долгосрочные задачи - PullRequest
4 голосов
/ 26 февраля 2010

Я пытаюсь реализовать Пассив Просмотр системы графического интерфейса в разгаре. По сути, я хочу, чтобы моя реализация представления (часть, которая фактически содержит свинг-код) была минимальной, и выполняю большую часть работы в своем классе Presenter. докладчик не должен зависеть от свинга, а также должен «запускать шоу», то есть сообщать представлению, что делать, а не наоборот.

Я сталкиваюсь с проблемами при работе с долго выполняющимися задачами и разделением потоков в целом. Я хочу, чтобы обновления GUI выполнялись на EDT, а логика докладчика - в другом потоке. Если я хочу, чтобы докладчик обновил некоторую часть графического интерфейса, это довольно просто, я пишу что-то вроде этого:

public interface View {
    void setText(String text);
}

public class Presenter {
    View view;
    ...
    public void setTextInVIew() {
        view.setText("abc");
    }
}

public class MyFrame implements View {
    JTextField textField;
    ...
    public void setText(final String text) {
        SwingUtilities.InvokeLater(new Runnable() {
            public void run() {
                textField.setText(text);
            }
        });
    }
}

Однако, когда графический интерфейс должен информировать докладчика о том, что произошло какое-то действие, я хочу отключить EDT и реагировать на него в другом потоке:

public class Presenter {
    ...
    public void buttonPressed() {
         // shouldn't run on EDT
    }
}

public class MyFrame implements View {
    JButton button;
    public MyFrame() {
        ...
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                presenter.ButtonPressed();
            }
        });
    }
}

так как код actionPerformed выполняется из EDT, как и Presenter.buttonPressed. Я знаю, что у Swing есть концепция SwingWorker - запуск задач в другом потоке, однако, похоже, мне придется вставить свинг-код в докладчика, и представление запускает шоу. Есть идеи как это решить?

Ответы [ 4 ]

2 голосов
/ 26 февраля 2010

Возможно, вас заинтересует Task API , чтобы избежать всех шаблонов. В противном случае решение akf выглядит нормально (хотя нет необходимости создавать переменную для SwingWorker, вы можете просто создать новую и выполнить анонимную).

2 голосов
/ 26 февраля 2010

вы можете сделать что-то вроде следующего, что сохранит ваш код GUI на месте и просто выполнит работу, чтобы выйти из EDT:

 button.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
           SwingWorker sw = new SwingWorker() {
             public Object doInBackground(){
                 presenter.ButtonPressed();             
                 return null;
            }
          }; 
          sw.execute();
        }
    });
0 голосов
/ 28 февраля 2010

ОК - у меня есть еще один вариант: Спин

В конечном итоге все эти решения передают вызовы между потоками. Я думаю, что цель состоит в том, чтобы найти решение, которое не требует больших затрат стандартного кода с вашей стороны. Вы можете, например, подключить всех ваших слушателей, чтобы они проверили, находятся ли они в соответствующем рабочем потоке, а затем - прокси для ExecutorService, если нет. Но это большая проблема. Гораздо лучше, чтобы проксирование происходило в слое между вашим бизнесом и объектами просмотра - привязка / слушатель / как вы хотите называть это слоем.

0 голосов
/ 27 февраля 2010

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

Выезд: EventBus

Существуют и другие реализации архитектуры шины, но EventBus популярен.

- обновление -

Таким образом, EventBus собирается предоставить очень чистый способ проксирования от не-EDT к EDT (намного приятнее, чем множество явных вызовов SwingUtilities.invokeLater () - но в основном делает то же самое. Хотя EventBus способен свяжите много уведомлений и сделайте так, чтобы они запускались в одном исполняемом EDT, так что производительность будет лучше).

Но это не решает необходимость прокси-событий из EDT и запуска их в рабочем потоке. В EventBus есть класс ThreadSafeEventService, который, вероятно, можно использовать в качестве основы для такого зверя - он может быть связан с ExecutorService, например, для обработки определенных регистраций событий для определенных слушателей.

Я думаю, ключ ко всему этому для меня заключается в том, что какое бы решение вы ни придумали, оно должно пытаться инкапсулировать вращение вкл / выкл EDT

Кстати, то, о чем вы спрашиваете здесь, действительно похоже на модель многопоточности Microsoft's Apartment.

...