不得不承认World Wind的代码真的很庞大,没有太多帮助文档的前提下,一头钻进代码里肯定令你头疼的,甚至研究代码间关联仿佛是在走迷宫。我最近一直想弄明白如何在MenuBar中加载那些插件的,WorldWind学习系列四中研究的只是特殊的三个功能加载的,那三个没有继承Plugin类,不算是插件功能加载。所以WorldWind学习系列四加载的三个是特殊情况,不是一般的插件加载。今天下午终于柳暗花明,如果你真正关注World Wind分析,那么就好好看看下面的插件加载过程全解析。
我们先看看Plugin类的继承图,看看到底都有些什么插件,然后在分析一般性的插件加载全过程。
![插件类继承关系图](https://i-blog.csdnimg.cn/blog_migrate/f87788b512696dbb52d739eacc8bcc32.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
try
{
Settings = (WorldWindSettings) SettingsBase.Load(Settings, SettingsBase.LocationType.User);
if ( ! File.Exists(Settings.FileName))
{
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等,然后开始加载一个星球。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 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();
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()如何加载插件的?
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 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.加载启动插件函数的代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// </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(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()方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
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方法,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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学习系列三:功能分析——截屏功能和“关于”窗体分析