“GetMessage()”循环的Java Swing对应物在哪里?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了“GetMessage()”循环的Java Swing对应物在哪里?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7266字,纯文字阅读大概需要11分钟。
内容图文
几年前我做了一些Win32 GUI编程.现在我正在使用Java Swing.
出于好奇,Win32消息循环逻辑的Swing对应物在哪里?在Win32中,它是通过API GetMessage()实现的.我想它一定已被包裹在某处.
解决方法:
概观
下图概括地说明了Swing / AWT在Windows平台上的工作原理:
Our Listeners
▲
│ (Events dispatched to our code by EDT)
╭ ?─────────┴───────────╮
│ Event Dispatch Thread │
╰───────────▲─────────? ╯
│ (Events pulled from the queue by EDT)
│
Event Queue
▲
│ (Events posted to the queue by WToolkit)
╭ ?─────────┴───────────╮
│ WToolkit Thread │
╰───────────▲─────────? ╯
│ (Messages pulled by WToolkit via PeekMessage)
│
Windows API
事件驱动的抽象几乎完全隐藏了这种体系结构.我们只在触发事件(actionPerformed,paintComponent等)时偶尔与最顶端进行交互,并偶尔自己发布事件(invokeLater,repaint等).
关于这个主题的官方文档往往非常一般,所以我将使用源代码中的(非常复述)摘录.
事件派遣线程
EDT是Swing事件处理线程和all Swing programs run primarily on this thread.在大多数情况下,这只是AWT系统,它位于java.awt.EventDispatchThread.
事件调度系统相当分散,因此我将通过一个特定的例子来假设已经点击了JButton.
为了开始弄清楚发生了什么,我们可能会看一下堆栈跟踪.
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);
}
});
}
}
该程序为我们提供了如下调用堆栈:
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.run方法,我们会看到:
public void run() {
try {
pumpEvents(...);
} finally {
...
}
}
EventDispatchThread.pumpEvents将我们带到EventDispatchThread.pumpEventsForFilter,它包含外部循环逻辑:
void pumpEventsForFilter(...) {
...
while(doDispatch && ...) {
pumpOneEventForFilters(...);
}
...
}
然后将一个事件从队列中拉出并在EventDispatchThread.pumpOneEventForFilters发送以进行调度:
void pumpOneEventForFilters(...) {
AWTEvent event = null;
...
try {
...
EventQueue eq = getEventQueue();
...
event = eq.getNextEvent();
...
eq.dispatchEvent(event);
...
} catch(...) {
...
} ...
}
java.awt.EventQueue包含逻辑,其中事件的类型变窄并且事件被进一步分派. EventQueue.dispatchEvent调用EventQueue.dispatchEventImpl,我们看到以下决策结构:
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 {
...
}
我们熟悉的大多数事件都要经过组件路径.
Component.dispatchEvent调用Component.dispatchEventImpl,对于大多数侦听器类型的事件,调用Component.processEvent,其中事件被缩小并再次转发:
/**
* 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.
这些低级事件最终在Component内部有一个处理程序.例如,我们可以看看javax.swing.plaf.BasicButtonListener,它实现了许多监听器接口.
BasicButtonListener使用鼠标事件来更改按钮模型的按下状态.最后,按钮模型确定它是否在DefaultButtonModel.setPressed中被单击,触发ActionEvent并调用我们的侦听器的actionPerformed.
原生消息
如何实现实际的本机窗口当然是特定于平台的,但我可以稍微浏览一下Windows平台,因为它就是你所问的内容.您将在以下目录中找到Windows平台的内容:
> Java:src/windows/classes/sun/awt/windows
>原住民:src/windows/native/sun/windows
java.awt.Toolkit的Windows实现,即sun.awt.windows.WToolkit,为实际的消息循环启动一个单独的线程. WToolkit.run调用JNI方法eventLoop. A comment in the source file解释说:
/*
* eventLoop() begins the native message pump which retrieves and processes
* native events.
* ...
这将我们引向位于awt_Toolkit.h和awt_Toolkit.cpp的C AwtToolkit类(其他类遵循相同的文件名约定).
native implementation of eventLoop拨打AwtToolkit::MessageLoop:
AwtToolkit::GetInstance().MessageLoop(AwtToolkit::PrimaryIdleFunc,
AwtToolkit::CommonPeekMessageFunc);
(AwtToolkit::CommonPeekMessageFunc调用PeekMessage,这是GetMessage的非阻塞替换.)
这是外环所在的位置:
UINT
AwtToolkit::MessageLoop(IDLEPROC lpIdleFunc,
PEEKMESSAGEPROC lpPeekMessageFunc)
{
...
m_messageLoopResult = 0;
while (!m_breakMessageLoop) {
(*lpIdleFunc)();
PumpWaitingMessages(lpPeekMessageFunc); /* pumps waiting messages */
...
}
...
}
AwtToolkit::PumpWaitingMessages实际上有一个熟悉的消息循环,调用TranslateMessage和DispatchMessage:
/*
* 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;
BOOL foundOne = FALSE;
...
while (!m_breakMessageLoop && (*lpPeekMessageFunc)(msg)) {
foundOne = TRUE;
ProcessMsg(msg); // calls TranslateMessage & DispatchMessage (below)
}
return foundOne;
}
void AwtToolkit::ProcessMsg(MSG& msg)
{
if (msg.message == WM_QUIT) {
...
}
else if (msg.message != WM_NULL) {
...
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
(并记得DispatchMessage称之为WindowProc回调.)
本机窗口由一个C对象包装,该对象具有特定于平台的内容,以及我们在Java代码中使用的一些API的松散并行.
似乎有一些WindowProc功能.其中一个仅由工具包AwtToolkit::WndProc内部使用,以及an empty window.
我们实际感兴趣的WindowProc函数是AwtComponent::WndProc.WndProc调用一个名为AwtComponent::WindowProc的虚函数.一些子类重写WindowProc(例如AwtFrame::WindowProc),但大多数消息由AwtComponent :: WindowProc处理.例如,它包含以下开关案例:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
mr = WmMouseDown(static_cast<UINT>(wParam), myPos.x, myPos.y,
LEFT_BUTTON);
break;
AwtComponent::WmMouseDown开始一系列调用,将java.awt.MouseEvent发布到Java中的EventQueue:
SendMouseEvent(java_awt_event_MouseEvent_MOUSE_PRESSED, now, x, y,
GetJavaModifiers(), clickCount, JNI_FALSE,
GetButton(button), &msg);
活动结束后,我们最终被带回到EDT上可以看到活动的顶端.
内容总结
以上是互联网集市为您收集整理的“GetMessage()”循环的Java Swing对应物在哪里?全部内容,希望文章能够帮你解决“GetMessage()”循环的Java Swing对应物在哪里?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。