WorldWind学习系列五:插件加载过程全解析

  不得不承认World Wind的代码真的很庞大,没有太多帮助文档的前提下,一头钻进代码里肯定令你头疼的,甚至研究代码间关联仿佛是在走迷宫。我最近一直想弄明白如何在MenuBar中加载那些插件的,WorldWind学习系列四中研究的只是特殊的三个功能加载的,那三个没有继承Plugin类,不算是插件功能加载。所以WorldWind学习系列四加载的三个是特殊情况,不是一般的插件加载。今天下午终于柳暗花明,如果你真正关注World Wind分析,那么就好好看看下面的插件加载过程全解析。

      我们先看看Plugin类的继承图,看看到底都有些什么插件,然后在分析一般性的插件加载全过程。

插件类继承关系图
  哦,原来这么多插件,我们要基于WW开发自己的应用,只需继承Plugin类写出自己的插件功能即可的。
     我们现在分析插件加载过程,请确保你看过WorldWind学习系列二:擒贼先擒王篇2 中的(5.加载上次使用的配置信息)。加载的插件入口就是WorldWind.cs的Main()中调用的LoadSettings()静态方法。
  1.读取WorldWind的配置中插件信息
加载WorldWind配置
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等,然后开始加载一个星球。

加载一个星球代码
        /// <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
        /// <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.加载启动插件函数的代码

加载启动插件
/// 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方法
 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(200200);
            m_form.Location 
= new System.Drawing.Point(0400);
            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(50);
            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方法
时间控制
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(300183);

                
// 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(0000);
                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(1259);
                time.ClientSize 
= new System.Drawing.Size(4242);
                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(501);
                play.ClientSize 
= new System.Drawing.Size(8282);
                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(293);
                close.ClientSize 
= new System.Drawing.Size(2222);
                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(1626);
                rewind.ClientSize 
= new System.Drawing.Size(3232);
                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(3588);
                pause.ClientSize 
= new System.Drawing.Size(6464);
                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(9788);
                slow.ClientSize 
= new System.Drawing.Size(6464);
                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(15888);
                fast.ClientSize 
= new System.Drawing.Size(6464);
                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(13465);
                timeLabel.ClientSize 
= new System.Drawing.Size(14060);
                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的朋友理清插件加载过程的思路,少走弯路。

其他部分:

WorldWind学习系列四:功能分析——Show Planet Axis、Show Position 、Show Cross Hairs功能

WorldWind学习系列三:简单功能分析——主窗体的键盘监听处理及拷贝和粘贴位置坐标功能

WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析

WorldWind学习系列二:擒贼先擒王篇2

WorldWind学习系列二:擒贼先擒王篇1

WorldWind学习系列一:顺利起航篇


 

   

原文地址:https://www.cnblogs.com/wuhenke/p/1623078.html