分类: Java
2009-05-29 21:24:13
------------------------------------------------
本文系本站原创,欢迎转载!
使用swt/jface开发过的人都知道在swt/jface中,窗体要显示必须要有shell,display,Display用于处理窗口事件等操作,相当于和系统窗体机制通信。而shell可以看成是mainwindow,是所有其他的控件的父窗体。
一个简单的swt/jface程序如下:
package swtjfacesample;
2
3import org.eclipse.swt.SWT;
4import org.eclipse.swt.widgets.Display;
5import org.eclipse.swt.widgets.Shell;
6import org.eclipse.swt.widgets.Text;
7
8public class HelloSwt {
9 /**//**
10 * Hello,world!
11 *
12 * @param args
13 */
14 public static void main(String[] args) {
15 Display display = new Display();
16 Shell shell = new Shell(display);
17
18 Text helloText = new Text(shell, SWT.CENTER);//这个就是shell就可看成是父窗口
19 helloText.setText("Hello,World!");
20 helloText.pack();
21
22 shell.pack();
23 shell.open();
24
25 while (!shell.isDisposed()) {
26 if (!display.readAndDispatch()) {
27 display.sleep();
28 }
29 }
30 display.dispose();
31
32 }
33}
34
首先我们新建一个rcp程序后,新建后,我们可以看到eclipse系统自动生成的代码。
Activator先不管,perspective也不管,这些在plugin程序里也有,我们讲讲rcp特有的,从上面我们可以看出生成了三个文件,同时也是三个类。
既然rcp也是使用swt/jface作为界面的,刚才说了swt/jface需要shell,display,那rcp也肯定有这个。
先看application.java
public class Application implements IApplication {
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
}
这里的start是rcp的开始。估计我们已经注意到display,在最开始就生成,那么现在已经解决一个问题了,只剩下shell了。
由于rcp是一个复杂窗体系统,所以他要以一个比较好的方式组织,一个rcp只有一个workbench,但是可以有多个workbenchwindow,然后布局又是通过perspective来实现,其他的像viewpart,editpart在perspective里布局,然后这些下去才是各种swt控件。看了系统为我们生成的代码,我们都有可能都注意到都有一个advisor后缀,且这些类根本不是继承上面提到类,这是为什么,其实rcp将上面提到的workbench等分成了两部分,一部分是核心部分,也就是rcp,elipse系统设计者写的,这些代码是实现功能,且用户不能修改,如果用户不能定制,没有相关接口那就不好,这时于是就提出一个advisor的概念,即用户可以通过继承这些advisor类来达到添加自己程序的效果,这个就相当于window的hook技术,内核在执行到一定阶段,就会调用制定好的hook,你只要将这些Hook绑定到你的程序,那你的程序就可以在特定阶段执行。
既然workbench是头头,那肯定要创建一个啊,这个就是PlatformUI.createAndRunWorkbench的工作。
public static int createAndRunWorkbench(Display display,
WorkbenchAdvisor advisor) {
return Workbench.createAndRunWorkbench(display, advisor);
}
public static final int createAndRunWorkbench(final Display display,
final WorkbenchAdvisor advisor) {
final int[] returnCode = new int[1];
Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
public void run() {
// create the workbench instance
Workbench workbench = new Workbench(display, advisor);
// run the workbench event loop
returnCode[0] = workbench.runUI();
}
});
return returnCode[0];
}
到这为此,workbench创建了。下面就要初始化这workbench
private int runUI() {
UIStats.start(UIStats.START_WORKBENCH, "Workbench");
boolean avoidDeadlock = true;
Thread initThread = new Thread() {
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
try {
//declare us to be a startup thread so that our syncs will be executed
UISynchronizer.startupThread.set(Boolean.TRUE);
initOK[0] = Workbench.this.init();//这个新增一个线程运行workbench.init函数,这个就和插件机制有关了,初始化完了initok[0]=true,
}
catch (Throwable e) {
error[0] = e;
}
finally {
initDone[0] = true;
display.wake();
}
}};
initThread.start();
while (true) {
if (!display.readAndDispatch()) {
if (initDone[0])
break;
display.sleep();
}
}//等待init完,完了就继续。
Throwable throwable = error[0];
if (throwable != null) {
if (throwable instanceof Error)
throw (Error)throwable;
if (throwable instanceof Exception)
throw (Exception)throwable;
// how very exotic - something that isn't playing by the rules. Wrap it in an error and bail
throw new Error(throwable);
}
}
else {
// initialize workbench and restore or open one window
initOK[0] = init();
}
// drop the splash screen now that a workbench window is up
Platform.endSplash();
// let the advisor run its start up code
if (initOK[0]) {
advisor.postStartup(); // may trigger a close/restart
}
//由于我们实现了advisor的poststartup,所以就执行我们的定制的程序了
if (initOK[0] && runEventLoop) {
// start eager plug-ins
startPlugins();//插件相关的
addStartupRegistryListener();//是和插件系统相关的
// WWinPluginAction.refreshActionList();
display.asyncExec(new Runnable() {
public void run() {
UIStats.end(UIStats.START_WORKBENCH, this, "Workbench"); //$NON-NLS-1$
UIStats.startupComplete();
}
});
getWorkbenchTestable().init(display, this);
// allow ModalContext to spin the event loop
ModalContext.setAllowReadAndDispatch(true);
isStarting = false;
if (synchronizer != null)
synchronizer.started();
// the event loop
runEventLoop(handler, display);//这个和窗体事件处理有关的}
}
…………………………… ………….
// restart or exit based on returnCode
return returnCode;
}
private void runEventLoop(Window.IExceptionHandler handler, Display display) {
runEventLoop = true;
while (runEventLoop) {
try {
if (!display.readAndDispatch()) {
getAdvisor().eventLoopIdle(display);
}
} catch (Throwable t) {
handler.handleException(t);
// In case Display was closed under us
if (display.isDisposed())
runEventLoop = false;
}
}
}//
上面这个就是执行消息处理。
刚才说了workbench的初始化是在workbench的init函数中,下面就来看下。
private boolean init() {
// setup debug mode if required.
// create workbench window manager
windowManager = new WindowManager();
//workbench是管理workbenchwindow的,windowmanger就是这个结构
IIntroRegistry introRegistry = WorkbenchPlugin.getDefault()
initializeDefaultServices();
initializeFonts();
initializeColors();
initializeApplicationColors();
//这些就是初始化字体,颜色等相关资源
StartupThreading.runWithoutExceptions(new StartupRunnable() {
public void runWithException() {
advisor.internalBasicInitialize(getWorkbenchConfigurer());
// getWorkbenchConfigurer为workbench创建了一个configure,并付给其成员
}
}
final boolean bail [] = new boolean[1];
StartupThreading.runWithoutExceptions(new StartupRunnable() {
public void runWithException() throws Throwable {
advisor.preStartup();
if (!advisor.openWindows()) {
bail[0] = true;
}
}});
);
public final void internalBasicInitialize(IWorkbenchConfigurer configurer) {
if (workbenchConfigurer != null) {
throw new IllegalStateException();
}
this.workbenchConfigurer = configurer;
initialize(configurer);//我们可以重载这个函数,加自己的
}
这个函数给workbenchadvisor附configure变量。
然后是openwindows函数,这个函数非常重要。
在workbenchadvisor里
public boolean openWindows() {
final Display display = PlatformUI.getWorkbench().getDisplay();
final boolean result [] = new boolean[1];
public void runWithException() throws Throwable {
myConfigurer[0] = getWorkbenchConfigurer();
//这个是internalBasicInitialize赋值的
}});
if (!status.isOK()) {
if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_EXIT) {
result[0] = false;
return;
}
if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_RESET) {
myConfigurer[0].openFirstTimeWindow();//这个将会生成workbenchwindow东西
}
}
result[0] = true;
}
public void openFirstTimeWindow() {
((Workbench) getWorkbench()).openFirstTimeWindow();
}
其实就是调用workbench的openfirsttimewindow
void openFirstTimeWindow() {
runStartupWithProgress(expectedProgressCount, new Runnable() {
public void run() {
doOpenFirstTimeWindow();
}
});
}
}
private void doOpenFirstTimeWindow() {
try {
final IAdaptable input [] = new IAdaptable[1];
StartupThreading.runWithoutExceptions(new StartupRunnable() {
public void runWithException() throws Throwable {
input[0] = getDefaultPageInput();
}});
busyOpenWorkbenchWindow(getPerspectiveRegistry()
.getDefaultPerspective(), input[0]);
} catch (final WorkbenchException e) {
// Don't use the window's shell as the dialog parent,
// as the window is not open yet (bug 76724).
}
}
busyOpenWorkbenchWindow才是真正开始创建workbenchwindow
private IWorkbenchWindow busyOpenWorkbenchWindow (final String perspID,
final IAdaptable input) throws WorkbenchException {
// Create a workbench window (becomes active window)
final WorkbenchWindow newWindowArray[] = new WorkbenchWindow[1];
StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {
public void runWithException() {
newWindowArray[0] = newWorkbenchWindow();
}
});
final WorkbenchWindow newWindow = newWindowArray[0];
StartupThreading.runWithoutExceptions(new StartupRunnable() {
public void runWithException() {
newWindow.create(); // 这个创建shell即顶级窗口
}
});
windowManager.add(newWindow);
StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {
public void runWithException() {
newWindow.open();
}
});
return newWindow;
}