【发布时间】:2016-06-03 18:56:18
【问题描述】:
在遍历我的客户表并根据地址发布纬度和经度值时,第一组纬度/经度值发布到记录号 1 和 2,然后随后每条记录都关闭一个。当我在调试模式下单步执行时,我看到第一条记录的值在我的第二次迭代中仍然存在。之后,它会自行更正,但每个记录值都是针对其上方的地址或记录的。为什么?
这是我的代码:
procedure TViewMaps.StartBtnClick(Sender: TObject);
var
iRecs, i : Integer;
Location : TLocation;
begin
ViewMaps := TViewMaps.create(self, MapAddress);
Customer.Open;
iRecs:= Customer.RecordCount;
i := 0;
While Not Customer.EOF do
begin
i := i + 1;
Customer.Edit;
MapAddress := CustomerSAddress1.AsString + ' ' + CustomerSAddress2.AsString + ' ' + CustomerSAddress3.AsString + ' ' + CustomerSAddress4.AsString + ', ' + CustomerSCity.AsString + ', ' + CustomerSState.AsString + ' ' + CustomerSZip.AsString;
fAddress := StringReplace(StringReplace(Trim(MapAddress), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
Location := GetGeoCode(fAddress);
Customerlat.AsString := Location.Lat;
Customerlng.AsString := Location.Lng;
StatusBar1.SimpleText:= 'Update Geocode for address ' + ' [Count ' + IntToStr(i) + ' of ' + IntToStr(iRecs) + ']';
Sleep(3000);
StatusBar1.Refresh;
Customer.Next;
end;
end;
好的,我根据您的建议修改了代码(不确定我的做法是否正确),但得到的结果完全相同。该程序只是一个运行一次的应用程序,用于将 lat/lng 值填充到我们的数据库中,延迟是因为我遇到了 Google 查询限制,并且该应用程序在结果从 Google 返回之前发布到数据库,所以我不得不放慢速度。
这是更新后的代码:
procedure TViewMaps.StartBtnClick(Sender: TObject);
begin
Customer.Open;
iRecCount:= Customer.RecordCount;
iCurRec := 0;
Customer.First;
if Not Customer.EOF then Timer1.Enabled := True;
end;
procedure TViewMaps.OnTimer(Sender: TObject);
begin
iCurRec := iCurRec + 1;
//ShowMessage('I am here and iCurRec = ' + inttostr(iCurRec));
Customer.Edit;
// Load full customer address into MapAddress
MapAddress := CustomerSAddress1.AsString + ' ' + CustomerSAddress2.AsString + ' ' + CustomerSAddress3.AsString + ' ' + CustomerSAddress4.AsString + ', ' + CustomerSCity.AsString + ', ' + CustomerSState.AsString + ' ' + CustomerSZip.AsString;
fAddress := StringReplace(StringReplace(Trim(MapAddress), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
// Get Longitude and Latitude from Google Maps
Location := GetGeoCode(fAddress);
// Populate lat and lng fields in Customer table
Customerlat.AsString := Location.Lat;
Customerlng.AsString := Location.Lng;
// Post record to Customer table
Customer.Post;
StatusBar1.SimpleText:= 'Update Geocode for address ' + ' [Count ' + IntToStr(iCurRec) + ' of ' + IntToStr(iRecCount) + ']';
StatusBar1.Refresh;
// Grab the next record in the Customer table
Customer.Next;
if Customer.EOF then Timer1.Enabled := False;
end;
好的...这是codeAddress javascript
''+
' function codeAddress(address) { '+
' if (geocoder) {'+
' geocoder.geocode( { address: address}, function(results, status) { '+
' if (status == google.maps.GeocoderStatus.OK) {'+
' map.setCenter(results[0].geometry.location);'+
' var myLatlng = new google.maps.LatLng( results[0].geometry.location.lat(), results[0].geometry.location.lng()); '+
' var marker = new google.maps.Marker({ '+
' position: myLatlng, '+
' title: "", '+
' map: map '+
' }); '+
' markersArray.push(marker); '+
' document.getElementById("hiddenlat").value = myLatlng.lat(); '+
' document.getElementById("hiddenlng").value = myLatlng.lng(); '+
' '+
' } else {'+
' document.getElementById("hiddenlat").value = "error"; '+
' document.getElementById("hiddenlng").value = "error"; '+
' alert("Geocode was not successful for the following reason: " + status);'+
' }'+
' });'+
' }'+
' }'+
''+
这是 Delphi 代码:
constructor TViewMaps.create(AOwner: TComponent; AAddress: string);
begin
inherited create(AOwner);
fAddress := AAddress; // fAddress is now stored to form variable
end;
procedure TViewMaps.LoadGoogleApi;
var
aStream: TMemoryStream;
begin
WebBrowser1.Navigate('about:blank'); //Set the location to an empty page
MemoAddress.Lines.Text := '1600 Amphitheatre Parkway, Mountain View, CA 94043';
if Assigned(WebBrowser1.Document) then
begin
aStream := TMemoryStream.Create; //create a TStream to load the Page from the string
try
aStream.WriteBuffer(Pointer(HTMLStr)^, Length(HTMLStr));
aStream.Seek(0, soFromBeginning);
(WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(aStream));
finally
aStream.Free;
end;
HTMLWindow2 := (WebBrowser1.Document as IHTMLDocument2).parentWindow;
end;
while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do // wait for google
begin
sleep(0);
application.processmessages;
end;
end;
function TViewMaps.GoogleApiReady: boolean;
begin
result := (HTMLWindow2 <> nil);
end;
procedure TViewMaps.ExecuteScript(AScript: string);
begin
HTMLWindow2.execScript(AScript, 'JavaScript');
end;
function TViewMaps.GetElementByID(AElementID: string): IHTMLElement;
begin
result := (WebBrowser1.Document as IHTMLDocument3).getElementByID(AElementID);
end;
function TViewMaps.GetElementValue(ElementID: string): string;
var
HtmlElement: IHTMLElement;
begin
HtmlElement := GetElementByID(ElementID);
result := HtmlElement.getAttribute('value', 0);
end;
procedure RemoveInvalidGeoLookupChars(var AString: string);
begin
AString := StringReplace(StringReplace(Trim(AString), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
// remove invalid chars
AString := StringReplace(AString, #39, #32, [rfReplaceAll]); // single quotes
AString := StringReplace(AString, #34, #32, [rfReplaceAll]); // double quotes
end;
procedure TViewMaps.FormShow(Sender: TObject);
var
Location: TLocation;
begin
MapAddress := '1600 Amphitheatre Parkway' + ', ' + 'Mountain View' + ', ' + 'CA' + ' ' + '94043';
ViewMaps := TViewMaps.create(self, MapAddress);
LoadGoogleApi;
address := MemoAddress.Lines.Text;
fAddress := StringReplace(StringReplace(Trim(address), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
Location := GetGeoCode(fAddress);
LatitudeEdit.Text := Location.Lat;
LongitudeEdit.Text := Location.Lng;
end;
function TViewMaps.GetGeocode(Address: string): TLocation;
begin
result.Lat := '0';
result.Lng := '0';
LatitudeEdit.text := '0';
LongitudeEdit.text := '0';
result.Result := 'OK';
application.processmessages;
RemoveInvalidGeoLookupChars(address);
application.processmessages;
ExecuteScript(Format('codeAddress(%s)',[QuotedStr(Address)]));
while (GetElementValue('hiddenlat') = '0') do
application.processmessages;
result.Lat := GetElementValue('hiddenlat');
result.Lng := GetElementValue('hiddenlng');
end;
procedure TViewMaps.StartBtnClick(Sender: TObject);
var
iRecCount, iCurRec: integer;
Location: TLocation;
fAddress, MapAddress: string;
begin
Customer.open;
Customer.first;
iRecCount := Customer.RecordCount;
iCurRec := 0;
while not Customer.eof do
begin
inc(iCurRec);
fillchar(Location, sizeof(Location), 0);
MapAddress := CustomerSAddress1.asstring+' '+CustomerSAddress2.asstring+' '+CustomerSCity.asstring+', '+CustomerSState.asstring+' '+CustomerSZip.asstring;
fAddress := StringReplace(StringReplace(Trim(MapAddress), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
fillchar(Location, sizeof(Location), 0);
Location := GetGeocode(fAddress);
if (Location.lat <> 'error') and (Location.lat <> '0') then
begin
Customer.edit;
CustomerLat.AsString := Location.Lat;
CustomerLng.AsString := Location.Lng;
Customer.Post;
end;
Statusbar1.SimpleText := 'Update Geocode for address ' + ' [Count ' + IntToStr(iCurRec) + ' of ' + IntToStr(iRecCount) + ']';
application.processmessages;
sleep(2000); // adjust to not exceed Google API query limit
Customer.next;
end;
end;
【问题讨论】:
-
我认为这不一定能解决您的问题,但您应该在设置 Customerlng.AsString 后立即显式调用 Customer.Post。更改将在调用 Customer.Next 期间发布,但依赖此操作是不好的做法。至于在你的循环中调用 Sleep ......好吧。
-
@MartynA - 当我达到第二条记录后,我尝试了 Customer.Post 和 Customer.Prior,但没有运气。第一条和第二条记录仍然会得到重复的 lat/lng 结果值,并且之后的每条记录都关闭一个。
-
抱歉,没有礼貌的说法:这个循环太可怕了——试试我在回答中建议的替代方案之一。至少,它们应该允许更容易地调试任何剩余的问题。
-
请澄清评论“当我在调试模式下单步执行时,我看到第一条记录的值在我的第二次迭代中仍然存在”。您具体指的是哪些价值观?数据集中 Customer* 字段的值?还是从 GetGeoCode 返回的值相同,即使两次使用不同的地址?
-
重新编辑,请参阅我的答案的更新 #1 和 #2。 #2尤其应该帮助您确定是否是您引入的延迟以避免过于频繁地调用 GetGeoLocation 这实际上导致了您的问题。
标签: delphi