WorldWind學習系列五:插件加載過程全解析

原文轉自:http://www.cnblogs.com/wuhenke/archive/2009/12/13/1623078.html

不得不承認World Wind的代碼真的很龐大,沒有太多幫助文檔的前提下,一頭鑽進代碼裏肯定令你頭疼的,甚至研究代碼間關聯彷彿是在走迷宮。我最近一直想弄明白如何在MenuBar中加載那些插件的,WorldWind學習系列四中研究的只是特殊的三個功能加載的,那三個沒有繼承Plugin類,不算是插件功能加載。所以WorldWind學習系列四加載的三個是特殊情況,不是一般的插件加載。今天下午終於柳暗花明,如果你真正關注World Wind分析,那麼就好好看看下面的插件加載過程全解析。

      我們先看看Plugin類的繼承圖,看看到底都有些什麼插件,然後在分析一般性的插件加載全過程。

哦,原來這麼多插件,我們要基於WW開發自己的應用,只需繼承Plugin類寫出自己的插件功能即可的。

     我們現在分析插件加載過程,請確保你看過WorldWind學習系列二:擒賊先擒王篇2 中的(5.加載上次使用的配置信息)。加載的插件入口就是WorldWind.cs的Main()中調用的LoadSettings()靜態方法。
  1.讀取WorldWind的配置中插件信息
加載WorldWind配置 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->private static void LoadSettings()
        {
            try
            {
    //先讀取上次使用時保存的“使用插件配置文件”,如果存在,則從文件中讀取配置實例化WorldWindSettings
                Settings = (WorldWindSettings) SettingsBase.Load(Settings, SettingsBase.LocationType.User);

                if(!File.Exists(Settings.FileName))
                {
           //我們假定是配置文件不存在,這就是一個個地加載插件,保存到ArrayList中 
                    Settings.PluginsLoadedOnStartup.Add("ShapeFileInfoTool");
                    //Settings.PluginsLoadedOnStartup.Add("OverviewFormLoader");
                    //Settings.PluginsLoadedOnStartup.Add("Atmosphere");
                    Settings.PluginsLoadedOnStartup.Add("SkyGradient");
                    Settings.PluginsLoadedOnStartup.Add("BmngLoader");
                    //Settings.PluginsLoadedOnStartup.Add("Compass");
                    //Settings.PluginsLoadedOnStartup.Add("ExternalLayerManagerLoader");
                    Settings.PluginsLoadedOnStartup.Add("MeasureTool");
                    //Settings.PluginsLoadedOnStartup.Add("MovieRecorder");
                    Settings.PluginsLoadedOnStartup.Add("NRLWeatherLoader");
                    Settings.PluginsLoadedOnStartup.Add("ShapeFileLoader");
                    Settings.PluginsLoadedOnStartup.Add("Stars3D");
                    Settings.PluginsLoadedOnStartup.Add("GlobalClouds");
                    Settings.PluginsLoadedOnStartup.Add("PlaceFinderLoader");
                    Settings.PluginsLoadedOnStartup.Add("LightController");

                    Settings.PluginsLoadedOnStartup.Add("Earthquake_2.0.2.1");
                    Settings.PluginsLoadedOnStartup.Add("Historical_Earthquake_2.0.2.2");
                    Settings.PluginsLoadedOnStartup.Add("KMLImporter");
                    //Settings.PluginsLoadedOnStartup.Add("doublezoom");
                    //Settings.PluginsLoadedOnStartup.Add("PlanetaryRings");
                    Settings.PluginsLoadedOnStartup.Add("TimeController");
                    //Settings.PluginsLoadedOnStartup.Add("WavingFlags");
                    Settings.PluginsLoadedOnStartup.Add("ScaleBarLegend");
                    Settings.PluginsLoadedOnStartup.Add("Compass3D");
                    Settings.PluginsLoadedOnStartup.Add("AnaglyphStereo");
                    Settings.PluginsLoadedOnStartup.Add("GlobeIcon");

                }
                // decrypt encoded user credentials
                DataProtector dp = new DataProtector(DataProtector.Store.USE_USER_STORE);

                if(Settings.ProxyUsername.Length > 0) Settings.ProxyUsername = dp.TransparentDecrypt(Settings.ProxyUsername);
                if(Settings.ProxyPassword.Length > 0) Settings.ProxyPassword = dp.TransparentDecrypt(Settings.ProxyPassword);
            }
            catch(Exception caught)
            {
                Log.Write(caught);
            }
        }


