“GetMessage()”循环的Java Swing对应物在哪里?
几年前我做了一些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系统,它位于 事件调度系统相当分散,因此我将通过一个特定的例子来假设已经点击了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 如果我们看一下 public void run() { try { pumpEvents(...); } finally { ... } }
void pumpEventsForFilter(...) { ... while(doDispatch && ...) { pumpOneEventForFilters(...); } ... } 然后将一个事件从队列中拉出并在 void pumpOneEventForFilters(...) { AWTEvent event = null; ... try { ... EventQueue eq = getEventQueue(); ... event = eq.getNextEvent(); ... eq.dispatchEvent(event); ... } catch(...) { ... } ... }
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 { ... } 我们熟悉的大多数事件都要经过组件路径.
/** * 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内部有一个处理程序.例如,我们可以看看 BasicButtonListener使用鼠标事件来更改按钮模型的按下状态.最后,按钮模型确定它是否在 原生消息 如何实现实际的本机窗口当然是特定于平台的,但我可以稍微浏览一下Windows平台,因为它就是你所问的内容.您将在以下目录中找到Windows平台的内容: > Java: java.awt.Toolkit的Windows实现,即 /* * eventLoop() begins the native message pump which retrieves and processes * native events. * ... 这将我们引向位于 native implementation of AwtToolkit::GetInstance().MessageLoop(AwtToolkit::PrimaryIdleFunc,AwtToolkit::CommonPeekMessageFunc); ( 这是外环所在的位置: UINT AwtToolkit::MessageLoop(IDLEPROC lpIdleFunc,PEEKMESSAGEPROC lpPeekMessageFunc) { ... m_messageLoopResult = 0; while (!m_breakMessageLoop) { (*lpIdleFunc)(); PumpWaitingMessages(lpPeekMessageFunc); /* pumps waiting messages */ ... } ... }
/* * 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称之为 本机窗口由一个C对象包装,该对象具有特定于平台的内容,以及我们在Java代码中使用的一些API的松散并行. 似乎有一些WindowProc功能.其中一个仅由工具包 我们实际感兴趣的WindowProc函数是 case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: mr = WmMouseDown(static_cast<UINT>(wParam),myPos.x,myPos.y,LEFT_BUTTON); break;
SendMouseEvent(java_awt_event_MouseEvent_MOUSE_PRESSED,now,x,y,GetJavaModifiers(),clickCount,JNI_FALSE,GetButton(button),&msg); 活动结束后,我们最终被带回到EDT上可以看到活动的顶端. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |