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

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

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

插件类继承关系图

 

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

 

ExpandedBlockStart.gif 加载一个星球代码
         ///   <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()如何加载插件的?

ExpandedBlockStart.gif 初始化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.加载启动插件函数的代码

ExpandedBlockStart.gif 加载启动插件
///  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()方法

ExpandedBlockStart.gif 重载后的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( 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方法,如下:

ExpandedBlockStart.gif 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( 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的朋友理清插件加载过程的思路,少走弯路。

其他部分:

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

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

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

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

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

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

 


 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值