哪里的&QUOT的Java Swing的对应; GetMessage函数()"循环? [英] Where is the Java Swing counterpart of "GetMessage()" loop?

查看:127
本文介绍了哪里的&QUOT的Java Swing的对应; GetMessage函数()"循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一些Win32的GUI编程几年前。现在,我使用的Java Swing。

I did some Win32 GUI programming several years ago. Now I am using Java Swing.

只是出于好奇,哪里是Win32的消息循环逻辑的摇摆对应?在Win32中,它与API的 GetMessage函数()。我想这一定是深深包裹的地方。

Just out of curiosity, where is the Swing counterpart of Win32 message loop logic? In Win32, it is achieved with the API GetMessage(). I guess it must have been wrapped deeply somewhere.

推荐答案

下图显示了广泛的Swing / AWT如何工作在Windows平台上:

Overview

The following diagram broadly illustrates how Swing/AWT works on the Windows platform:

    Client Listeners (Us)
             ▲
             │ events dispatched to client code
 ╭ ◀─────────┴───────────╮
 │ Event Dispatch Thread │
 ╰───────────┬─────────▶ ╯
             │ events pulled from the queue
             ▼
        Event Queue
             ▲
             │ events posted to the queue
 ╭ ◀─────────┴───────────╮
 │    WToolkit Thread    │
 ╰───────────┬─────────▶ ╯
             │ messages pulled via PeekMessage
             ▼
        Windows API

该架构是从我们由事件驱动的抽象几乎完全隐藏。当事件被触发(的actionPerformed 的paintComponent 等)和偶尔我们只与最顶层的最终互动发布自己的活动(的invokeLater 重绘,等等)。

This architecture is almost entirely hidden from us by the event-driven abstraction. We only interact with the top-most end when events are triggered (actionPerformed, paintComponent, etc.) and by occasionally posting events ourselves (invokeLater, repaint, etc.).

关于这个问题的正式文件往往是很一般,所以我将使用(非常转述)摘录从源头code。

Official documentation on the subject tends to be very general so I'm going to use (very paraphrased) excerpts from the source code.

EDT为Swing事件处理线程和所有Swing程序运行为主在此线程。在大多数情况下,这仅仅是在AWT系统和它位于<一href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventDispatchThread.java#EventDispatchThread\"相对=nofollow> java.awt.EventDispatchThread

The EDT is the Swing event processing thread and all Swing programs run primarily on this thread. For the most part, this is just the AWT system and it is located in java.awt.EventDispatchThread.

调度系统的事件是pretty分散,所以我会通过一个具体的例子假设行走在的JButton 已被点击。

The event dispatching system is pretty dispersed, so I'll walk through a specific example supposing a JButton has been clicked.

要开始搞清楚是怎么回事,我们不妨来看一个堆栈跟踪。

To begin figuring out what's going on, we might look at a stack trace.

class ClickStack {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                JButton button = new JButton("Click for stack trace");

                button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        new Error().printStackTrace(System.out);
                    }
                });

                frame.add(button);
                frame.pack();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

此程序得到我们像下面这样的调用堆栈:

This program gets us a call stack like the following:

at sscce.ClickStack$1$1.actionPerformed
at javax.swing.AbstractButton.fireActionPerformed
...
at javax.swing.DefaultButtonModel.setPressed
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased
at java.awt.Component.processMouseEvent
...
at java.awt.Component.processEvent
...
at java.awt.Component.dispatchEventImpl
...
at java.awt.Component.dispatchEvent
at java.awt.EventQueue.dispatchEventImpl
...
at java.awt.EventQueue.dispatchEvent
at java.awt.EventDispatchThread.pumpOneEventForFilters
at java.awt.EventDispatchThread.pumpEventsForFilter
...
at java.awt.EventDispatchThread.pumpEvents
at java.awt.EventDispatchThread.run

如果我们看一看在 EventDispatchThread 运行 方法,我们可以看到:

If we take a look at the EventDispatchThread run method, we see:

public void run() {
    try {
        pumpEvents(...);
    } finally {
        ...
    }
}

pumpEvents 把我们带到<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventDispatchThread.java#EventDispatchThread.pumpEventsForFilter%28int%2Cjava.awt.Conditional%2Cjava.awt.EventFilter%29\"相对=nofollow> pumpEventsForFilter 其中包含外环逻辑:

pumpEvents takes us to pumpEventsForFilter which contains the outer loop logic:

void pumpEventsForFilter(...) {
    ...
    while(doDispatch && ...) {
        pumpOneEventForFilters(...);
    }
    ...
}

