如何在Java中生成事件?

如何在Java中生成事件?,java,swing,events,Java,Swing,Events,首先,我不是在问事件处理的问题。我知道处理是使用观察者模式实现的 让我举一个小例子。假设我在JFrame上有一个Jbutton。我点击这个按钮的顶部。 现在按钮怎么知道我点击了它 1) 是否有java线程等待单击?如果是这样的话,这个代码从哪里来(等到我点击了部分)?那么每个swing组件是否都在线程顶部等待事件?我想这是一项非常昂贵的任务 2) 如果没有,这是如何工作的 是否有java线程等待单击 是的,它被称为事件调度线程(EDT) 由于Swing中的所有组件都是轻量级的,这意味着只是一个漂

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

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

1) 是否有java线程等待单击?如果是这样的话,这个代码从哪里来(等到我点击了部分)?那么每个swing组件是否都在线程顶部等待事件?我想这是一项非常昂贵的任务

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

是否有java线程等待单击

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

由于Swing中的所有组件都是轻量级的,这意味着只是一个漂亮的动画而已,因此它实际上是顶级组件,比如说,跟踪鼠标单击并将其传递给该像素上的组件的
JFrame

是否有java线程等待单击

是,
java.awt.EventDispatchThread
。下面引用java教程的一段话:

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)。一旦
条件
评估为
,并发送额外的
事件
,该辅助事件泵将自动退出

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

然后,是否每个swing组件都在顶部等待事件 线的数量?我想这是一项非常昂贵的任务

java教程再次回答了这个问题

考虑在事件分派线程上运行的代码是很有用的 作为一系列简短的任务。大多数任务都是对 事件处理方法,如ActionListener.actionPerformed。其他 任务可以通过应用程序代码,使用invokeLater或 调用EANDWAIT。事件调度线程上的任务必须快速完成; 如果没有,未处理的事件将备份,用户界面将变为 反应迟钝

事件在独立于平台的类
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;
事件从事件队列中拉出,从 最高优先权。我们在所有队列中按降序前进

请注意,一些通常调用的事件会被缓存以获得更好的性能,例如
PaintEvent.Paint
PaintEvent.UPDATE
MouseEvent.MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u MOUSE\u


这并不像您想象的那么昂贵。

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

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

    while (!shutdownRequested) {
        Event e = retrieveEventFromEventQueue(); // for instance our mouse clicked event
        handleEvent(e);
    }
    
    在AWT/Swing中,有一个线程执行该代码。第一个调用将被阻止,直到新事件可用为止,handleEvent()将为此事件调用侦听器。也就是说,一个线程执行所有UI更新(这就是为什么不应该在事件侦听器中执行长时间运行的任务,因为这会冻结UI),如果用户不与应用程序交互,则该线程处于睡眠状态


  • 所有谈论世界上设计模式的人和
    MouseEvent
    都知道
    JFrame
    的功能;)我确实想要一个这样的答案