在分析功能时发现,各功能都有自己的快捷键相应,比如今天要分析的 Copy Coordinates (Ctrl+C)和Paste Coordinates (Ctrl+P),以及主窗体的全屏功能也是通过快捷键(Alt+Enter)。这就使我需要彻底分析一下主窗体的键盘监听处理啦。
主窗体的键盘监听处理
与WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析 中AboutDialog.cs分析类似,WorldWind主窗体也是重载了OnKeyUp,使窗体接受键盘响应。
936行
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函数
真正处理键盘响应函数
///
<summary>
///
Handles key up events.
///
</summary>
///
<param name="e"></param>
///
<returns>
Returns true if the key is handled.
</returns>
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属性控制的?注意不是函数,我想这是它值得我们学习的优点。
全屏属性
private
bool
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
拷贝代码
private
void
menuItemCoordsToClipboard_Click(
object
sender, System.EventArgs e)
{
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()方法 实现自己的拷贝功能,如拷贝图片等复杂对象。
粘贴位置坐标功能
粘贴坐标信息,并重新定位
2150
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
{
//通过字符串,解析还原出对象。这原理很像对象XML序列化
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()。
转到特定的经纬度位置
WorldWindow类的 GotoLatLon()转到特定的位置
524
///
<summary>
///
Moves to specified location.
///
</summary>
///
<param name="latitude">
Latitude in degrees of target position. (-90 - 90).
</param>
///
<param name="longitude">
Longitude in degrees of target position. (-180 - 180).
</param>
///
<param name="heading">
Camera heading in degrees (0-360) or double.NaN for no change.
</param>
///
<param name="altitude">
Camera altitude in meters or double.NaN for no change.
</param>
///
<param name="perpendicularViewRange"></param>
///
<param name="tilt">
Camera tilt in degrees (-90 - 90) or double.NaN for no change.
</param>
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学习系列一:顺利起航篇