一个事件,然后脱下队列,并在<一个被罚下的调度href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventDispatchThread.java#EventDispatchThread.pumpOneEventForFilters%28int%29\"相对=nofollow> pumpOneEventForFilters

void pumpOneEventForFilters(...) {
    AWTEvent event = null;
    ...
    try {
        ...
        EventQueue eq = getEventQueue();
        ...
        event = eq.getNextEvent();
        ...
        eq.dispatchEvent(event);
        ...
    } catch(...) {
        ...
    } ...
}

<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventQueue.java#EventQueue\"相对=nofollow> java.awt.EventQueue中 包含其中,事件的类型变窄逻辑,而该事件进一步调度。 <一href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventQueue.java#EventQueue.dispatchEvent%28java.awt.AWTEvent%29\"相对=nofollow> 则dispatchEvent 调用<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/EventQueue.java#EventQueue.dispatchEventImpl%28java.awt.AWTEvent%2Cjava.lang.Object%29\"相对=nofollow> dispatchEventImpl 我们看到了以下决定结构:

java.awt.EventQueue contains logic where the type of event is narrowed and the event is further dispatched. dispatchEvent calls dispatchEventImpl where we see the following decision structure:

if (event instanceof ActiveEvent) {
    ...
    ((ActiveEvent)event).dispatch();
} else if (src instanceof Component) {
    ((Component)src).dispatchEvent(event);
    ...
} else if (src instanceof MenuComponent) {
    ((MenuComponent)src).dispatchEvent(event);
} else if (src instanceof TrayIcon) {
    ((TrayIcon)src).dispatchEvent(event);
} else if (src instanceof AWTAutoShutdown) {
    ...
    dispatchThread.stopDispatching();
} else {
    ...
}

我们所熟悉的经过组件路径大多数事件。

组件dispatchEvent也#调用<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/Component.java#Component.dispatchEventImpl%28java.awt.AWTEvent%29\"相对=nofollow> dispatchEventImpl 其中,对大多数听众类型的事件,呼吁<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/java/awt/Component.java#Component.processEvent%28java.awt.AWTEvent%29\"相对=nofollow> 的processEvent 凡在活动范围缩小,再进行转发:

Component#dispatchEvent calls dispatchEventImpl which, for most listener-type events, calls processEvent where the event is narrowed down and forwarded again:

/**
 * Processes events occurring on this component. By default this
 * method calls the appropriate process<event type>Event
 * method for the given class of event.
 * ...
 */
protected void processEvent(AWTEvent e) {
    if (e instanceof FocusEvent) {
        processFocusEvent((FocusEvent)e);
    } else if (e instanceof MouseEvent) {
        switch(e.getID()) {
          case MouseEvent.MOUSE_PRESSED:
          case MouseEvent.MOUSE_RELEASED:
          case MouseEvent.MOUSE_CLICKED:
          case MouseEvent.MOUSE_ENTERED:
          case MouseEvent.MOUSE_EXITED:
              processMouseEvent((MouseEvent)e);
              break;
          case ...:
              ...
        }
    } else if (e instanceof KeyEvent) {
        processKeyEvent((KeyEvent)e);
    } else if (e instanceof ComponentEvent) {
        processComponentEvent((ComponentEvent)e);
    } else if (...) {
        ...
    } ...
}

对于的JButton 点击,我们下面一个的MouseEvent

这些低级别的事件,最终有一个单一的处理器内部的组件。因此,例如,我们可以看看<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/javax/swing/plaf/basic/BasicButtonListener.java?av=f\"相对=nofollow> javax.swing.plaf.BasicButtonListener 它实现了许多侦听器接口。

These low level events ultimately have a single handler internal to the Component. So for example, we might have a look at javax.swing.plaf.BasicButtonListener which implements a number of listener interfaces.

BasicButtonListener 使用鼠标事件来改变pssed按钮模型的状态$ P $。最后,按钮模型决定,如果它被点击的<一个href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/javax/swing/DefaultButtonModel.java#DefaultButtonModel.set$p$pssed%28boolean%29\"相对=nofollow> 集$ P pssed $,触发一个的ActionEvent 和我们的听众的的actionPerformed 被调用。

BasicButtonListener uses the mouse events to change the pressed state of the button model. Finally, the button model determines if it's been clicked in setPressed, fires an ActionEvent and our listener's actionPerformed gets called.

这是一个有点难以挖掘,因为源不是在网上提供。您需要下载OpenJDK源码

This is a bit harder to dig up since the source isn't available online. You'll need to download the OpenJDK source.

