Ramblings

Delphi Programming Observations

Wednesday, October 29, 2008

Interact with Google Maps in a TWebBrowser from Delphi

Here is a simple program to show how you can “host” google maps in a TWebBrowser and interact with it from a Delphi application.

Download the Delphi project

GoogleMapsTest Program Screenshot

GoogleMapsTest Program Screenshot

I saw a recent newsgroup post at borland.public.delphi.language.delphi.general Google Maps geocoding service with TWebBrowser and I had seen some interesting posts by former CodeGear employee Steve Trefethen (Using Google Maps From a Windows Client Application). Having played a little with googlemaps hosted in a webpage, and also with a TWebBrowser in a Delphi application hooking into JavaScript events, I thought I would throw together a little test app to at least have one full working example for people to look at.

I am a big fan of self contained EXEs, saving to a file and then loading that file in a TWebBrowser did not seem necessary. My first thought was to put an Indy TIdHTTPServer and serve the page from the code. This worked, but it activated the windows Firewall and asked me if I wanted to unblock, which annoyed me.

My next thought was to load a string directly into the TWebBrowser, as I had done before, following: How to load HTML directly to a WebBrowser, but then I started getting the Google Maps error that “The Google Maps API key used on this web site was registered for a different web site. …” I found a trick to get around that by making the TWebBrowser think its URL was http://localhost, by setting the IHTMLDocument2.URL after the .Navigate() to about:blank

WebBrowser.Navigate('about:blank');
(WebBrowser.Document as IHTMLDocument2).URL :=
   'http://localhost/';

That was all it needed, now the Delphi app was completely self contained.

Geocoding using Google from Delphi

I knew that Google allowed geocoding using your API key, so I signed up for another API key (I can’t find anywhere to retrieve the keys I’ve generated) and quickly made an example which retrieved the comma-separated values from http://maps.google.com/maps/geo?q=[Encoded address here]&output=csv&key= and loaded the two edit boxes. The “Add Marker” button simply puts a marker on the map at the latitude and longitude specified in the edit boxes, and the “Center map on” button simply calls map.panTo. I may update this to have a more usable marker being added, since right now it doesn’t have a callback for clicking or anything, it’s just a visual representation.

I knew it had to be possible, and I wanted to give out a fully working example, without giving out an API key tied to my gmail address, so in some quick google searches, I found some php code which scraped the resulting page that google returns when a user types into the search box at the main page of googlemaps. So I copied and pasted my other geocoding function and used http://maps.google.com/maps?q= as the link, and searched through the html response for the center point, which would be the latitude and longitude of the address entered. I parsed out the values, and I was a little surprised that when searching on the same address through these two different ways, the geocoding API was less accurate, typing a town name into google maps search box put the Marker just about directly over the town name that is drawn on the map, but through the geocoding service, it was off a little. So this way may be a little more accurate, but it will break if Google changes the structure of the page.

I noticed something else strange, when I was looking through the code, I noticed that my “cheat” geocoding URL was adding &output=csv because I copied and pasted it. I didn’t think it was necessary, as I could leave it off and Firefox would bring me to the page of the map without problems. When I removed it from the code, however, Indy kept throwing “HTTP/1.1 302 Found.” Exceptions. I thought maybe it just needed another dummy parameter after the q=, but everything else I tried caused the Exceptions.

I do suggest you stick to the geocode API, since it has a much less likelihood of breaking if Google decides to change something, and it’s the accepted way to use their free service.

I hope this helps satisfy the people who wanted to see the source for a working example of using Google Maps in a Delphi Application.

posted by Jason at 10:12 pm  

