第一篇文章中,有一个问题我没有解释,在Display中的runDeferedEvents方法中:
boolean runDeferredEvents () {
boolean run = false;
/*
* Run deferred events. This code is always
* called in the Display's thread so it must
* be re-enterant but need not be synchronized.
*/
while (eventQueue != null) {
/* Take an event off the queue */
Event event = eventQueue [0];
if (event == null) break;
int length = eventQueue.length;
System.arraycopy (eventQueue, 1, eventQueue, 0, --length);
eventQueue [length] = null;
/* Run the event */
Widget widget = event.widget;
if (widget != null && !widget.isDisposed ()) {
Widget item = event.item;
if (item == null || !item.isDisposed ()) {
run = true;
widget.sendEvent (event);
}
}
/*
* At this point, the event queue could
* be null due to a recursive invocation
* when running the event.
*/
}
/* Clear the queue */
eventQueue = null;
return run;
}
事件event是从eventQueue中取出来的,eventQueue是Display中的一个Event数组:
Event [] eventQueue;
我自然就会想到,系统中的各种事件,是怎么放入这个eventQueue中的呢?
继续从上文的按钮程序入手,现在监听按钮1的鼠标按下事件:
package com.edgar;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
class TestMultButton {
public static void main(String[] args) {
Display display = new Display();// 创建一个display对象。
final Shell shell = new Shell(display);// shell是程序的主窗体
shell.setText("Java应用程序"); // 设置主窗体的标题
shell.setSize(300, 300); // 设置主窗体的大小
Button b1 = new Button(shell,SWT.NONE);
b1.setText("按钮1");
b1.setBounds(100,50, 100, 50);
Button b2 = new Button(shell,SWT.NONE);
b2.setText("按钮2");
b2.setBounds(100,150, 100, 50);
b1.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mousedown");
}
});
shell.open(); // 打开主窗体
while (!shell.isDisposed()) { // 如果主窗体没有关闭则一直循环
if (!display.readAndDispatch()) { // 如果display不忙
display.sleep(); // 休眠
}
}
display.dispose(); // 销毁display
}
}
我在System.out.println("mousedown");这行代码加上断点,然后运行程序,然后点击按钮一,程序暂停,运行上下文如下:
程序执行的流程和分析一中的一样,我们并没有看到上下文中看到windowProc,这是“意料之中”的,因为我们在利用SWT这个GUI类库编程,几乎搜有GUI类库都会对消息循环,窗口过程函数进行封装,让我们能以OO的方式来编程。现在为了知道SWT是怎么进行封装的,我找到Control类中的 windowProc 方法:
int /*long*/ windowProc (int /*long*/ hwnd, int msg, int /*long*/ wParam, int /*long*/ lParam) {
LRESULT result = null;
switch (msg) {
......
case OS.WM_KILLFOCUS: result = WM_KILLFOCUS (wParam, lParam); break;
case OS.WM_LBUTTONDBLCLK: result = WM_LBUTTONDBLCLK (wParam, lParam); break;
case OS.WM_LBUTTONDOWN: result = WM_LBUTTONDOWN (wParam, lParam); break;
case OS.WM_LBUTTONUP: result = WM_LBUTTONUP (wParam, lParam); break;
......
}
if (result != null) return result.value;
return callWindowProc (hwnd, msg, wParam, lParam);
}
对应左键点击按钮来说,windowProc中会接收到WM_LBUTTONDOWN消息,然后会调用WM_LBUTTONDOWN(wParam,lParam)函数,所以我在WM_LBUTTONDOWN函数加一个断点:
运行程序,点击按钮一后,程序果然停在return wmLButtonDown (handle, wParam, lParam);这行!
现在我们就进入wmLButtonDown(handle,wParam,lParam)方法里面,看看都有什么操作:
LRESULT wmLButtonDown (int /*long*/ hwnd, int /*long*/ wParam, int /*long*/ lParam) {
Display display = this.display;
LRESULT result = null;
int x = OS.GET_X_LPARAM (lParam);
int y = OS.GET_Y_LPARAM (lParam);
boolean [] consume = null, detect = null;
boolean dragging = false, mouseDown = true;
int count = display.getClickCount (SWT.MouseDown, 1, hwnd, lParam);
if (count == 1 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
if (!OS.IsWinCE) {
/*
* Feature in Windows. It's possible that the drag
* operation will not be started while the mouse is
* down, meaning that the mouse should be captured.
* This can happen when the user types the ESC key
* to cancel the drag. The fix is to query the state
* of the mouse and capture the mouse accordingly.
*/
detect = new boolean [1];
consume = new boolean [1];
dragging = dragDetect (hwnd, x, y, true, detect, consume);
if (isDisposed ()) return LRESULT.ZERO;
mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0;
}
}
display.captureChanged = false;
boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
if (dispatch && (consume == null || !consume [0])) {
result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDOWN, wParam, lParam));
} else {
result = LRESULT.ZERO;
}
if (OS.IsPPC) {
/*
* Note: On WinCE PPC, only attempt to recognize the gesture for
* a context menu when the control contains a valid menu or there
* are listeners for the MenuDetect event.
*/
Menu menu = getMenu ();
boolean hasMenu = menu != null && !menu.isDisposed ();
if (hasMenu || hooks (SWT.MenuDetect)) {
SHRGINFO shrg = new SHRGINFO ();
shrg.cbSize = SHRGINFO.sizeof;
shrg.hwndClient = hwnd;
shrg.ptDown_x = x;
shrg.ptDown_y = y;
shrg.dwFlags = OS.SHRG_RETURNCMD;
int type = OS.SHRecognizeGesture (shrg);
if (type == OS.GN_CONTEXTMENU) showMenu (x, y);
}
}
if (mouseDown) {
if (!display.captureChanged && !isDisposed ()) {
if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
}
}
if (dragging) {
sendDragEvent (1, x, y);
} else {
if (detect != null && detect [0]) {
/*
* Feature in Windows. DragDetect() captures the mouse
* and tracks its movement until the user releases the
* left mouse button, presses the ESC key, or moves the
* mouse outside the drag rectangle. If the user moves
* the mouse outside of the drag rectangle, DragDetect()
* returns true and a drag and drop operation can be
* started. When the left mouse button is released or
* the ESC key is pressed, these events are consumed by
* DragDetect() so that application code that matches
* mouse down/up pairs or looks for the ESC key will not
* function properly. The fix is to send the missing
* events when the drag has not started.
*
* NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
* events for the ESC key. This would require computing
* wParam (the key) and lParam (the repeat count, scan code,
* extended-key flag, context code, previous key-state flag,
* and transition-state flag) which is non-trivial.
*/
if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
OS.SendMessage (hwnd, OS.WM_LBUTTONUP, wParam, lParam);
}
}
}
return result;
}
方法有点长,但是真正执行的地方并不长。一开始得到点击事件的x坐标和y坐标,然后得到点击的次数,然后调用sendMouseEvent方法:
boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
看方法的名字是“发送鼠标事件”进入该方法:
boolean sendMouseEvent (int type, int button, int count, int detail, boolean send, int /*long*/ hwnd, int msg, int /*long*/ wParam, int /*long*/ lParam) {
if (!hooks (type) && !filters (type)) return true;
Event event = new Event ();
event.button = button;
event.detail = detail;
event.count = count;
event.x = OS.GET_X_LPARAM (lParam);
event.y = OS.GET_Y_LPARAM (lParam);
setInputState (event, type);
mapEvent (hwnd, event);
if (send) {
sendEvent (type, event);
if (isDisposed ()) return false;
} else {
postEvent (type, event);
}
return event.doit;
}
我们看到方法里面将系统的消息 “转换”成了SWT自己的事件对象。给event对象的属性赋值之后,因为send的值是false(看调用的代码和形参对应起来!),所以调用postEvent(type,event)方法:
void postEvent (int eventType, Event event) {
sendEvent (eventType, event, false);
}
又调用了sendEvent方法:
void sendEvent (int eventType, Event event, boolean send) {
if (eventTable == null && !display.filters (eventType)) {
return;
}
if (event == null) event = new Event ();
event.type = eventType;
event.display = display;
event.widget = this;
if (event.time == 0) {
event.time = display.getLastEventTime ();
}
if (send) {
sendEvent (event);
} else {
display.postEvent (event);
}
}
给属性赋值之后,因为send是false,继续调用display.postEvent(event):
void postEvent (Event event) {
/*
* Place the event at the end of the event queue.
* This code is always called in the Display's
* thread so it must be re-enterant but does not
* need to be synchronized.
*/
if (eventQueue == null) eventQueue = new Event [4];
int index = 0;
int length = eventQueue.length;
while (index < length) {
if (eventQueue [index] == null) break;
index++;
}
if (index == length) {
Event [] newQueue = new Event [length + 4];
System.arraycopy (eventQueue, 0, newQueue, 0, length);
eventQueue = newQueue;
}
eventQueue [index] = event;
}
postEvent方法,正是把此时的事件event存入了eventQueue。好了,文章一遗留的问题解决了。
- 大小: 12.1 KB
- 大小: 7.3 KB
分享到:
相关推荐
SWT源码的获取和分析对于开发者来说非常有价值,因为它可以深入理解其工作原理,自定义组件或优化应用程序。 "swt.jar"文件是SWT库的二进制版本,包含了运行SWT应用所需的类和资源。这个jar包通常会被Java项目引用...
《图书馆管理系统SWT源码详解》 在信息技术领域,开发高效、用户友好的管理软件是提升工作效率的关键。本文将深入探讨一个特别的案例——“图书馆管理系统”,该系统采用SWT(Standard Widget Toolkit)进行设计,...
**源码分析** SWT 的源码是用Java编写的,通过JNI(Java Native Interface)与操作系统底层交互。通过阅读源码,开发者可以深入理解SWT的工作原理,学习如何与本地系统进行通信,以及如何优化GUI性能。源码中包含了...
5. **源码分析与使用**: 源码中可能包含了如何初始化和控制SWT_Browser实例,如何加载和导航网页,以及如何处理JavaScript与Java之间的交互的示例代码。开发者可以通过学习和理解这些源码,了解如何在自己的项目中...
源代码对于学习和理解SWT和JFace的工作原理极其有用,开发者可以通过阅读源码学习如何使用这些库,或者进行二次开发。 6. `about_files`:这个目录可能包含了Eclipse关于对话框显示的其他资源文件,如图标、语言...
通过分析这些源代码,开发者可以了解SWT如何与操作系统进行底层交互,实现高效、原生的GUI效果。这对于希望优化SWT性能、定制特定功能或者学习GUI编程原理的开发者来说,是非常宝贵的资料。如果你对SWT感兴趣,那么...
Kettle 4.4.2源码分析 Kettle 是一款功能强大且流行的数据 Integrator 工具,它提供了多种数据处理和Integration 功能。本文档将对 Kettle 4.4.2 的源码进行分析,从源码获取和编译到修改 Kettle 界面和启动测试等...
Java SWT(Standard Widget Toolkit)是Java编程环境中...通过学习和分析这个源码,你可以深入理解Java SWT的用法,以及如何结合算法实现一个完整的桌面应用程序。此外,对于游戏设计和用户交互也有一定的学习价值。
掌握它们的使用和源码分析能力,对于提升 Java GUI 开发技能和参与 Eclipse RCP 应用的开发具有重要意义。通过深入研究提供的源码,开发者可以更好地优化自己的代码,实现更加高效和用户友好的界面。
5. **源码分析**:在提供的压缩包中,`com.cxd.zxsj`、`com.cxd.zxsj.feature`和`com.cxd.zxsj.update`可能分别代表了项目的主代码包、功能描述文件和更新相关配置。`com.cxd.zxsj`可能是应用程序的主要代码结构,...
通过分析这些源码,开发者可以学习到如何实际应用 SWT 和 JFace 创建高效、美观的 GUI 应用。例如,Chapter09可能介绍了布局管理,包括如何使用GridLayout、FillLayout等;Chapter13可能涉及事件处理和监听器;...
首先,我们来分析给定的文件列表: 1. `otree.css`: 这个文件是CSS样式表,用于定义SWT Tree的外观和布局,如字体、颜色、边框等。在创建树形结构时,可以利用CSS定制节点的样式,使其更具视觉吸引力。 2. `otree....
源码分析** 对于SWT的深入学习,阅读源码是一个有效的途径。了解SWT如何与操作系统进行交互,以及如何实现各种控件和功能,可以帮助开发者更好地优化应用性能,解决特定问题。 在实际项目中,SWT常用于开发桌面...
7. **源码阅读**:了解SWT源码有助于深入理解其工作机制,解决性能问题或自定义组件。 8. **开发工具**:Eclipse是主要的SWT开发环境,提供代码补全、调试、布局编辑等功能。除此之外,还有SWTBot用于自动化测试,...
博客链接中的内容可能涉及对SWT源码的分析。SWT作为一个开源项目,其源码对于开发者来说是一个宝贵的资源,可以深入理解其内部工作机制,学习如何与操作系统进行交互,以及如何优化GUI性能。通过阅读源码,开发者...
Kettle4.1 是该工具的一个版本,其源码分析有助于深入理解其内部工作原理,便于自定义开发或优化。 在开始源码分析之前,首先需要获取和编译 Kettle4.1 的源码。这可以通过 SVN 从官方仓库中下载,网址为 svn://...
通过分析和运行这些代码,你可以深入理解SWT的API和组件使用方式,以及如何将它们整合到Java应用程序中。 SWT提供了一系列的控件,包括按钮、文本框、列表、树、表格等,这些都可以用来构建各种复杂的用户界面。...
JAVA SWT 多标签浏览器是一种利用Java编程语言和SWT(Standard Widget Toolkit)库构建...通过分析源码,开发者可以学习到如何利用SWT创建原生外观的应用,以及如何实现复杂的用户交互功能,比如多标签导航和书签管理。
标题中的“以SWT为界面,用POI读取、修改excel文件(源码)”指的是一个Java编程项目,它利用了两种主要的技术:SWT(Standard Widget Toolkit)和Apache POI,来创建用户界面并处理Microsoft Excel文件。下面将详细...