图文解说ChinaCock高德地图组件采集坐标 (二)
前文介绍了如何快速在uniGUI项目中引用ChinaCock地图组件,为应用增加地图功能。本文从实战出发,继续介绍为项目增加实战功能:让用在项目中可以采集指定实体的坐标。
假设,你已经参阅了前文图文解说ChinaCock高德地图组件CCuniGUIAMap (一),所以本文不再提及前文涉及到的细节。
0.用户需求
先来看一下用户的实际需求:
1.当前用户管理着所辖区域的企业资料,现在想在地图中显示这些企业的位置
2.用户需要为这些企业在地图中标注出来,以满足第一条的实现
3.用户在标注的时候,可以拖放标注,进行微调并重新按新指定的地址进行保存
4.用户鼠标指向一个标注的时候,能在上面显示企业的名称,离开后自动隐藏企业名称
5.用户单击一个标注的时候,能显示详细信息
6.自动隐藏企业详细信息,分两种情况:
a.上一步当显示详细信息时,用户不进入详细信息区域情况下,信息显示3秒后自动隐藏
b.上一步显示的信息,即当户鼠标进入这个详细信息区域,一直显示,当离开时,信息显示3秒后自动隐藏,在这期间,如果用户鼠标又回到详细信息区域,则保持显示,离开自动隐藏,这一过程可重复执行
7.用户在知道企业名称的情况下,能在地图上按企业名称查询并快速标注该企业
8.用户可以重新标注指定企业,即当前编辑一个企业的标注时,打开地图,显示所编辑企业旧的标注点,并允许重新标注。
9.用户标注企业时,要取得经纬度及详细地址
开发者想到的需求:
1.用户编辑一个企业位置,当用户进入这个功能界面时,在地图正中心显示该企业标注,这样方便用户查看并重新标注
2.地图要显示的简洁,当前用进入时,只显示所辖区域
3.实现结果,功能界面与地图尽量整合为一体,让用户感觉就是地图上操作,没有突兀的感觉
4.尽量与业务分开,实现一个与业务分开的功能,在类似的需求中可以直接使用(这一条跟用户需求无关了)
综上所述,需求看起来不少,我基本上把与用户的需求交流都整理出来了,但实现起来,由于ChinaCock精美的地图封装控件,实现起来,就是简单的事了。
现在开始动工,制作一个通用的窗口,四步实现即满足上面的需求,这又让我想起了宋丹丹的小品,说把大象关进冰箱分几步?
1.设计标注界面
先可设化设计一个界面,如下图:
整个布局基本显示地图,最底部显示标注信息,详细地址、经纬度,确定及取消按钮。
用三个uniEdit对应详细地址、经度、纬度
当用户在详细地址中,可以输入企业名称并提供一个查询按钮,进行查询,查询后自动在地图上进行标注
确定按钮,返回mrOK,取消按钮,返回mrCancel。
为此,我们要新建一个uniForm,然后放置对应的控件,并调整好布局,这没有什么难度,完全的可视化操作。
运行后的效果:
2.实现方法AddMarker
先实现方法AddMarker,按指定经纬度在地图上增加标注。实际上这是在开发过程中提练出来的方法,因此多处需要调用他,在地图上显示标注点。
function TGaoDeMapForm.AddMarker(ALng, ALat: Double):TCCuniGUIAMap.TMarker; begin //只显示当前企业的标注 if CCuniGUIAMap1.Markers.Count <= 0 then begin result:= self.CCuniGUIAMap1.Markers.Add; with result do begin with Options.Position do begin Lng := ALng; Lat := ALat; end; with Options.icon.Options do // 设置图标 begin Image := '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png'; // 图标所用图片大小,根据所设置的大小拉伸或压缩图片,等同于CSS中的background-size属性。可用于实现高清屏的高清效果 with imageSize do begin width := 25; height := 34; end; end; with Options.Offset do begin X := -13; Y := -30; end; // 标注里加上公司名称,当用户指向一个标注时显示此名称 CustomParams.Values['CorpName'] := self.CorpName; //允许用户拖放标注 Options.draggable := true; // 添加到地图 AddToMap; end; end else//已经标注过,则直接修改标注位置,不增加新的标注点,保证只有一个标注 begin result:= self.CCuniGUIAMap1.Markers.Items[0]; result.SetPosition(ALng,ALat); end; end;
代码中,直接考虑了用户需求:3.用户在标注的时候,可以拖放标注,进行微调并重新按新指定的地址进行保存。
从Delphi的角度说,我们只是操作地图的Markers对象,为其增加一个Marker对象并设置其位置等属性信息。ChinaCock作者为其封了一个属性CustomParams,方便你在这里存储你需要的信息,注意这个属性,我们在标注上显示企业名称时用的就是他。
3.处理用户标注动作
用户在地图上点击,代码响应在地图上显示一个标注点,地图控件的事件OnMapClick,正好处理这个:
procedure TGaoDeMapForm.CCuniGUIAMap1MapClick(const ASender: TObject; APosition: TLngLat; AParams: TUniStrings); begin EditLng.Text := APosition.Lng.ToString; EditLat.Text := APosition.Lat.ToString; // 根据经纬度获取位置 self.CCuniGUIAMap1.Geocoder.GetAddress(APosition, procedure(AResult: TArray<String>; AParams: TUniStrings) begin // 显示获取到的位置 self.EditAddress.Text := AResult[0]; end); //在地图上显示标注 AddMarker(APosition.Lng, APosition.Lat); end;
在这个事件中,我们同时做了三件事:
- 在界面对应的经纬度控件上显示对应信息
- 在详细地址控件上显示详细信息,为此调用了地图控件的方法GetAddress,注意这是异步执行的。
- 在地图上显示标注信息
4.处理用户拖放动作
同上一步一样,地图控件同样实现了拖放标注的事件,当用户拖放一个标注时会触发。直接上代码:
procedure TGaoDeMapForm.CCuniGUIAMap1MarkerDragEnd(const ASender: TObject; const AMarker: TCCuniGUIAMap.TMarker; const ALngLat: TLngLat; const AEventParams: TUniStrings); begin //拖放一个标注到新地点,重新取地址 EditLng.Text := ALngLat.Lng.ToString; EditLat.Text := ALngLat.Lat.ToString; // 根据经纬度获取位置 self.CCuniGUIAMap1.Geocoder.GetAddress(ALngLat, procedure(AResult: TArray<String>; AParams: TUniStrings) begin // 显示获取到的位置 self.EditAddress.Text := AResult[0]; end); //重新显示标注的名称 var AText := self.CCuniGUIAMap1.Texts.Items[0]; AText.Show; AText.SetPosition(AMarker.Options.Position); AText.SetText(AMarker.CustomParams.Values['CorpName']); end;
在这个事件中,我们也是做了三件事:
- 在界面对应的经纬度控件上显示对应信息
- 在详细地址控件上显示详细信息,为此调用了地图控件的方法GetAddress,注意这是异步执行的。
- 重新显示标注名称
经过上面的实现,核心的标注功能就完成了!用户可以在地图上标注出一个企业,同时支持拖放操作,重新标注企业的地址,在用户标注的过程中,我们取到了想要的经纬度及详细地址。
总结来说,我们只是使用了OnMapClick及OnMarkerDrapEnd两个地图控件的事件,并在这两个事件中操作Marker对象,就达到了目的!
更进步讲,地图控件提供了Markers对象列表来管理Marker对象,让我们可以同时在地图中标注多个特定的实体并显示他们。这在后面我还会继续分享给朋友们。
接下来,就是调用这个窗口,处理返回值了!
procedure TOrgBillForm.btnMapClick(Sender: TObject); begin inherited; // 经度 GaoDeMapForm.Lng := MasterDataSet.FieldByName('FJD').AsString; // 维度 GaoDeMapForm.Lat := MasterDataSet.FieldByName('FWD').AsString; //详细地址 GaoDeMapForm.CorpAddress := MasterDataSet.FieldByName('FADDRESSNAME').AsString; //公司名称 GaoDeMapForm.CorpName := MasterDataSet.FieldByName('FName').AsString; GaoDeMapForm.ShowModal( procedure(Sender: TComponent; AResult: Integer) begin case AResult of mrOk: begin MasterDataSet.Edit; // 经度 MasterDataSet.FieldByName('FJD').AsString := GaoDeMapForm.Lng; // 维度 MasterDataSet.FieldByName('FWD').AsString := GaoDeMapForm.Lat; MasterDataSet.FieldByName('FADDRESSNAME').AsString := GaoDeMapForm.CorpName; MasterDataSet.Post; end; end end); end;