大家都用過百度地圖或者google地圖吧,在它們主地圖的右下角,有個小地圖窗口,這就是鷹眼窗口。用鼠標拖動鷹眼裡的小窗口,則主地圖便移動到相應的位置。下面就介紹鷹眼的實現。
鷹眼和主地圖的互動,主要體現在兩個方面:一是主地圖的地圖改變了,則鷹眼裡的矩形框要移動到對應的位置,以指示當前地圖在整個地圖中的位置;二是鷹眼的矩形框移動了,則主地圖中顯示的地圖要移動到相應的位置。
ArcEngine中顯示地圖的控件叫 ESRI MapControl,這裡主要用到了它的OnAfterDraw事件。在主地圖的OnAfterDrawMapControl事件中,根據當前地圖的大小,改變鷹眼中矩形框的大小;在鷹眼的OnAfterDraw事件中,根據矩形框的位置,確定主地圖中地圖的位置。google地圖的鷹眼還實現了矩形框的拖動,這個也很好實現,呵呵。在鼠標點擊到鷹眼控件時,先判斷是否在矩形框內,如果在的話,用一個狀態量記住這個狀態,此時如果鼠標移動,則矩形框跟著相應的移動;若不在矩形框內,則矩形框移動到鼠標點擊的位置。下面的代碼是基於VC6和ArcEngine9.2實現的。鷹眼矩形框的拖動涉及到的事件比較多,包括OnMouseDownMapControl、OnMouseMoveMapControl、OnMouseUpMapControl事件。
1
2 class CEagleEyeCtrl : public CStatic
3 {
4 // Construction
5 public:
6 CEagleEyeCtrl();
7 CMapControlDefault m_MapCtrl;
8 IFillShapeElementPtr m_ipFillShapeElement;
9 IEnvelopePtr m_ipLastEnvelope;
10 IPointPtr m_ipPoint;
11 int m_nAction;
12 BOOL m_bDrag; // 紅框拖動的標記
13 BOOL m_bDragWnd; // 拖動整個鷹眼窗口
14 BOOL m_bShow;
15 CPoint m_point; // 鼠標上一次左鍵按下的屏幕坐標
16 afx_msg void OnMouseDownMapcontrol(long button, long shift, long X, long Y, double mapX, double mapY);
17 afx_msg void OnMouseMoveMapcontrol(long button, long shift, long X, long Y, double mapX, double mapY);
18 afx_msg void OnMouseUpMapcontrol(long button, long shift, long X, long Y, double mapX, double mapY);
19 afx_msg void OnAfterDrawMapcontrol(const VARIANT FAR& Display, long viewDrawPhase);
20 DECLARE_EVENTSINK_MAP()
21 DECLARE_MESSAGE_MAP()
22 };
23
24 void CEagleEyeCtrl::OnMouseDownMapcontrol(long button, long shift, long X,
25 long Y, double mapX, double mapY)
26{
27 // TODO: Add your control notification handler code here
28 IActiveViewPtr ipActiveView;
29 ipActiveView = m_MapCtrl.GetActiveView();
30 if (ipActiveView == NULL)
31 {
32 return ;
33 }
34
35 IPointPtr ipPoint(CLSID_Point);
36 IRgbColorPtr ipRgbColor(CLSID_RgbColor);
37
38 HRESULT hr = ipPoint->PutCoords(mapX, mapY);
39 hr = ipRgbColor->put_RGB((OLE_COLOR)RGB(255, 0, 0));
40 ASSERT(SUCCEEDED(hr));
41
42 IGraphicsContainerPtr ipGraphicsContainer;
43 ipActiveView->get_GraphicsContainer(&ipGraphicsContainer);
44
45 // 添加矩形
46 IEnvelopePtr ipEnvelope(CLSID_Envelope);
47 ipEnvelope->put_XMax(mapX + 0.0005);
48 ipEnvelope->put_XMin(mapX - 0.0005);
49 ipEnvelope->put_YMax(mapY + 0.0003);
50 ipEnvelope->put_YMin(mapY - 0.0003);
51 IRectangleElementPtr ipRectangleElement(CLSID_RectangleElement);
52 ISimpleFillSymbolPtr ipSimpleFillSymbol(CLSID_SimpleFillSymbol);
53 ISimpleLineSymbolPtr ipSimpleLineSymbol(CLSID_SimpleLineSymbol);
54 ipSimpleFillSymbol->put_Style(esriSFSHollow);
55 ipSimpleLineSymbol->put_Color(ipRgbColor);
56 ipSimpleLineSymbol->put_Style(esriSLSSolid);
57 ipSimpleLineSymbol->put_Width(1.8);
58 ipSimpleFillSymbol->put_Outline(ipSimpleLineSymbol);
59
60 IElementPtr ipElement = ipRectangleElement;
61 ipElement->put_Geometry(ipEnvelope);
62 if (m_ipFillShapeElement != NULL)
63 {
64 IElementPtr ipTempElement = m_ipFillShapeElement;
65 IGeometryPtr ipGeometry = NULL;
66 ipTempElement->get_Geometry(&ipGeometry);
67 esriGeometryType esriType = esriGeometryNull;
68 ipGeometry->get_GeometryType(&esriType);
69 ASSERT(esriType == esriGeometryPolygon);
70 IEnvelopePtr ipEnvelope2 = NULL;
71 IPolygonPtr ipPolygon = ipGeometry;
72 hr = ipPolygon->get_Envelope(&ipEnvelope2);
73 ASSERT(ipEnvelope2 != NULL);
74 double xMin = 0.0;
75 double xMax = 0.0;
76 double yMin = 0.0;
77 double yMax = 0.0;
78 ipEnvelope2->QueryCoords(&xMin, &yMin, &xMax, &yMax);
79 if (mapX >= xMin && mapX <= xMax && mapY >= yMin && mapY <= yMax)
80 {
81 m_bDrag = TRUE;
82 }
83 else
84 {
85 m_bDrag = FALSE;
86 }
87 }
88 }
89
90 void CEagleEyeCtrl::OnMouseMoveMapcontrol(long button, long shift, long X,
91 long Y, double mapX, double mapY)
92 {
93 // TODO: Add your control notification handler code here
94 if (m_bDrag)
95 {
96 if (m_ipFillShapeElement != NULL)
97 {
98 IActiveViewPtr ipActiveView = m_MapCtrl.GetActiveView();
99 if (ipActiveView == NULL || m_ipFillShapeElement == NULL)
100 {
101 return;
102 }
103 IGraphicsContainerPtr ipGraphicsContainer = NULL;
104 HRESULT hr = ipActiveView->get_GraphicsContainer(&ipGraphicsContainer);
105 IRgbColorPtr ipRgbColor(CLSID_RgbColor);
106
107 IElementPtr ipElement = m_ipFillShapeElement;
108 IGeometryPtr ipGeometry = NULL;
109 hr = ipElement->get_Geometry(&ipGeometry);
110 esriGeometryType esriType = esriGeometryNull;
111 ipGeometry->get_GeometryType(&esriType);
112 ASSERT(esriType == esriGeometryPolygon);
113 IEnvelopePtr ipEnvelope(CLSID_Envelope);
114 IPolygonPtr ipPolygon = ipGeometry;
115 hr = ipPolygon->get_Envelope(&ipEnvelope);
116
117 IPointPtr ipPoint(CLSID_Point);
118 ipPoint->PutCoords(mapX, mapY);
119 ipEnvelope->CenterAt(ipPoint);
120 m_ipLastEnvelope = ipEnvelope;
121 IEnvelopePtr ipEnvelope2 = m_MapCtrl.GetExtent();
122 ipActiveView->PartialRefresh(esriViewForeground, NULL, ipEnvelope2);
123 }
124 }
125 }
126
127 void CEagleEyeCtrl::OnMouseUpMapcontrol(long button, long shift, long X,
128 long Y, double mapX, double mapY)
129 {
130 // TODO: Add your control notification handler code here
131 m_bDrag = FALSE;
132
133 IActiveViewPtr ipActiveView = m_MapCtrl.GetActiveView();
134 if (ipActiveView == NULL || m_ipFillShapeElement == NULL)
135 {
136 return;
137 }
138 if (m_ipLastEnvelope != NULL)
139 {
140 m_ipLastEnvelope = NULL;
141 }
142 IGraphicsContainerPtr ipGraphicsContainer = NULL;
143 HRESULT hr = ipActiveView->get_GraphicsContainer(&ipGraphicsContainer);
144 IElementPtr ipElement = m_ipFillShapeElement;
145 IGeometryPtr ipGeometry = NULL;
146 ipElement->get_Geometry(&ipGeometry);
147 esriGeometryType esriType;
148 ipGeometry->get_GeometryType(&esriType);
149 ASSERT(esriType == esriGeometryPolygon);
150 IPolygonPtr ipPolygon = ipGeometry;
151 IEnvelopePtr ipEnvelope = NULL;
152 ipPolygon->get_Envelope(&ipEnvelope);
153 IPointPtr ipPoint(CLSID_Point);
154 ipPoint->PutCoords(mapX, mapY);
155 ipEnvelope->CenterAt(ipPoint);
156 ipElement->put_Geometry(ipEnvelope);
157 m_ipFillShapeElement = ipElement;
158 ipGraphicsContainer->UpdateElement((IElementPtr)m_ipFillShapeElement);
159 ipActiveView->Refresh();
160 // 給父控件發消息,切換視圖
161 m_ipPoint = ipPoint;
162 GetParent()->GetParent()->SendMessage(WMU_GIS_EAGLE_NOTIFY, 0, 0);
163 }
164
165
166 void CEagleEyeCtrl::OnAfterDrawMapcontrol(const VARIANT FAR& Display,
167 long viewDrawPhase)
168{
169 // TODO: Add your control notification handler code here
170 if (m_ipLastEnvelope != NULL && m_bDrag)
171 {
172 if (m_ipFillShapeElement != NULL)
173 {
174 IActiveViewPtr ipActiveView = m_MapCtrl.GetActiveView();
175 if (ipActiveView == NULL || m_ipFillShapeElement == NULL)
176 {
177 return;
178 }
179
180 IElementPtr ipElement = m_ipFillShapeElement;
181 IGeometryPtr ipGeometry = NULL;
182 ipElement->get_Geometry(&ipGeometry);
183 esriGeometryType esriType = esriGeometryNull;
184 ipGeometry->get_GeometryType(&esriType);
185 ASSERT(esriType == esriGeometryPolygon);
186 IEnvelopePtr ipEnvelope(CLSID_Envelope);
187 IPolygonPtr ipPolygon = ipGeometry;
188 ipPolygon->get_Envelope(&ipEnvelope);
189
190 CPoint pt;
191 GetCursorPos(&pt);
192 m_MapCtrl.ScreenToClient(&pt);
193 IPointPtr ipPoint = m_MapCtrl.ToMapPoint(pt.x, pt.y);
194 ipEnvelope->CenterAt(ipPoint);
195
196 ISimpleFillSymbolPtr ipSimpleFillSymbol(CLSID_SimpleFillSymbol);
197 ISimpleLineSymbolPtr ipSimpleLineSymbol(CLSID_SimpleLineSymbol);
198 IRgbColorPtr ipRgbColor(CLSID_RgbColor);
199 HRESULT hr = ipRgbColor->put_RGB((OLE_COLOR)RGB(255, 0, 0));
200 ASSERT(SUCCEEDED(hr));
201 ipSimpleFillSymbol->put_Style(esriSFSHollow);
202 ipSimpleLineSymbol->put_Color(ipRgbColor);
203 ipSimpleLineSymbol->put_Style(esriSLSSolid);
204 ipSimpleLineSymbol->put_Width(1.8);
205 ipSimpleFillSymbol->put_Outline(ipSimpleLineSymbol);
206
207 IScreenDisplayPtr ipScreenDisplay = NULL;
208 OLE_HANDLE hDC = NULL;
209 hr = ipActiveView->get_ScreenDisplay(&ipScreenDisplay);
210 ASSERT(SUCCEEDED(hr));
211 hr = ipScreenDisplay->get_hDC(&hDC);
212 ASSERT(SUCCEEDED(hr));
213
214 hr = ipScreenDisplay->StartDrawing(hDC, -1);
215 ASSERT(SUCCEEDED(hr));
216 hr = ipScreenDisplay->SetSymbol((ISymbolPtr)ipSimpleFillSymbol);
217 ASSERT(SUCCEEDED(hr));
218 hr = ipScreenDisplay->DrawRectangle(ipEnvelope);
219 ASSERT(SUCCEEDED(hr));
220 hr = ipScreenDisplay->FinishDrawing();
221 }
222 }
223}