Я использую Spring для моего приложения Java Swing. Я инициализирую мои объекты MVC как весенний боб в моем приложении-context.xml таким образом, с @Autowired для DI.
<bean id="model" class="com.Model"/>
<bean id="view" class="com.View"/>
<bean id="controller" class="com.Controller"/>
Он работает без проблем. Однако, читая этот вопрос, я думаю, что я должен поместить все компоненты Swing в SwingUtilities.invokerLater() по этой причине.
Некоторые методы компонента Swing помечены как "потокобезопасные" в спецификации API; они могут быть безопасно вызваны из любого потока. Все остальные методы компонента Swing должны быть вызваны из потока отправки событий. Программы, которые игнорируют это правило, могут нормально функционировать большую часть времени, но подвержены непредсказуемым ошибкам, которые трудно воспроизвести.
Итак, мой вопрос: где/как помещать мои вещи в эту тему Dispatch Event? В настоящее время мой основной метод - это всего лишь один лайнер...
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml");
ОБНОВЛЕНИЕ: Я хочу знать, что я должен делать?
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml");
}
context.xxxx
blahblahblah...
});
Вчера вечером у меня был такой же вопрос, он искал везде, но не мог найти и ответить соответствующим образом. Я несколько секунд пробовал свой мозг, вот что я придумал, и он выглядит довольно солидно.
Это решение использует метод Spring lookup для ленивой загрузки Swing Gui на EDT.
IOnDemandBeanGetter.java
Это интерфейс Spring, который будет использоваться для инъекции метода
public interface IOnDemandBeanGetter {
public IOnDemandBean getBean();
}
IOnDemandBean.java
Интерфейс маркера, возвращаемый IOnDemandBeanGetter
public interface IOnDemandBean {}
GuiOnEdtUtility.java
Эта утилита использует введенный IOnDemandBeanGetter, чтобы получить компонент и загрузить его на EDT.
public class GuiOnEdtUtility {
private final IOnDemandBeanGetter beanGetter;
public GuiOnEdtUtility(IOnDemandBeanGetter beanGetter) {
this.beanGetter = beanGetter;
}
public void createGuiOnEdt(){
SwingUtilities.invokeLater(()->beanGetter.getBean());
}
}
MainGui.java
Это содержит компоненты swing, будет возвращен IOnDemandBeanGetter и загружен в EDT с помощью GuiOnEdtUtility. Вы можете вводить любые компоненты, которые я не делал для простоты, но все они должны иметь lazy-init = "true"
public class MainGui implements IOnDemandBean {
private final JFrame frame = new JFrame();
public MainGui() {
System.out.println(SwingUtilities.isEventDispatchThread()
? "Created On EDT"
: "Not created On EDT");
}
public void init() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
beans.xml
<bean name="onDemandBeanGetter" class="IOnDemandBeanGetter">
<lookup-method name="getBean" bean="mainGui"/>
</bean>
<bean name="guiOnEdtUtility" class="GuiOnEdtUtility" init-method="createGuiOnEdt">
<constructor-arg ref="onDemandBeanGetter"></constructor-arg>
</bean>
<bean name="mainGui" class="MainGui" init-method="init" lazy-init="true"/>
Обновить...
Вот как выглядит MainGui.java, если он унаследовал от JFrame, и он работает одинаково
public class MainGui extends JFrame implements IOnDemandBean {
public MainGui() {
System.out.println(SwingUtilities.isEventDispatchThread()
? "Created On EDT"
: "Not created On EDT");
}
public void init() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(200, 200);
setLocationRelativeTo(null);
setVisible(true);
}
}
Чтобы запустить код в потоке отправки событий, вы можете:
EventQueue.invokeLater(new Runnable() {
public void run() {
//your code here
}
});
... или эквивалентно:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//your code here
}
});
Вы можете использовать любой подход в любом месте, где у вас есть код, который нужно запустить в потоке отправки событий. Просто заверните код внутри анонимного Runnable
и вам хорошо идти.
Обратите внимание: если у вас есть переменные, определенные вне анонимной реализации Runnable
которой вы хотите получить доступ, вам нужно объявить их final
. Для получения дополнительной информации попробуйте следующее: