zoukankan      html  css  js  c++  java
  • GEF入门实例_总结_04_Eclipse插件启动流程分析

    一、前言

    本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏

    注意到app目录下的6个类文件。

    这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们将通过这几个文件来了解Eclipse插件的启动过程。

    二、Eclipse工作台层次结构

    1.Eclipse工作台示例

    (1)运行Eclipse之后,出现下图所示界面,其中顶层窗口就是Eclipse的工作台窗口

    (2)每个工作台窗口又包括菜单栏、工具栏、状态栏 和 多个工作台页面

    (3)每个工作台页面又包含多个视图、编辑器

    顶层窗口就是Eclipse的工作台窗口

    三、6个类文件的作用

     这六个类文件的作用如下:

    序号 类名 作用
    1 Application RCP应用程序的入口
    2 ApplicationWorkbenchAdvisor 负责应用程序生命周期管理
    3 ApplicationWorkbenchWindowAdvisor 负责窗口生命周期管理。控制窗口界面的UI元素
    4 ApplicationActionBarAdvisor 负责定义创建窗口的行为。 负责创建菜单栏、工具栏、状态行
    5 Perspective 默认透视图,负责界面布局的安排
    6 Activator 控制插件的生命周期

     

    1.Application

    package gef.tutorial.step.app;
    
    import org.eclipse.equinox.app.IApplication;
    import org.eclipse.equinox.app.IApplicationContext;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.ui.IWorkbench;
    import org.eclipse.ui.PlatformUI;
    
    /**
     * This class controls all aspects of the application's execution
     */
    public class Application implements IApplication {
    
        @Override
        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();
            }
            
        }
    
        @Override
        public void stop() {
            if (!PlatformUI.isWorkbenchRunning())
                return;
            final IWorkbench workbench = PlatformUI.getWorkbench();
            final Display display = workbench.getDisplay();
            display.syncExec(new Runnable() {
                public void run() {
                    if (!display.isDisposed())
                        workbench.close();
                }
            });
        }
    }
    View Code

    (1)Application类是RCP程序的入口,它实现了IApplication接口,在RCP程序启动时会执行该接口的start方法。

    (2)事件循环:工作台启动之后,会处于持续打开状态。这时,应用程序开始处理用户的鼠标单击、移动、按键等各种事件,一直到用户关闭程序退出,这就是所谓的事件循环。

    2.ApplicationWorkbenchAdvisor

    package gef.tutorial.step.app;
    
    import org.eclipse.ui.application.IWorkbenchConfigurer;
    import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
    import org.eclipse.ui.application.WorkbenchAdvisor;
    import org.eclipse.ui.application.WorkbenchWindowAdvisor;
    
    public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
    
        private static final String PERSPECTIVE_ID = "gef.tutorial.step.perspective"; //$NON-NLS-1$
    
        @Override
        public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
            return new ApplicationWorkbenchWindowAdvisor(configurer);
        }
        
        
        /**1.在工作台开始运行之前执行初始化操作。
         *   在打开任何窗口之前,在工作台初始化期间调用此方法。
         * 
         */
        @Override
        public void initialize(IWorkbenchConfigurer configurer) {
            
            super.initialize(configurer);
            
            //1.1 设置应用程序每次退出时保存当前窗口状态
            configurer.setSaveAndRestore(true);
        }
    
    
    
        /**
         * 2.指定工作台的初始透视图
         */
        @Override
        public String getInitialWindowPerspectiveId() {
            return PERSPECTIVE_ID;
        }
    }
    View Code

    (1)负责应用程序生命周期管理。

    (2)可以在该类中实现程序启动或关闭时的某种处理

    (3)主要方法

    序号 方法名 生命周期 用法
    1 initialize 最先调用。在工作台开始运行之前执行一些初始化操作。 可用来处理初始化配置操作
    2 preStartup initialize之后、第一个窗口打开之前调用 可以用来处理临时或者可选处理操作
    3 postStartup 第一个窗口打开之后但启动事件循环之前调用 可以用来进行那些需要自动处理的动作
    4 preShutdown 事件循环结束之后但工作台关闭之前调用 可以用来进行保存数据、关闭数据库服务器等操作
    5 postShutdown 工作台关闭之后调用 可以用来进行保存应用程序

    3.ApplicationWorkbenchWindowAdvisor

    package gef.tutorial.step.app;
    
    import org.eclipse.swt.graphics.Point;
    import org.eclipse.ui.application.ActionBarAdvisor;
    import org.eclipse.ui.application.IActionBarConfigurer;
    import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
    import org.eclipse.ui.application.WorkbenchWindowAdvisor;
    
    public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
    
        public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
            super(configurer);
        }
        
        /**
         * 1.创建一个新的action bar advisor
         *      指定由ApplicationActionBarAdvisor来配置窗口的操作条。
         */
        @Override
        public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
            return new ApplicationActionBarAdvisor(configurer);
        }
        
        
        /**
         * 2.在窗口打开之前执行
         */
        @Override
        public void preWindowOpen() {
            IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
            //1.设置窗口初始化大小
            configurer.setInitialSize(new Point(700, 550));
            
            //2.显示工具栏
            configurer.setShowCoolBar(true);
            
            //3.不显示状态栏
            configurer.setShowStatusLine(false);
            
            //4.设置窗口标题
            configurer.setTitle("GEF入门实例"); //$NON-NLS-1$
        }
    }
    View Code

    (1)负责应用程序窗口生命周期管理。

    (2)该类扩展自WorkbenchWindowAdvisor。每个应用程序都需要一个WorkbenchWindowAdvisor 来控制窗口界面的UI元素。

             开发人员可以控制窗口创建时(或其他生命周期时)的大小、标题、位置等。

    (3)主要方法

    序号 方法名 生命周期 用法
    1 preWindowOpen 窗口控件创建之前调用 可用于设置窗口的初始大小、状态栏、工具栏等的可视性
    2 postWindowRestore 当窗口根据上一次的保存状态恢复创建之后调用 可用于调整窗口的恢复状态
    3 postWindowCreate 窗口创建之后调用 可用于调整窗口
    4 postWindowOpen 窗口已经打开之后调用 可用于注册窗口监听,例如在此方法中实现系统托盘

    4.ApplicationActionBarAdvisor

    package gef.tutorial.step.app;
    
    import org.eclipse.jface.action.ICoolBarManager;
    import org.eclipse.jface.action.IMenuManager;
    import org.eclipse.jface.action.MenuManager;
    import org.eclipse.jface.action.Separator;
    import org.eclipse.jface.action.ToolBarManager;
    import org.eclipse.swt.SWT;
    import org.eclipse.ui.IWorkbenchWindow;
    import org.eclipse.ui.actions.ActionFactory;
    import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
    import org.eclipse.ui.application.ActionBarAdvisor;
    import org.eclipse.ui.application.IActionBarConfigurer;
    
    import gef.tutorial.step.action.DiagramAction;
    
    public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
    
        
        private IWorkbenchAction exitAction;
        private IWorkbenchAction aboutAction;
        private DiagramAction diagramAction;
        
        
        public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
            super(configurer);
        }
    
        
        /**
         * 1.注册菜单或者工具栏的Action。Action只有注册后才能添加到菜单中。
         * 
         */
        @Override
        protected void makeActions(IWorkbenchWindow window) {
            //退出
            exitAction = ActionFactory.QUIT.create(window);
            register(exitAction);
            
            //关于
            aboutAction = ActionFactory.ABOUT.create(window);
            register(aboutAction);
            
            //绘图
            diagramAction = new DiagramAction(window);
            register(diagramAction);
    
        }
    
        
    
        /**
         * 2.填充菜单栏。用Action来填充菜单
         * 
         *  (1) 菜单管理器负责管理菜单项、设置菜单行为、创建级联菜单或者对菜单项进行分组。
         *  (2) MenuManager构造函数:菜单项文本、菜单项ID
         *  (3) new Separator() 为一条分割线
         */
        @Override
        protected void fillMenuBar(IMenuManager menuBar) {
            //(1)一级菜单  File
            MenuManager fileMenuManager= new MenuManager("File", "fileMenuManager");
            //加入绘图动作,是叶子节点菜单,也是二级菜单。点击之后将执行Action的run方法
            fileMenuManager.add(diagramAction);
            //加入分隔符
            fileMenuManager.add(new Separator());
            //加入退出动作
            fileMenuManager.add(exitAction);
            
            //(2)一级菜单  Help
            MenuManager helpMenuManager = new MenuManager("Help", "helpMenuManager");
            helpMenuManager.add(aboutAction);
            //加入二级菜单
            helpMenuManager.add(fileMenuManager);
            
            //(3)将菜单加入菜单栏
            menuBar.add(fileMenuManager);
            menuBar.add(helpMenuManager);
    
        }
        
        
    
    
        /**
         * 3.填充工具栏。用Action来填充工具栏
         * (1) 工具栏默认是不显示。在 ApplicationWorkbenchWindowAdvisor 类中的
         *  preWindowOpen方法中有一句 configurer.setShowCoolBar(false);将false改为true即可显示工具栏
         * (2) 工具栏管理器负责工具栏的分类管理
         * (3) SWT.FLAT将工具栏设置成平滑方式,SWT.SHADOW_OUT用于在工具栏和菜单栏之间加一条分割线
         * 
         */
        @Override
        protected void fillCoolBar(ICoolBarManager coolBar) {
            //1.生成工具栏
            ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT | SWT.SHADOW_OUT);
            
            //2.将工具放入工具栏
            toolBarManager.add(diagramAction);
            
            
            //3.将工具栏放入 
            coolBar.add(toolBarManager);
        }
    
        
    }
    View Code

    (1)负责定义创建窗口的行为。

    (2)该类扩展自ActionBarAdvisor,用于创建菜单栏、工具栏、状态行

    (3)主要方法

    序号 方法名 用法
    1 makeActions 注册菜单或者工具栏的工作
    2 fillMenuBar 添加菜单栏
    3 fillCoolBar 添加工具栏
    4 fillStatusLine 添加状态栏

    5.Perspective

    package gef.tutorial.step.app;
    
    import org.eclipse.ui.IFolderLayout;
    import org.eclipse.ui.IPageLayout;
    import org.eclipse.ui.IPerspectiveFactory;
    
    public class Perspective implements IPerspectiveFactory {
    
        public void createInitialLayout(IPageLayout layout) {
            //一、基本配置
            //1.1 获取布局的编辑器
            final String editorArea = layout.getEditorArea();
            //1.2 设置显示编辑区
            layout.setEditorAreaVisible(true);
            
            //二、添加各种视图
            //2.1 添加属性视图
            IFolderLayout bottomFolder = layout.createFolder("bottom",IPageLayout.BOTTOM, 0.75f, editorArea);
            bottomFolder.addView(IPageLayout.ID_PROP_SHEET);
            
            //2.2 添加大纲视图
            IFolderLayout rightBottomFolder = layout.createFolder("right",IPageLayout.RIGHT, 0.75f, editorArea);
            rightBottomFolder.addView(IPageLayout.ID_OUTLINE);
            
            
        }
    }
    View Code

    (1)是程序默认的透视图

    (2)负责初始页面布局并显示

    (3)主要方法

    方法名 用法
    createInitialLayout

    创建页面的初始布局。此方法的实现人员可以向透视图添加其他视图。

    6.Activator

    package gef.tutorial.step.app;
    
    import org.eclipse.jface.resource.ImageDescriptor;
    import org.eclipse.ui.plugin.AbstractUIPlugin;
    import org.osgi.framework.BundleContext;
    
    /**
     * The activator class controls the plug-in life cycle
     */
    public class Activator extends AbstractUIPlugin {
    
        // The plug-in ID
        public static final String PLUGIN_ID = "gef.tutorial.step"; //$NON-NLS-1$
    
        // The shared instance
        private static Activator plugin;
        
        /**
         * The constructor
         */
        public Activator() {
        }
    
        /*
         * (non-Javadoc)
         * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
         */
        public void start(BundleContext context) throws Exception {
            super.start(context);
            plugin = this;
        }
    
        /*
         * (non-Javadoc)
         * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
         */
        public void stop(BundleContext context) throws Exception {
            plugin = null;
            super.stop(context);
        }
    
        /**
         * Returns the shared instance
         *
         * @return the shared instance
         */
        public static Activator getDefault() {
            return plugin;
        }
    
        /**
         * Returns an image descriptor for the image file at the given
         * plug-in relative path
         *
         * @param path the path
         * @return the image descriptor
         */
        public static ImageDescriptor getImageDescriptor(String path) {
            return imageDescriptorFromPlugin(PLUGIN_ID, path);
        }
    }
    View Code

    (1)是插件类,控制插件的生命周期

    (2)见第二节: GEF入门实例_总结_02_新建初始RCP空项目   ,如下图,

             若2处勾选 "This plug-in will make contributions to the UI",表示插件对UI进行添加,则此类将扩展自AbstractUIPlugin。

             否则,该类扩展自 AbstractUIPlugin 的父类 Plugin。

    (3)主要方法

    序号 方法名 作用
    1 start 插件启动时的处理
    2 stop 插件停止时的处理
    3 getDefault 获取默认的插件类实例。单例模式。
    4 getImageDescriptor 根据插件相对路径返回图片描述符,可用于获取图片

    四、Eclipse插件启动流程图

    有问题的地方:第9步的实际的具体流程我暂时还不清楚。

     Eclipse启动流程图如下,都是自己总结的,所以可能有不当之处,希望读者能解惑并将其完善。

     温馨提示:可将下图拖入浏览器中查看原图

    五、Eclipse插件启动流程分析

     以下流程与上述流程图步骤对应,通过进行断点调试,可发现启动流程如下:

    0.run

    首先是运行插件,可参见: GEF入门实例_总结_02_新建初始RCP空项目  的 “三、启动项目” 部分。

    (1)其中注意上图:run  an  application  ,这里主要是设置程序的入口,这里我们选择的是 “gef.tutorial.step.application”,含义为(插件ID).(扩展点 runtime.applications 的ID)。

    (2)打开plugin.xml,在overview页,可以看到插件id为gef.tutorial.step

    (3)在 Extensions 页,可以看到扩展点“org.eclipse.core.runtime.applications”的 ID 为 application。

     

    (4)至此,我们知道插件启动时,执行这个扩展点,那为啥会执行到Application类中去呢?如下图:

    1.插件启动

     Application.start

    如上所述,因为Run Configuration  中 run an application 配置的入口程序为 Application 类,因此程序启动时,会执行到 Application 的 start 方法中来。

        int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());

    然后由此处代码创建一个 ApplicationWorkbenchAdvisor ,并进行到第二步

    2.获取工作台窗口初始透视标识

    ApplicationWorkbenchAdvisor.getInitialWindowPerspectiveId

    /**
         * 2.指定工作台的初始透视图
         */
        @Override
        public String getInitialWindowPerspectiveId() {
            return PERSPECTIVE_ID;
        }

    3.创建workbench window advisor 

    ApplicationWorkbenchAdvisor.createWorkbenchWindowAdvisor

    @Override
        public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
            return new ApplicationWorkbenchWindowAdvisor(configurer);
        }

    在这一步去创建了  ApplicationWorkbenchWindowAdvisor  ,通过这个Advisor 可以配置工作台窗口。

    4.窗口打开前的处理

    ApplicationWorkbenchWindowAdvisor.preWindowOpen

    /**
         * 2.在窗口打开之前执行
         */
        @Override
        public void preWindowOpen() {
            IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
            //1.设置窗口初始化大小
            configurer.setInitialSize(new Point(700, 550));
            
            //2.显示工具栏
            configurer.setShowCoolBar(true);
            
            //3.不显示状态栏
            configurer.setShowStatusLine(false);
            
            //4.设置窗口标题
            configurer.setTitle("GEF入门实例"); //$NON-NLS-1$
        }
    View Code

    在窗口打开前,设置了窗口大小、标题、工具栏与状态栏的可视性

    5.创建 ActionBarAdvisor

    ApplicationWorkbenchWindowAdvisor.createActionBarAdvisor

        /**
         * 1.创建一个新的action bar advisor
         *      指定由ApplicationActionBarAdvisor来配置窗口的操作条。
         */
        @Override
        public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
            return new ApplicationActionBarAdvisor(configurer);
        }

    6.注册菜单或者工具栏的Action

    ApplicationActionBarAdvisor.makeActions

        /**
         * 1.注册菜单或者工具栏的Action。Action只有注册后才能添加到菜单中。
         * 
         */
        @Override
        protected void makeActions(IWorkbenchWindow window) {
            //退出
            exitAction = ActionFactory.QUIT.create(window);
            register(exitAction);
            
            //关于
            aboutAction = ActionFactory.ABOUT.create(window);
            register(aboutAction);
            
            //绘图
            diagramAction = new DiagramAction(window);
            register(diagramAction);
    
        }
    View Code

    7.填充菜单栏

     ApplicationActionBarAdvisor.fillMenuBar

        /**
         * 2.填充菜单栏。用Action来填充菜单
         * 
         *  (1) 菜单管理器负责管理菜单项、设置菜单行为、创建级联菜单或者对菜单项进行分组。
         *  (2) MenuManager构造函数:菜单项文本、菜单项ID
         *  (3) new Separator() 为一条分割线
         */
        @Override
        protected void fillMenuBar(IMenuManager menuBar) {
            //(1)一级菜单  File
            MenuManager fileMenuManager= new MenuManager("File", "fileMenuManager");
            //加入绘图动作,是叶子节点菜单,也是二级菜单。点击之后将执行Action的run方法
            fileMenuManager.add(diagramAction);
            //加入分隔符
            fileMenuManager.add(new Separator());
            //加入退出动作
            fileMenuManager.add(exitAction);
            
            //(2)一级菜单  Help
            MenuManager helpMenuManager = new MenuManager("Help", "helpMenuManager");
            helpMenuManager.add(aboutAction);
            //加入二级菜单
            helpMenuManager.add(fileMenuManager);
            
            //(3)将菜单加入菜单栏
            menuBar.add(fileMenuManager);
            menuBar.add(helpMenuManager);
    
        }
        
    View Code

    8.填充工具栏

     ApplicationActionBarAdvisor.fillCoolBar

    /**
         * 3.填充工具栏。用Action来填充工具栏
         * (1) 工具栏默认是不显示。在 ApplicationWorkbenchWindowAdvisor 类中的
         *  preWindowOpen方法中有一句 configurer.setShowCoolBar(false);将false改为true即可显示工具栏
         * (2) 工具栏管理器负责工具栏的分类管理
         * (3) SWT.FLAT将工具栏设置成平滑方式,SWT.SHADOW_OUT用于在工具栏和菜单栏之间加一条分割线
         * 
         */
        @Override
        protected void fillCoolBar(ICoolBarManager coolBar) {
            //1.生成工具栏
            ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT | SWT.SHADOW_OUT);
            
            //2.将工具放入工具栏
            toolBarManager.add(diagramAction);
            
            
            //3.将工具栏放入 
            coolBar.add(toolBarManager);
        }
    View Code

    9.getInitialWindowPerspectiveId(有疑问)

    ApplicationWorkbenchAdvisor.getInitialWindowPerspectiveId

        /**
         * 2.指定工作台的初始透视图
         */
        @Override
        public String getInitialWindowPerspectiveId() {
            return PERSPECTIVE_ID;
        }
    View Code

    断点调试时是又走了一遍此方法,

    至于为啥走了两遍,怎么走到第10步的,这个还不清楚。

    希望读者能为我解惑,不胜感激。

    10.创建默认透视图的初始布局

    Perspective.createInitialLayout

    package gef.tutorial.step.app;
    
    import org.eclipse.ui.IFolderLayout;
    import org.eclipse.ui.IPageLayout;
    import org.eclipse.ui.IPerspectiveFactory;
    
    public class Perspective implements IPerspectiveFactory {
    
        public void createInitialLayout(IPageLayout layout) {
            //一、基本配置
            //1.1 获取布局的编辑器
            final String editorArea = layout.getEditorArea();
            //1.2 设置显示编辑区
            layout.setEditorAreaVisible(true);
            
            //二、添加各种视图
            //2.1 添加属性视图
            IFolderLayout bottomFolder = layout.createFolder("bottom",IPageLayout.BOTTOM, 0.75f, editorArea);
            bottomFolder.addView(IPageLayout.ID_PROP_SHEET);
            
            //2.2 添加大纲视图
            IFolderLayout rightBottomFolder = layout.createFolder("right",IPageLayout.RIGHT, 0.75f, editorArea);
            rightBottomFolder.addView(IPageLayout.ID_OUTLINE);
            
            
        }
    }
    View Code

    在这一步创建工作台默认透视图的初始布局,可在此方法中添加其他视图。

    这样窗口就创建好了

    11.窗口创建之后

    ApplicationWorkbenchWindowAdvisor.postWindowCreate

    在窗口创建完毕之后,会执行此方法。可用此方法来调整窗口

    六、参考资料

    1.《Eclipse RCP 应用系统开发方法与实践》

    2.《Eclipse插件开发学习笔记》

    3.本系列总结配套PDF教程《GEF开发简单实例.pdf》

  • 相关阅读:
    CSS定位(Position)
    深入理解Javascript闭包(二)
    深入理解Javascript闭包(一)
    如何将页脚固定在页面底部
    JQuery中$.fn的用法示例
    关于HttpWebRequest.KeepAlive
    Fiddler 教程
    js数组的操作
    oracle 修改字段类型的方法(转)
    Oracle查看表结构的几种方法(转后加工)
  • 原文地址:https://www.cnblogs.com/shirui/p/9173816.html
Copyright © 2011-2022 走看看