在分析功能时发现,各功能都有自己的快捷键相应,比如今天要分析的 Copy Coordinates (Ctrl+C)和Paste Coordinates (Ctrl+P),以及主窗体的全屏功能也是通过快捷键(Alt+Enter)。这就使我需要彻底分析一下主窗体的键盘监听处理啦。
主窗体的键盘监听处理
与WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析 中AboutDialog.cs分析类似,WorldWind主窗体也是重载了OnKeyUp,使窗体接受键盘响应。
protected override void OnKeyUp(KeyEventArgs e)
{
if ( this .webBrowserPanel.IsTyping()) // 如果是在“网页窗体”(稍后介绍)里输入地址,则主窗体处不相应键盘事件,将 e.Handled = true; 表示已经处理事件 啦。
e.Handled = true ;
else e.Handled = HandleKeyUp(e); //此处HandleKeyUp()是真正处理主窗口的键盘响应
base .OnKeyUp(e);
}
HandleKeyUp函数
/// Handles key up events.
///
///
///
protected bool HandleKeyUp(KeyEventArgs e)
{
// keep keypresses inside browser url bar
if (e.Handled)
return true ;
if (e.Alt) //处理Alt 组合键
{
// Alt key down
switch (e.KeyCode)
{
case Keys.A:
menuItemAlwaysOnTop_Click( this ,e);
return true ;
case Keys.Q:
using ( PropertyBrowserForm worldWindSettings = new PropertyBrowserForm( Settings, " World Wind Settings " ) )
{
worldWindSettings.Icon = this .Icon;
worldWindSettings.ShowDialog();
}
return true ;
case Keys.W:
menuItemOptions_Click( this , EventArgs.Empty);
return true ;
case Keys.Enter: // 实现全屏功能,稍后看看如何实现??
this .FullScreen = ! this .FullScreen;
return true ;
case Keys.F4:
Close();
return true ;
}
}
else if (e.Control) //处理Ctrl组合键
{
// Control key down
switch (e.KeyCode)
{
case Keys.C:
case Keys.Insert: //调用拷贝坐标功能,即Copy Coordinates (Ctrl+C)
menuItemCoordsToClipboard_Click( this , e);
return true ;
case Keys.F:
return true ;
case Keys.H:
if (progressMonitor != null )
{
bool wasVisible = progressMonitor.Visible;
progressMonitor.Close();
progressMonitor.Dispose();
progressMonitor = null ;
if (wasVisible)
return true ;
}
progressMonitor = new ProgressMonitor();
progressMonitor.Icon = this .Icon;
progressMonitor.Show();
return true ;
case Keys.I:
menuItemConfigWizard_Click( this ,e);
return true ;
case Keys.N:
menuItemOptions_Click( this ,e);
return true ;
case Keys.T: //控制工具栏的显示。
menuItemShowToolbar_Click( this ,e);
return true ;
case Keys.V: // 粘贴坐标,并转向粘贴的坐标位置。今天分析
menuItemEditPaste_Click( this ,e);
return true ;
case Keys.S: //保存截屏,已经分析
menuItemSaveScreenShot_Click( this , e);
return true ;
}
}
else if (e.Shift)
{
// Shift key down
switch (e.KeyCode)
{
case Keys.Insert:
menuItemEditPaste_Click( this ,e);
return true ;
case Keys.S:
menuItemSunShading_Click( this , e);
return true ;
case Keys.A:
menuItemAtmosphericScattering_Click( this , e);
return true ;
}
}
else
{
// Other or no modifier key
switch (e.KeyCode)
{
// case Keys.B:
// menuItemWMS_Click(this, e);
// return true;
case Keys.G:
return true ;
case Keys.L:
menuItemLayerManager_Click( this , e);
return true ;
case Keys.P:
if ( this .pathMaker == null )
{
this .pathMaker = new PathMaker( this .worldWindow);
this .pathMaker.Icon = this .Icon;
}
this .pathMaker.Visible = ! this .pathMaker.Visible;
return true ;
case Keys.V:
if ( this .placeBuilderDialog == null )
{
this .placeBuilderDialog = new PlaceBuilder( this .worldWindow );
this .placeBuilderDialog.Icon = this .Icon;
}
this .placeBuilderDialog.Visible = ! this .placeBuilderDialog.Visible;
return true ;
case Keys.Escape: //退出全屏快捷键 ESC
if ( this .FullScreen)
{
this .FullScreen = false ;
return true ;
}
break ;
case Keys.D1:
case Keys.NumPad1:
this .VerticalExaggeration = 1.0f ;
return true ;
case Keys.D2:
case Keys.NumPad2:
this .VerticalExaggeration = 2.0f ;
return true ;
case Keys.D3:
case Keys.NumPad3:
this .VerticalExaggeration = 3.0f ;
return true ;
case Keys.D4:
case Keys.NumPad4:
this .VerticalExaggeration = 4.0f ;
return true ;
case Keys.D5:
case Keys.NumPad5:
this .VerticalExaggeration = 5.0f ;
return true ;
case Keys.D6:
case Keys.NumPad6:
this .VerticalExaggeration = 6.0f ;
return true ;
case Keys.D7:
case Keys.NumPad7:
this .VerticalExaggeration = 7.0f ;
return true ;
case Keys.D8:
case Keys.NumPad8:
this .VerticalExaggeration = 8.0f ;
return true ;
case Keys.D9:
case Keys.NumPad9:
this .VerticalExaggeration = 9.0f ;
return true ;
case Keys.D0:
case Keys.NumPad0:
this .VerticalExaggeration = 0.0f ;
return true ;
case Keys.F1:
this .menuItemAnimatedEarth_Click( this ,e);
return true ;
case Keys.F2:
this .menuItemModisHotSpots_Click( this ,e);
return true ;
case Keys.F5:
this .menuItemRefreshCurrentView_Click( this ,e);
return true ;
case Keys.F6:
return true ;
case Keys.F7:
this .menuItemShowLatLonLines_Click( this ,e);
return true ;
case Keys.F8:
this .menuItemPlanetAxis_Click( this ,e);
return true ;
case Keys.F9:
this .menuItemShowCrosshairs_Click( this ,e);
return true ;
case Keys.F10:
this .menuItemShowPosition_Click( this ,e);
return true ;
case Keys.F11:
this .menuItemConstantMotion_Click( this ,e);
return true ;
case Keys.F12:
this .menuItemPointGoTo_Click( this ,e);
return true ;
}
}
return false ;
}
从上面,我们可以温故和强化窗体键盘响应功能如何实现的知识点。不再多说了。
我们看看如何实现全屏功能的,FullScreen属性控制的?注意不是函数,我想这是它值得我们学习的优点。
{
get
{
return this .FormBorderStyle == FormBorderStyle.None;
}
set
{
if (value)
{
// Enter full-screen.
this .normalWindowState = this .WindowState;
this .WindowState = FormWindowState.Normal;
this .FormBorderStyle = FormBorderStyle.None;
this .Menu = null ;
this .WindowState = FormWindowState.Maximized;
}
else
{
// Go back to normal
this .WindowState = normalWindowState;
this .FormBorderStyle = FormBorderStyle.Sizable;
this .Menu = mainMenu;
}
}
}
原来Fullscreen属性只是封装了Form原有的 FormBorderStyle和WindowState,同时在里面控制了主菜单Menu的显示与否。这里就是写好属性的妙用,可以学习一下,写出更好的属性控制,而不是简单的带参数的函数控制。
拷贝位置坐标功能
WorldWind.cs
1790
{
if ( this .worldWindow.CurrentWorld == null )
return ;
WorldWindUri uri = new WorldWindUri(worldWindow.CurrentWorld.Name,worldWindow.DrawArgs.WorldCamera); //构建保存当前状态的WorldWindUri对象
string uriString = uri.ToString();
Clipboard.SetDataObject(uriString, true );// 调用Form类的Clipboard.SetDataObject()方法,将字符串拷贝到粘贴板上
}
WorldWindUri对象保存的字符串例如为:
worldwind://goto/world=Earth&lat=34.25320&lon=-101.57184&alt=48652548&dir=0.1
worldwind://goto/world=Earth&lat=-41.38362&lon=101.15747&alt=48652548&dir=0.2
worldwind://goto/world=Earth&lat=-89.89754&lon=136.64324&alt=48652548&dir=-7.2
我们应该学会使用Form类的Clipboard.SetDataObject()方法 实现自己的拷贝功能,如拷贝图片等复杂对象。
粘贴位置坐标功能
void menuItemEditPaste_Click( object sender, System.EventArgs e)
{
IDataObject iData = Clipboard.GetDataObject();
if ( ! iData.GetDataPresent(DataFormats.Text))
return ;
string clipBoardString = ( string )iData.GetData(DataFormats.Text);
try
{
worldWindUri = WorldWindUri.Parse(clipBoardString);
ProcessWorldWindUri();
}
catch (UriFormatException caught)
{
MessageBox.Show(caught.Message, " Unable to paste - you are not stupid! " , MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
2439 ProcessWorldWindUri()方法分析
private void ProcessWorldWindUri()
{
if (worldWindUri.RawUrl.IndexOf("wmsimage") >= 0)
ProcessWmsEncodedUri();
if (worldWindUri.RawUrl.IndexOf("install") >= 0)
ProcessInstallEncodedUri();
worldWindow.Goto(worldWindUri); //根据worldWindUri对象,实现定位
worldWindUri = null;
}
worldWindow.Goto实现最终是调用WorldWindow类的 GotoLatLon()。
524
///
/// Moves to specified location.
///
/// Latitude in degrees of target position. (-90 - 90).
/// Longitude in degrees of target position. (-180 - 180).
/// Camera heading in degrees (0-360) or double.NaN for no change.
/// Camera altitude in meters or double.NaN for no change.
///
/// Camera tilt in degrees (-90 - 90) or double.NaN for no change.
public void GotoLatLon( double latitude, double longitude, double heading, double altitude, double perpendicularViewRange, double tilt)
{
if ( ! double .IsNaN(perpendicularViewRange))
altitude = m_World.EquatorialRadius * Math.Sin(MathEngine.DegreesToRadians(perpendicularViewRange * 0.5 ));
if (altitude < 1 )
altitude = 1 ;
this .drawArgs.WorldCamera.SetPosition(latitude, longitude, heading, altitude, tilt);
}
关键是: this .drawArgs.WorldCamera.SetPosition(latitude, longitude, heading, altitude, tilt)其中调用了Camera.cs中的SetPosition函数,其中主要代码
Point3d p = Quaternion4d.QuaternionToEuler(m_Orientation);
_latitude.Radians = p.Y;
_longitude.Radians = p.X;
_heading.Radians = p.Z;
此中用到Quaternion4d和Point3d类。
希望网友能有所收获,其他部分:
WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析
WorldWind学习系列二:擒贼先擒王篇2
WorldWind学习系列二:擒贼先擒王篇1
WorldWind学习系列一:顺利起航篇