Java 在哪里调用事件调度线程?
我读到所有构造Swing组件和处理事件的代码都必须由事件分派线程运行。我理解这是如何通过使用Java 在哪里调用事件调度线程?,java,multithreading,swing,event-dispatch-thread,Java,Multithreading,Swing,Event Dispatch Thread,我读到所有构造Swing组件和处理事件的代码都必须由事件分派线程运行。我理解这是如何通过使用SwingUtilities.invokeLater()方法实现的。考虑下面的代码,其中GUI初始化在主< 方法本身中完成。 public class GridBagLayoutTester extends JPanel implements ActionListener { public GridBagLayoutTester() { setLayout(new GridB
SwingUtilities.invokeLater()
方法实现的。考虑下面的代码,其中GUI初始化在<代码>主< <代码>方法本身中完成。
public class GridBagLayoutTester extends JPanel implements ActionListener {
public GridBagLayoutTester() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JButton button = new JButton("Testing");
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
button.addActionListener(this);
add(button, gbc);
}
public void actionPerformed(ActionEvent e) {
System.out.println("event handler code");
}
public static void main(String[] args) {
JFrame frame = new JFrame("GridBagLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER);
frame.setSize(800, 600);
frame.pack();
frame.setVisible(true);
System.out.println("Exiting");
}
}
这段代码是如何完美工作的?我们正在构建JFrame
,并在主线程中调用大量其他方法。我不明白EDT在这里的具体位置(它执行的是什么代码?)。GridBagLayoutTester
类的构造函数也从main
方法调用,这意味着EDT没有运行它
总之
newjframe
中还是在setVisible
中,但它是按需初始化的,这就是主方法的结尾(通过主进程线程)不会终止进程的原因。EDT已启动,在等待下一个事件的循环中被阻止
2) 肯定的。该循环从操作系统接收事件,找到JButton并告诉它事件已触发。然后按钮调用侦听器。所有这些都发生在EDT中
您可以查看在想要终止进程(或关闭主窗口)时调用的Swing代码,以查找EDT终止的位置。。。这可以给你一个线索(我稍后再做):事件调度线程,顾名思义,每次需要处理事件时,Swing都会调用它 在您给出的示例中,“测试”按钮将在需要处理动作事件时自动调用actionPerformed方法。因此,actionPerformed方法的内容将由事件调度线程调用 回答最后两个问题:
- 当Swing框架加载时,EDT将自动启动。你不必关心启动这个线程,JRE会为你处理这个任务
- 事件处理程序代码由EDT运行。Swing接口生成的所有事件都是池化的,EDT负责执行它们
Component.repaint()
时,您可以从任何线程调用它。这只是设置一个标志,将组件标记为需要绘制,EDT将在下一个周期中进行绘制
EDT是自动启动的,并且与系统实现紧密相连。它在JVM中处理得很好。通常,它与窗口系统中处理用户交互的单个线程相关。当然,这完全取决于实现。好在你不用担心这个。你只需要知道-如果你与任何Swing组件交互,在EDT上进行
同样,还有一件事很重要。如果要对外部资源执行任何长时间的处理或阻塞,并且要响应用户生成的事件,则必须将其安排在EDT的自己线程中运行。如果未能执行此操作,将导致用户界面在等待长时间处理运行时阻塞。很好的例子是从文件加载、从数据库读取或与网络交互。您可以使用SwingUtilities.isEventDispatchThread()
方法测试是否在EDT(用于创建可从任何线程调用的中立方法)上
以下是我在编写处理EDT的Swing编程时经常使用的两段代码:
void executeOffEDT() {
if (SwingUtilities.isEventDispatchThread()) {
Runnable r = new Runnable() {
@Override
public void run() {
OutsideClass.this.executeOffEDTInternal();
}
};
new Thread(r).start();
} else {
this.executeOffEDTInternal();
}
}
void executeOnEDT() {
if (SwingUtilities.isEventDispatchThread()) {
this.executeOnEDTInternal();
} else {
Runnable r = new Runnable() {
@Override
public void run() {
OutsideClass.this.executeOnEDTInternal();
}
};
SwingUtilities.invokeLater(r);
}
}
void executeOffEDT(){
if(SwingUtilities.isEventDispatchThread()){
Runnable r=新的Runnable(){
@凌驾
公开募捐{
OutsideClass.this.executeOffedInternal();
}
};
新线程(r.start();
}否则{
this.executeOffedInternal();
}
}
void executeOnEDT(){
if(SwingUtilities.isEventDispatchThread()){
this.executeOnEDTInternal();
}否则{
Runnable r=新的Runnable(){
@凌驾
公开募捐{
OutsideClass.this.executeOnEDTInternal();
}
};
SwingUtilities.invokeLater(r);
}
}
EDT线程在您第一次调用
setVisible(true)之后启动代码>如果尚未启动,则为ofc。或者如果调用SwingUtilities.invokeAndWait()
或SwingUtilities.invokeLater()
方法
请参见关于Component.repaint(),我怀疑这只是“设置一个标志”,它实际上是对一个绘画事件(然后将由EDT处理)进行排队。模式是相同的。为了成功使用EDT,您不需要知道处理方法的内部结构。因此,frame.setVisible()调用是在EDT上执行的?否。在您的示例中,整个main()方法是在主线程上执行的。EDT上执行的唯一代码行是actionPerformed方法。我看到的标准是创建某种initializeUserInterface()方法,并将其包装