2.Main()中後面調用MainApplication()方法,該MainApplication()調用OpenStartupWorld(),用來初始化啓動World對象。OpenStartupWorld()方法首先確定加載的是Earth/Moon等,然後開始加載一個星球。

 

加載一個星球代碼 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        /// <summary>
        /// Loads a new planet
        /// </summary>
        private void OpenWorld(string worldXmlFile)
        {
            
            if(this.worldWindow.CurrentWorld != null)
            {
                try
                {
                    this.worldWindow.ResetToolbar();
                }
                catch
                {}

                try
                {
                    foreach(PluginInfo p in this.compiler.Plugins)
                    {
                        try
                        {
                            if(p.Plugin.IsLoaded)
                                p.Plugin.Unload();
                        }
                        catch
                        {}
                    }
                }
                catch
                {}
                
                try
                {
                    this.worldWindow.CurrentWorld.Dispose();
                }
                catch
                {}
                
            }


            if(this.gotoDialog != null)
            {
                this.gotoDialog.Dispose();
                this.gotoDialog = null;
            }

            if(this.rapidFireModisManager != null)
            {
                this.rapidFireModisManager.Dispose();
                this.rapidFireModisManager = null;
            }

            if(this.animatedEarthMananger != null)
            {
                this.animatedEarthMananger.Dispose();
                this.animatedEarthMananger = null;
            }

            if(this.wmsBrowser != null)
            {
                this.wmsBrowser.Dispose();
                this.wmsBrowser = null;
            }
            worldWindow.CurrentWorld = WorldWind.ConfigurationLoader.Load(worldXmlFile, worldWindow.Cache);
            this.splashScreen.SetText("Initializing menus...");
            // InitializePluginCompiler()是我們要關注的初始化插件編輯器PluginCompiler(真正管理加載插件的類)
            InitializePluginCompiler();
       
       //RenderableObject系統很複雜,我們稍後準備專門分析一下
            foreach(RenderableObject worldRootObject in this.worldWindow.CurrentWorld.RenderableObjects.ChildObjects)
            {
                this.AddLayerMenuButtons(this.worldWindow, worldRootObject);
            }
            //加載Earth專有的MenuButton( AnimatedEarthManager和RapidFireModisManager)的配置,
            //這裏主要不關注
            this.AddInternalPluginMenuButtons();

            this.menuItemModisHotSpots.Enabled = worldWindow.CurrentWorld.IsEarth;
            this.menuItemAnimatedEarth.Enabled = worldWindow.CurrentWorld.IsEarth;
        }


3.我們看看InitializePluginCompiler()如何加載插件的?

初始化PluginCompiler 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        /// <summary>
        /// Compile and run plug-in "scripts"
        /// </summary>
        private void InitializePluginCompiler()
        {
            Log.Write(Log.Levels.Debug, "CONF", "initializing plugin compiler...");
            this.splashScreen.SetText("Initializing plugins...");
            string pluginRoot = Path.Combine(DirectoryPath, "Plugins");
            compiler = new PluginCompiler(this, pluginRoot);

//#if DEBUG
            // Search for plugins in worldwind.exe (plugin development/debugging aid)
            compiler.FindPlugins(Assembly.GetExecutingAssembly());
//#endif
       //從啓動文件夾下Plugins文件夾,加載插件
            compiler.FindPlugins();
      //加載啓動插件插件
            compiler.LoadStartupPlugins();
        }


 4.加載啓動插件函數的代碼

