如何在Java中生成事件?

时间:2015-04-26 17:13:38

标签: java swing events

首先,我不是在询问事件处理。我知道使用Observer模式实现了处理。

让我举一个小例子。假设我在JFrame上有一个Jbutton。我单击此按钮的顶部。 现在按钮如何知道我点击了它?

1)是否有任何java线程等待点击?如果是这样的代码来自哪里(等到我点击部分)?那么每个swing组件是否都在等待线程之上的事件?我认为这是一项非常昂贵的任务。

2)如果没有,这是如何工作的?

3 个答案:

答案 0 :(得分:2)

观察者模式在整个堆栈中使用:

  1. 用户释放鼠标按钮
  2. 鼠标向CPU发送消息,触发硬件中断
  3. 操作系统的中断处理程序意识到自按下按钮后鼠标尚未移动,即发生了鼠标点击。它标识鼠标位置的窗口,以及负责该窗口的应用程序,并将鼠标单击的消息放入应用程序的事件队列中
  4. 我们的Swing应用程序的“事件调度线程”运行以下形式的循环:

    while (!shutdownRequested) {
        Event e = retrieveEventFromEventQueue(); // for instance our mouse clicked event
        handleEvent(e);
    }
    

    在AWT / Swing中,有单个线程执行该代码。第一个调用将阻塞,直到新事件变为可用,handleEvent()将调用此事件的侦听器。也就是说,单个线程执行所有UI更新(这就是为什么长时间运行的任务不应该在事件监听器中完成,因为这会冻结ui),并且如果用户没有与应用程序交互,它就会休眠。

答案 1 :(得分:1)

  

有没有等待点击的java线程?

是的,java.awt.EventDispatchThread。这里引用了来自java教程的the event dispatch thread section

  

Swing事件处理代码在称为事件的特殊线程上运行   派遣线程。大多数调用Swing方法的代码也会运行   这个帖子。这是必要的,因为大多数Swing对象方法都是   不是“线程安全”:从多个线程调用它们冒险线程   干扰或内存一致性错误。一些Swing组件   方法在API规范中标记为“线程安全”;这些可以   从任何线程安全地调用。所有其他Swing组件方法   必须从事件派发线程调用。忽略的程序   此规则可能在大多数情况下正常运行,但受制于   难以重现的不可预测的错误。

回答你的下一个问题,

  

如果是这样的代码来自哪里(等到我被点击   部)?

EventDispatchThread启动永久事件泵,并在其pumpEvents(Conditional)方法中调用run

public void run() {
    try {
        pumpEvents(new Conditional() {
            public boolean evaluate() {
                return true;
            }
        });
    } finally {
        getEventQueue().detachDispatchThread(this);
    }
}

任何事件处理程序都可以随时选择阻止此事件泵,但应再次调用pumpEvents(Conditional)启动新泵(而不是新的EDT)。 Conditional评估为false后,此辅助事件泵将自动退出,并且会调度另外的Event

泵事件将调用AWTEvent#getNextEvent,它将从事件队列中检索事件。

  

然后每个挥杆组件都在等待顶部的事件   线程?我认为这是一项非常昂贵的任务。

再一次,java教程回答了这个

  

考虑在事件派发线程上运行的代码很有用   作为一系列短期任务。大多数任务都是调用   事件处理方法,例如ActionListener.actionPerformed。其他   可以使用invokeLater或应用程序代码来安排任务   invokeAndWait。事件派发线程上的任务必须快速完成;   如果他们不这样做,未处理的事件将备份并且用户界面变为   不响应。

事件在与平台无关的类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;
  

从Queue of开始,事件从EventQueue中拉出   最高优先级。我们在所有队列中按顺序递减。

请注意,通常调用的某些事件会被缓存以获得更好的性能,例如PaintEvent.PaintPaintEvent.UPDATEMouseEvent.MOUSE_MOVEDMouveSevent.MOUSE_DRAGGED

这并不像你想象的那么贵。

答案 2 :(得分:0)

  

有没有等待点击的java线程?

是的,它被称为事件调度线程(EDT)。

由于Swing中的所有组件都是轻量级的,这意味着只是一个很好的动画,仅此而已,它实际上是顶级组件,例如跟踪鼠标点击的JFrame,并将它们传递给该像素上的组件。