实施实际的本地窗口如何当然是特定于平台的,但我可以通过在Windows平台上一点,因为它是你问什么。你会发现在Windows平台上的东西,在以下目录:

How the actual native window is implemented is of course platform-specific but I can go through the Windows platform a bit since it's what you asked about. You'll find the Windows platform stuff in the following directories:


  • Java的:的src /窗/班/阳光/ AWT /窗口

  • 本机:的src /窗/本地/日光/窗口

  • Java: src/windows/classes/sun/awt/windows
  • Native: src/windows/native/sun/windows

Windows实现 java.awt.Toolkit中的 sun.awt.windows.WToolkit 的启动一个单独的线程实际消息循环。 <一href=\"http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/8-b132/sun/awt/windows/WToolkit.java#WToolkit.run%28%29\"相对=nofollow> WToolkit#运行 调用JNI方法事件循环。在源文件中的注释解释说:

The Windows implementation of java.awt.Toolkit, sun.awt.windows.WToolkit starts a separate thread for the actual message loop. WToolkit#run calls a JNI method eventLoop. A comment in the source file explains that:

/*
 * eventLoop() begins the native message pump which retrieves and processes
 * native events.
 * ...

这导致我们的C ++ AwtToolkit 类,位于 awt_Toolkit.h awt_Toolkit.cpp (其他类都遵循相同的文件名约定)。

This leads us to the C++ AwtToolkit class, located in awt_Toolkit.h and awt_Toolkit.cpp (other classes follow the same file name convention).

的本机实现事件循环要求 AwtToolkit ::消息循环

AwtToolkit::GetInstance().MessageLoop(AwtToolkit::PrimaryIdleFunc,
                                      AwtToolkit::CommonPeekMessageFunc);

AwtToolkit :: CommonPeekMessageFunc 来电的 的PeekMessage ,这是的 的GetMessage 。)

(AwtToolkit::CommonPeekMessageFunc calls PeekMessage, which is the non-blocking alter-ego of GetMessage.)

这是哪里外环位于:

UINT
AwtToolkit::MessageLoop(IDLEPROC lpIdleFunc,
                        PEEKMESSAGEPROC lpPeekMessageFunc)
{
    ...

    m_messageLoopResult = 0;
    while (!m_breakMessageLoop) {

        (*lpIdleFunc)();

        PumpWaitingMessages(lpPeekMessageFunc); /* pumps waiting messages */
        ...
    }
    ...
}

PumpWaitingMessages 有一个实际的熟悉的前瞻性消息循环:

PumpWaitingMessages has an actual familiar-looking message loop:

/*
 * Called by the message loop to pump the message queue when there are
 * messages waiting. Can also be called anywhere to pump messages.
 */
BOOL AwtToolkit::PumpWaitingMessages(PEEKMESSAGEPROC lpPeekMessageFunc)
{
    MSG  msg;
    ...

    while (!m_breakMessageLoop && (*lpPeekMessageFunc)(msg)) {
        ...

        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    ...
}

(并调用 在DispatchMessage 调用的 的WindowProc 回调。)

本机窗口是由我们在Java的code A C ++对象具有特定于平台的东西,还有一些API的一个松散的平行包裹。

The native window is wrapped by a C++ object which has platform-specific stuff, as well as a loose parallel of some of the API we have in Java code.

的WindowProc 切入点,似乎是在 AwtFrame :: WindowProc中,它代表了超类层次结构。大多数消息是由 AwtComponent :: WindowProc中处理。例如, AwtComponent :: WindowProc中包含以下开关情况:

The WindowProc entry point appears to be in AwtFrame::WindowProc, which delegates up the superclass hierarchy. A majority of messages are handled by AwtComponent::WindowProc. For example, AwtComponent::WindowProc contains the following switch case:

case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
    mr = WmMouseDown(static_cast<UINT>(wParam), myPos.x, myPos.y,
                     LEFT_BUTTON);
    break;

AwtComponent :: WmMouseDown 开头的一系列调用该职位 java.awt.MouseEvent 的EventQueue 在Java中:

AwtComponent::WmMouseDown begins a series of calls that posts a java.awt.MouseEvent to the EventQueue in Java:

SendMouseEvent(java_awt_event_MouseEvent_MOUSE_PRESSED, now, x, y,
               GetJavaModifiers(), clickCount, JNI_FALSE,
               GetButton(button), &msg);

该事件被发布后,我们最终导致回哪里看到的EDT事件的顶部。

After the event is posted, we are ultimately lead back to the top where the event is seen on the EDT.

这篇关于哪里的&QUOT的Java Swing的对应; GetMessage函数()&QUOT;循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