加載啓動插件 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/// Loads the plugins that are set for load on world wind startup.
        /// </summary>
        public void LoadStartupPlugins()
        {
            foreach(PluginInfo pi in m_plugins)
            {
                if(pi.IsLoadedAtStartup)
                {
                    try
                    {
                        // Compile
                        Log.Write(Log.Levels.Debug, LogCategory, "loading "+pi.Name+" ...");
                        worldWind.SplashScreen.SetText("Initializing plugin " + pi.Name);
     //Load()方法加載插件,Plugin類的Load()爲虛方法,實質上調用的是各個插件重載後的Load()方法
                        Load(pi);
                    }
                    catch(Exception caught)
                    {
                        // Plugin failed to load
                        string message = "Plugin " + pi.Name + " failed: " + caught.Message;
                        Log.Write(Log.Levels.Error, LogCategory, message);
                        Log.Write(caught);

                        // Disable automatic load of this plugin on startup
                        pi.IsLoadedAtStartup = false;

                        worldWind.SplashScreen.SetError(message);
                    }
                }
            }
        }


5.現在看兩個插件類重載的Load()方法的實例。例如:Compass3D.cs和TimeController.cs。

  Compass3D.cs的Load()方法

重載後的Load方法 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 21行     public override void Load()
        {
            m_menuItem = new System.Windows.Forms.MenuItem("Compass");
            m_menuItem.Click += new EventHandler(m_menuItem_Click);
            m_menuItem.Checked = World.Settings.ShowCompass;
            ParentApplication.ToolsMenu.MenuItems.Add(m_menuItem);
            
            m_form = new FormWidget("Compass");
            m_form.ClientSize = new System.Drawing.Size(200, 200);
            m_form.Location = new System.Drawing.Point(0, 400);
            m_form.BackgroundColor = World.Settings.WidgetBackgroundColor;
            m_form.AutoHideHeader = true;
            m_form.VerticalScrollbarEnabled = false;
            m_form.HorizontalScrollbarEnabled = false;
            m_form.BorderEnabled = false;
       //註冊兩個窗體事件
            m_form.OnResizeEvent += new FormWidget.ResizeHandler(m_form_OnResizeEvent);
            m_form.OnVisibleChanged += new VisibleChangedHandler(m_form_OnVisibleChanged);
            //實例化Compass3DWidget
            m_compass = new Compass3DWidget();
            m_compass.Location = new System.Drawing.Point(5, 0);
            m_compass.Font = new System.Drawing.Font("Ariel", 10.0f, System.Drawing.FontStyle.Bold);
            m_compass.ParentWidget = m_form;
            m_form_OnResizeEvent(m_form, m_form.WidgetSize);
            
            m_form.ChildWidgets.Add(m_compass);
            m_form.Visible = World.Settings.ShowCompass;
//將要繪製的Widget加載到DrawArgs.NewRootWidget.ChildWidgets,爲了在WorldWindow.cs的Render()方法裏渲染
            DrawArgs.NewRootWidget.ChildWidgets.Add(m_form);
       //Compass 3D工具菜單按鈕
            m_toolbarItem = new WorldWind.NewWidgets.WidgetMenuButton(
                    "Compass 3D",
                    basePath + "\\Data\\Icons\\Interface\\compass2.png",
                    m_form);
      //向MenuBar中添加Compass 3D菜單按鈕
            ParentApplication.WorldWindow.MenuBar.AddToolsMenuButton(m_toolbarItem);
            base.Load();
        }


TimeController.cs的Load方法,如下:

