【问题标题】:How events are generated in Java?Java中的事件是如何产生的?
【发布时间】:2015-04-26 17:13:38
【问题描述】:

首先,我不是在询问事件处理。我知道处理是使用观察者模式实现的。

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

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

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

【问题讨论】:

    标签: java swing events


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我就是想要这样的答案
    【解决方案2】:

    是否有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.PaintPaintEvent.UPDATEMouseEvent.MOUSE_MOVEDMouveSevent.MOUSE_DRAGGED

    这并没有你想象的那么贵。

    【讨论】:

      【解决方案3】:

      是否有java线程在等待点击?

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

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

      【讨论】:

      • 世界上所有谈论设计模式和MouseEvent 的人都知道JFrame 做了什么;)
      猜你喜欢
      • 2012-02-06
      • 1970-01-01
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 2020-07-10
      • 1970-01-01
      相关资源
      最近更新 更多