不得不承认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( 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方法 时间控制 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学习系列一:顺利起航篇
转载于:https://www.cnblogs.com/wuhenke/archive/2009/12/13/1623078.html
相关资源:数据结构—成绩单生成器