【发布时间】:2015-04-26 17:13:38
【问题描述】:
首先,我不是在询问事件处理。我知道处理是使用观察者模式实现的。
让我举一个小例子。假设我在 JFrame 上有一个 Jbutton。我点击这个按钮的顶部。 现在按钮怎么知道我点击了它?
1) 有没有等待点击的java线程?如果是这样,这段代码是从哪里来的(等到我被点击部分)?那么每个swing组件是否都在等待线程之上的事件?我认为这是一项非常昂贵的任务。
2) 如果没有,它是如何工作的?
【问题讨论】:
首先,我不是在询问事件处理。我知道处理是使用观察者模式实现的。
让我举一个小例子。假设我在 JFrame 上有一个 Jbutton。我点击这个按钮的顶部。 现在按钮怎么知道我点击了它?
1) 有没有等待点击的java线程?如果是这样,这段代码是从哪里来的(等到我被点击部分)?那么每个swing组件是否都在等待线程之上的事件?我认为这是一项非常昂贵的任务。
2) 如果没有,它是如何工作的?
【问题讨论】:
观察者模式在整个堆栈中使用:
我们的 Swing 应用程序的“事件分派线程”运行如下形式的循环:
while (!shutdownRequested) {
Event e = retrieveEventFromEventQueue(); // for instance our mouse clicked event
handleEvent(e);
}
在 AWT / Swing 中,有单个线程执行该代码。第一次调用将阻塞,直到有新事件可用,handleEvent() 将调用此事件的侦听器。也就是说,单个线程执行所有 UI 更新(这就是为什么不应在事件侦听器中完成长时间运行的任务,因为这会冻结 ui),并且如果用户不与应用程序交互,它会处于休眠状态。
【讨论】:
是否有java线程在等待点击?
是的,java.awt.EventDispatchThread。这里引用java教程的the event dispatch thread section:
Swing 事件处理代码在称为事件的特殊线程上运行 调度线程。大多数调用 Swing 方法的代码也运行在 这个线程。这是必要的,因为大多数 Swing 对象方法都是 不是“线程安全的”:从多个线程中调用它们会带来线程风险 干扰或内存一致性错误。一些 Swing 组件 方法在 API 规范中被标记为“线程安全”;这些可以 从任何线程安全地调用。所有其他 Swing 组件方法 必须从事件调度线程调用。忽略的程序 此规则可能在大多数情况下正常运行,但受制于 难以重现的不可预测的错误。
要回答您的下一个问题,
如果是这样,这段代码是从哪里来的(等我被点击 部分)?
EventDispatchThread 通过在其run 方法中调用pumpEvents(Conditional) 来启动一个永久 事件泵。
public void run() {
try {
pumpEvents(new Conditional() {
public boolean evaluate() {
return true;
}
});
} finally {
getEventQueue().detachDispatchThread(this);
}
}
任何事件处理程序都可以随时选择阻止此事件泵,但应通过再次调用 pumpEvents(Conditional) 来启动新泵(而不是新 EDT)。一旦Conditional 评估为false 并且额外的Event 被抽出并调度,此辅助事件泵将自动退出。
泵事件将调用AWTEvent#getNextEvent,它将从事件队列中检索事件。
那么每个swing组件是否都在等待顶部的事件 线程?我认为这是一项非常昂贵的任务。
再次,java教程回答了这个
考虑在事件调度线程上运行的代码很有用 作为一系列简短的任务。大多数任务都是调用 事件处理方法,例如 ActionListener.actionPerformed。其他 任务可以由应用程序代码调度,使用 invokeLater 或 调用并等待。事件派发线程上的任务必须快速完成; 如果他们不这样做,未处理的事件会备份并且用户界面变为 没有反应。
事件排在独立于平台的类java.awt.EventQueue 中。事件存储在给定优先级的队列中,每个优先级创建一个队列。
private static final int LOW_PRIORITY = 0;
private static final int NORM_PRIORITY = 1;
private static final int HIGH_PRIORITY = 2;
private static final int ULTIMATE_PRIORITY = 3;
事件从 EventQueue 中拉出,从 Queue 开始 最高优先级。我们在所有队列中按降序进行。
请注意,为了获得更好的性能,某些通常调用的事件会被缓存,例如 PaintEvent.Paint、PaintEvent.UPDATE、MouseEvent.MOUSE_MOVED、MouveSevent.MOUSE_DRAGGED。
这并没有你想象的那么贵。
【讨论】:
是否有java线程在等待点击?
是的,它被称为事件调度线程 (EDT)。
由于 Swing 中的所有组件都是轻量级的,这意味着只是一个漂亮的动画而已,它实际上是顶级组件,例如,JFrame,它跟踪鼠标点击,并将它们传递给组件那个像素。
【讨论】:
MouseEvent 的人都知道JFrame 做了什么;)