15 Responses to “Interact with Google Maps in a TWebBrowser from Delphi”

  1. Henk says:

    I got an erro when i try the example

    It told met that the property anchor form twebbrowser1 does not exist.

  2. Jason says:

    I suppose I should say that I tested this in Delphi 2007 and Delphi 2009 using the normal TWebBrowser in dclie1XX.bpl. The example also works with Delphi 2006 if you remove the Application.MainFormOnTaskbar := true from the DPR.

  3. [...] received an email about my first Google Maps in a TWebBrowser post asking how to remove the white border around the map, in order to let the GoogleMap fill the [...]

  4. Lapo says:

    Hi, I’m trying to use your trick with Borland C++ but I have a problem:
    When I set URL to “http://localhost” the browser try to surf and a “404 error” page is displayed.
    How can I avoid this odd problem? Using Delphi it doesn’t occurres?
    Thanks for your time and for sharing.
    Lapo

    • Jason says:

      I haven’t seen a 404, but I have seen a dns error show for a moment before the map loads, but I only started noticing it and started using opendns.com for my dns which may have something to do with it.
      Fooling the page to think it is http://localhost was an easy way to make working demo code available without giving out my API key, but it does not comply with the google maps API Terms of Service (9.1 Free, Public Accessibility to Your Maps API Implementation), so if it’s anything more than a demo program, you really should be using an API key and a public website to host the site.

  5. Ciuly says:

    I was looking for somehting else when I found this and I figured I shodul turn on some lights:

    >> Indy kept throwing “HTTP/1.1 302 Found.”
    that is because you forgot to set HandleRedirects to true.

    I’m off to my searching now…

  6. simon chen says:

    hi:
    can you give a delphi 7 version, my ERP system programmed in delphi 7

    • Jason says:

      I don’t use Delphi 7, nor am I interested in doing so.

    • Thomas Nitzschke says:

      Hi Simon,
      this is an old question. But I program currently a framework by which the entire Google Maps API V3 is available with Delphi. This no JavaScript and no HTML knowledge is required. It is free for personal use.

      It has been tested with:
      – Delphi 5
      – Delphi 7
      – Delphi 2005 PE
      – (Turbo) Delphi 2006
      – Delphi 2010
      – Delphi XE

      Sorry: Currently there are still all comments in German, will follow English.

      http://www.delphipraxis.net/157004-google-maps-ueber-com-component-object-model.html

      • Anthony says:

        Hi Thomas,
        I was trying to download your sample projects such as Simplemap.zip in your link above.
        However, I got the below error which was translated to English by Google.

        ============
        Anthony, You have no rights to access this page. The reasons could e.g. be responsible for:

        You’re trying to change the contribution of another user, or access to administrative functions. Please check the forum rules that you must take this action.
        If you tried to write a review, it may be that your account has been disabled or will be enabled.
        =============

        So I opened up the account in your site with translation of google.com.
        However, I am still having a problem to download the files from your page.

        Can you please help me out?

        Thanks.

        • Thomas Nitzschke says:

          Hi Anthony,

          write to tngab(at)t-online(dot)de and I’ll send the samples via email.
          Regards Thomas

          • Francisco Dueñas says:

            Hi Thomas, I’m having the same problem as Anthony, JNo german knowledge and when trying to register the same erro occurs. Can I write you to your mail so you can send me you package?

            BTW, does the component can manage onlick events so I can get the Lat, Lon coordinates when you click on a map? so i can make a Database search for example?

            Thanks and Regards

  7. Anthony says:

    Hi all,
    I am trying to catch what marker in the map over TWebBrowser is clicked from Delphi.
    Let’s say, there are 500 markers for terminals in the map, and once I click one of markers, and I will see the id of this marker in a TLabel control. And I will retrieve all the info for this marker such as IP address, terminal ID, and mobile number.

    Can I get any details from Delphi when I click one of markers?

    Thanks for your comments.

    • Thomas Nitzschke says:

      Hi Anthony,
      the markers was created with Delphi or an external HTML file with markers loaded?
      The question is whether the data (ID, IP, Terminal ID, …) already in Delphi exists and there must be only respond to the OnClick-Event or data (ID, IP, TerminalID…) from JavaScript objects must be extracted?

  8. Anonymous says:

    [...] [...]