Java SWT: упаковка syncExec и asyncExec для очистки кода - PullRequest
5 голосов
/ 03 июня 2010

У меня есть Java-приложение, использующее SWT в качестве инструментария, и я устал от всего уродливого кода, который требуется для обновления элемента GUI.

Просто чтобы активировать отключенную кнопку, мне нужно пройти примерно так:

shell.getDisplay().asyncExec(new Runnable() {
    public void run() {
        buttonOk.setEnabled(true);
    }
});

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

Есть ли способ, которым я могу обернуть это? Я хотел бы класс, как:

public class UIUpdater {
    public static void updateUI(Shell shell, *function_ptr*) {
        shell.getDisplay().asyncExec(new Runnable() {
           public void run() {
              //Execute function_ptr
           }
        });
    }
}

И может использоваться так:

UIUpdater.updateUI(shell, buttonOk.setEnabled(true));

Что-то вроде этого было бы замечательно, если бы скрыл этот ужасный беспорядок, который, похоже, SWT считает необходимым сделать что-либо.

Насколько я понимаю, Java не может выполнять указатели на функции. Но в Java 7 будет нечто, называемое Closures, которое должно быть тем, что я хочу. Но в то же время есть ли что-нибудь, что я могу сделать, чтобы передать указатель на функцию или обратный вызов другой функции, которая должна быть выполнена?

Кроме того, я начинаю думать, что стоило бы приложить усилия, чтобы переделать это приложение в Swing, и мне не нужно мириться с этим уродливым дерьмом и непросплатформенностью SWT. 1018 *

Ответы [ 3 ]

4 голосов
/ 04 июня 2010

У меня была похожая проблема в моем SWT-коде.

Я написал базовый класс, в котором не было ничего, кроме методов asyncExec и syncExec. У меня был метод для каждого метода GUI, который я хотел вызвать.

Мой класс не-GUI-потоков расширил базовый класс.

Таким образом, в классе потока, не являющемся графическим интерфейсом, у меня будет вызов типа setEnabled(shell, true)

В базовом классе я бы определил метод public void setEnabled(Shell shell, boolean flag), который бы включал код в ваш первый пример.

2 голосов
/ 08 июня 2010

Вы говорите, что хотите что-то вроде:

public class UIUpdater {
    public static void updateUI(Shell shell, *function_ptr*) {
        shell.getDisplay().asyncExec(new Runnable() {
           public void run() {
              //Execute function_ptr
           }
        });
    }
}

Тот факт, что вы не можете иметь это, не является функцией SWT, это функция Java как языка программирования. Отсутствие в Java функций и замыканий более высокого порядка не позволяет вам создавать хорошие DSL, которые бы скрывали эту бессмысленность для вас, поэтому остальные полученные вами ответы будут такими же хорошими, как и все, если вы не поменяете языки.

Теперь, если вы использовали такой язык, как, например, Scala, я думаю, что ответ сильно отличается. Возможно, вы бы создали какую-то функцию, имитирующую управляющую структуру, которая обеспечила бы выполнение ваших вызовов SWT в основном потоке отображения SWT.

Что-то вроде:

val enabled = model.isEditable
Swt {
  text.setEnabled(enabled);
  composite.refresh();
}
2 голосов
/ 06 июня 2010

Я решил это некоторое время назад в проекте с закрытым исходным кодом. Мой API работал так:

SWTUtils.asyncExec(display).on(this.getClass(), this).runInUIThread(123);

Этот вызов будет запускать метод runInUIThread(.) в экземпляре this с параметром 123. Здесь нужен беспорядок - параметр this.getClass().

Ваш пример переписан:

SWTUtils.asyncExec(shell.getDisplay()).on(Button.class, buttonOk).setEnabled(true);

Моя реализация использовала CGLib для создания динамического прокси для данного класса. Этот прокси был возвращен on(.), а вызов метода и его параметры были записаны и переданы display.asyncExec(.). Я использовал Objenesis для создания экземпляра прокси.

Вы можете быть удивлены, что не было ощутимого влияния на производительность. Поскольку проксирование было кэшировано, и API отражения, необходимого для вызова фактического метода, стало очень быстрым в Java 1.6, я даже использовал его для прослушивателей событий.

Очевидно, что это довольно безумное решение;) Я не могу его опубликовать, но если вы так же взбешены, как и все эти анонимные внутренние классы, вы можете захотеть пойти на это. На самом деле это не слишком много кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...