TimeController.cs的Load方法 


Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->時間控制
public override void Load()
        {
            try
            {
                m_window = new WorldWind.NewWidgets.FormWidget("Time Control");
                m_window.Name = "Time Control";
                m_window.ClientSize = new System.Drawing.Size(300, 183);

                // Bug in FormWidget required anchor to be set before Location and parent widget
                m_window.Anchor = WorldWind.NewWidgets.WidgetEnums.AnchorStyles.Left | WorldWind.NewWidgets.WidgetEnums.AnchorStyles.Bottom;
                m_window.ParentWidget = DrawArgs.NewRootWidget;
                m_window.Location = new System.Drawing.Point(0, DrawArgs.NewRootWidget.ClientSize.Height - 183);
                m_window.Text = "Double Click to Re-Open";
                m_window.BorderEnabled = false;
                m_window.AutoHideHeader = true;
                m_window.BackgroundColor = System.Drawing.Color.FromArgb(0, 0, 0, 0);
                m_window.HeaderEnabled = true;
                m_window.Visible = false;

                time = new WorldWind.NewWidgets.PictureBox();
                time.Name = "Time";
                time.ImageUri = basePath + "\\Data\\Icons\\Time\\time off.png";
                time.ClientLocation = new System.Drawing.Point(12, 59);
                time.ClientSize = new System.Drawing.Size(42, 42);
                time.Visible = true;
                time.ParentWidget = m_window;
                time.OnMouseEnterEvent += new EventHandler(time_OnMouseEnterEvent);
                time.OnMouseLeaveEvent += new EventHandler(time_OnMouseLeaveEvent);
                time.OnMouseUpEvent += new MouseEventHandler(time_OnMouseUpEvent);
                time.CountHeight = false;
                time.CountWidth = true;
                m_window.ChildWidgets.Add(time);

                play = new WorldWind.NewWidgets.PictureBox();
                play.Name = "Play";
                if (TimeKeeper.Enabled)
                {
                    play.ImageUri = basePath + "\\Data\\Icons\\Time\\play on.png";
                }
                else
                {
                    play.ImageUri = basePath + "\\Data\\Icons\\Time\\play off.png";
                }
                play.ClientLocation = new System.Drawing.Point(50, 1);
                play.ClientSize = new System.Drawing.Size(82, 82);
                play.Visible = true;
                play.ParentWidget = m_window;
                play.OnMouseEnterEvent += new EventHandler(play_OnMouseEnterEvent);
                play.OnMouseLeaveEvent += new EventHandler(play_OnMouseLeaveEvent);
                play.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(play_OnMouseUpEvent);
                play.CountHeight = true;
                play.CountWidth = true;
                m_window.ChildWidgets.Add(play);

                close = new WorldWind.NewWidgets.PictureBox();
                close.Name = "Close";
                close.ImageUri = basePath + "\\Data\\Icons\\Time\\close off.png";
                close.ClientLocation = new System.Drawing.Point(29, 3);
                close.ClientSize = new System.Drawing.Size(22, 22);
                close.Visible = true;
                close.ParentWidget = m_window;
                close.OnMouseEnterEvent += new EventHandler(close_OnMouseEnterEvent);
                close.OnMouseLeaveEvent += new EventHandler(close_OnMouseLeaveEvent);
                close.OnMouseUpEvent += new MouseEventHandler(close_OnMouseUpEvent);
                close.CountHeight = false;
                close.CountWidth = false;
                m_window.ChildWidgets.Add(close);

                rewind = new WorldWind.NewWidgets.PictureBox();
                rewind.Name = "Rewind";
                rewind.ImageUri = basePath + "\\Data\\Icons\\Time\\repeat off.png";
                rewind.ClientLocation = new System.Drawing.Point(16, 26);
                rewind.ClientSize = new System.Drawing.Size(32, 32);
                rewind.Visible = true;
                rewind.ParentWidget = m_window;
                rewind.OnMouseEnterEvent += new EventHandler(rewind_OnMouseEnterEvent);
                rewind.OnMouseLeaveEvent += new EventHandler(rewind_OnMouseLeaveEvent);
                rewind.OnMouseUpEvent += new MouseEventHandler(rewind_OnMouseUpEvent);
                rewind.CountHeight = false;
                rewind.CountWidth = false;
                m_window.ChildWidgets.Add(rewind);

                pause = new WorldWind.NewWidgets.PictureBox();
                pause.Name = "Pause";
                if (TimeKeeper.Enabled)
                {
                    pause.ImageUri = basePath + "\\Data\\Icons\\Time\\pause off.png";
                }
                else
                {
                    pause.ImageUri = basePath + "\\Data\\Icons\\Time\\pause on.png";
                }
                pause.ClientLocation = new System.Drawing.Point(35, 88);
                pause.ClientSize = new System.Drawing.Size(64, 64);
                pause.Visible = true;
                pause.ParentWidget = m_window;
                pause.OnMouseEnterEvent += new EventHandler(pause_OnMouseEnterEvent);
                pause.OnMouseLeaveEvent += new EventHandler(pause_OnMouseLeaveEvent);
                pause.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(pause_OnMouseUpEvent);
                pause.CountHeight = true;
                pause.CountWidth = false;
                m_window.ChildWidgets.Add(pause);

                slow = new WorldWind.NewWidgets.PictureBox();
                slow.Name = "Slow";
                slow.ImageUri = basePath + "\\Data\\Icons\\Time\\slow off.png";
                slow.ClientLocation = new System.Drawing.Point(97, 88);
                slow.ClientSize = new System.Drawing.Size(64, 64);
                slow.Visible = true;
                slow.ParentWidget = m_window;
                slow.OnMouseEnterEvent += new EventHandler(slow_OnMouseEnterEvent);
                slow.OnMouseLeaveEvent += new EventHandler(slow_OnMouseLeaveEvent);
                slow.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(slow_OnMouseUpEvent);
                slow.CountHeight = false;
                slow.CountWidth = false;
                m_window.ChildWidgets.Add(slow);

                fast = new WorldWind.NewWidgets.PictureBox();
                fast.Name = "Fast";
                fast.ImageUri = basePath + "\\Data\\Icons\\Time\\fast off.png";
                fast.ClientLocation = new System.Drawing.Point(158, 88);
                fast.ClientSize = new System.Drawing.Size(64, 64);
                fast.Visible = true;
                fast.ParentWidget = m_window;
                fast.OnMouseEnterEvent += new EventHandler(fast_OnMouseEnterEvent);
                fast.OnMouseLeaveEvent += new EventHandler(fast_OnMouseLeaveEvent);
                fast.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(fast_OnMouseUpEvent);
                fast.CountHeight = false;
                fast.CountWidth = false;
                m_window.ChildWidgets.Add(fast);

                timeLabel = new WorldWind.NewWidgets.TextLabel();
                timeLabel.Name = "Current Time";
                timeLabel.ClientLocation = new System.Drawing.Point(134, 65);
                timeLabel.ClientSize = new System.Drawing.Size(140, 60);
                timeLabel.Visible = true;
                timeLabel.ParentWidget = m_window;
                timeLabel.Text = GetCurrentTimeString();
                TimeKeeper.Elapsed += new System.Timers.ElapsedEventHandler(TimeKeeper_Elapsed);
                timeLabel.CountHeight = false;
                timeLabel.CountWidth = true;
                timeLabel.WordBreak = true;
                m_window.ChildWidgets.Add(timeLabel);

                DrawArgs.NewRootWidget.ChildWidgets.Add(m_window);

                m_toolbarItem = new WorldWind.NewWidgets.WidgetMenuButton(
                    "Time Controller",
                    basePath + "\\Data\\Icons\\Time\\time off.png",
                    m_window);
      //向MenuBar中添加菜單按鈕
                ParentApplication.WorldWindow.MenuBar.AddToolsMenuButton(m_toolbarItem);
            }
            catch (Exception ex)
            {
                Log.Write(ex);
            }
            base.Load();
        }


 

其他插件的重載後的Load()方法也是類似的,不再贅述。希望能幫研究WW的朋友理清插件加載過程的思路,少走彎路。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章