Код проверки Swing в потоке отправки событий во время выполнения

Существуют ли какие-либо библиотеки, которые используют код для проверки того, что методы, вызываемые компонентами Swing, вызываются в потоке отправки событий? Вероятно, было бы не слишком сложно написать базовый код для этого, но я уверен, что есть крайние случаи и еще много чего, с чем работали другие люди. Я ищу это во время выполнения, а не для модульных тестов.


person Jeff Storey    schedule 10.06.2010    source источник


Ответы (4)


В структуре FEST есть инструмент для обнаружения использования Swing вне EDT. По сути, вы устанавливаете RepaintManager. Фреймворк ориентирован на тестирование, но RepaintManager можно использовать во время развертывания.

В качестве альтернативы, чтобы проверить все методы, такие как геттеры и сеттеры, для доступа только к EDT, вы можете использовать AspectJ и weaving во время загрузки, чтобы добавить совет SwingUtilities.isDisaptchThread () к каждому методу в ваших компонентах Swing (и компонентах JDK Swing. )

@Aspect
public class EDTCheck {

    @Pointcut("call (* javax.swing..*+.*(..)) || " +
              "call (javax.swing..*+.new(..))")
    public void swingMethods() {}

    @Pointcut("call (* com.mystuff.swing..*+.*(..)) || " +
              "call (com.mystuff.swing..*+.new(..))")
    public void mySwingMethods() {}


    @Pointcut("call (* javax.swing..*+.add*Listener(..)) || " +
              "call (* javax.swing..*+.remove*Listener(..)) || " +
              "call (void javax.swing.JComponent+.setText(java.lang.String))")
    public void safeMethods() {}

    @Before("(swingMethods() || mySwingMethods()) && !safeMethods()")
    public void checkCallingThread(JoinPoint.StaticPart thisJoinPointStatic) {
        if(!SwingUtilities.isDispatchThread()) {
            System.out.println(
                    "Swing single thread rule violation: " 
                    + thisJoinPointStatic);
            Thread.dumpStack();
            // or you might throw an unchecked exception
        }
    }

}

(Немного изменено из статьи - добавлен pointcut mySwingMethods и используется SwingUtiliites.isDispatchThread (). На практике это то же самое, что и EventQueue.isDispatchThread (), но абстракция более чистая.)

person mdma    schedule 10.06.2010
comment
Спасибо. Я видел FEST, но видел его только в контексте модульного тестирования. Думаю, я мог бы использовать его снаружи. - person Jeff Storey; 10.06.2010

Я наткнулся на простой и умный (хотя и не совсем пуленепробиваемый) метод Скотта Делапа по адресу http://today.java.net/pub/a/today/2005/04/19/desktoplive.html.

Как указано в ответе FEST от mdma выше, можно использовать настраиваемый RepaintManger, просто переопределив методы

addInvalidComponent(JComponent component) 

и

addDirtyRegion(JComponent component, int x, int y, int w, int h)

и использовать

SwingUtilities.isEventDispatchThread()

чтобы проверить, находимся ли мы на AWT, вы можете довольно легко интегрировать это в JUnit, добавив

org.JUnit.Assert.fail("AWT Thread Violation")

в вашей программе проверки.

Логика здесь в том, что большинство (но не все) операций Swing вызывают перерисовку, которая в конечном итоге вызывает эти методы в RepaintManager, чтобы мы могли их поймать и выполнить нашу проверку.

У Александра Поточкина есть хороший обзор различных методов: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

person dassimon    schedule 14.09.2012
comment
Один шаг был описан только в связанном блоге (который доступен только на сайте archive.org: вот оно. Чтобы использовать свой собственный менеджер перерисовки, вам понадобится этот статический вызов: RepaintManager.setCurrentManager(new MyRepaintManager()); - person Joshua Goldberg; 03.09.2014

С точки зрения кодирования, четко отделите код EDT от кода, не относящегося к EDT. Избегайте SwingWorker, как чумы.

Чтобы подтвердить, что вы находитесь в EDT (вставьте ! для выключения), добавьте строку:

assert java.awt.EventQueue.isDispatchThread();

Для этого вам понадобится _4 _ / _ 5_. Однако в основном он работает как исполняемый комментарий.

person Tom Hawtin - tackline    schedule 10.06.2010
comment
Какая у вас альтернатива для длительных задач вместо SwingWorker? - person Jeff Storey; 10.06.2010
comment
Отправляет задачи в другой поток [пул], который отправляет задачи обратно (прямо или косвенно) через invokeLater. - person Tom Hawtin - tackline; 10.06.2010

Все, что вам нужно, это следующий код:

void method() {
    if (!SwingUtilities.isEventDispatchThread()) {
       SwingUtilities.invokeAndWait(new Runnable() { public void run() { method(); } );
       return;
    }

    // do method code here, guaranteed to be in EDT
}

Кроме того, использование Substance в качестве вашего LAF поможет вам определить, где вещи, связанные с Swing, не исполняется на EDT. У него есть проверки, чтобы убедиться, что все Swing-файлы выполняются в правильном потоке, в противном случае он не работает с исключением.

person Chris Dennett    schedule 10.06.2010
comment
код инструмента указывает, что он хочет сделать это во время компиляции, а не во время выполнения. - person aioobe; 10.06.2010
comment
Эрг. Будьте ясны, находитесь ли вы на EDT или нет. Код не должен проверять, а затем делать invokeLater. Конечно, избегайте invokeAndWait, если вам не нравятся тупиковые ситуации. assert java.awt.EventQueue.isDispatchThread(); - сделано. - person Tom Hawtin - tackline; 10.06.2010
comment
@aioobe не знаю, он говорит «инструмент», а затем говорит, что он хочет его во время выполнения. Я полагаю, он ищет аннотации, которые украшают код, чтобы проверить безопасность потока. Ardor3D делает нечто подобное с аннотацией @mainthread. - person Chris Dennett; 10.06.2010
comment
Я в основном пытаюсь протестировать свое существующее приложение. Над ним было несколько разработчиков, и я просто хочу запустить его и убедиться, что материал Swing происходит на EDT, без ручного прохождения всего кода. Меня не волнует, с аспектами или аннотациями, я просто смотрю, существует ли что-то уже. - person Jeff Storey; 10.06.2010
comment
Используйте вещество LAF, как указано. Это вызовет исключения. Я использовал эту тактику в прошлом. pushing-pixels.org/?p=368 - person Chris Dennett; 10.06.2010