Это один из тех вопросов, который радует меня тем, что я купил книгу Робинсона и Воробьева о Swing .
Все, что обращается к состоянию java.awt.Component
, должно выполняться внутри EDT, с тремя исключениями: все, что конкретно задокументировано как поточно-ориентированное, например repaint()
, revalidate()
и invalidate()
; любой компонент в пользовательском интерфейсе, который еще не был реализован ; и любой Компонент в Апплете до того, как start()
этого Апплета был вызван.
Методы, специально созданные для обеспечения многопоточной безопасности, настолько необычны, что часто достаточно просто запомнить те, которые являются; Вы также можете избежать неприятностей, если предположить, что таких методов нет (например, совершенно безопасно обернуть вызов перерисовки в SwingWorker).
Реализовано означает, что Компонент является либо контейнером верхнего уровня (например, JFrame), для которого был вызван любой из setVisible(true)
, show()
или pack()
, либо он был добавлен к реализованному компоненту. Это означает, что совершенно нормально построить свой пользовательский интерфейс в методе main (), как это делают многие учебные примеры, поскольку они не вызывают setVisible(true)
в контейнере верхнего уровня, пока каждый компонент не будет добавлен в него, не настроены шрифты и границы и т. д.
По тем же причинам совершенно безопасно построить пользовательский интерфейс апплета в его методе init()
, а затем вызвать start()
после того, как все будет построено.
Включение последующих изменений компонентов в Runnables для отправки в invokeLater()
становится легко получить сразу после выполнения всего лишь нескольких раз. Единственное, что меня раздражает, это чтение состояния компонента (скажем, someTextField.getText()
) из другого потока. Технически это тоже должно быть заключено в invokeLater()
; на практике это может сделать уродливый код быстрым, и я часто не беспокоюсь, или я осторожен, чтобы получить эту информацию в начальный момент обработки события (как правило, в любом случае самое подходящее время для этого).