Displaying a Map

The code is developed from the example. We have added code to enable selection from locations in two drop down lists or by inputting the longitude and latitude of the centre of your desired map. At the bottom of the panel you can see how long you needed to wait to view the map after making the selection.

In order to experiment with it you need to either (1) install Maciej Kaczkowski's TMapViewer component or (2) add its source files to your application folder and use our other version of the demonstration. We provide stepwise instructions for the installation on the following page.

The demonstration offers many possibilities for experimentation such as the following:
  • If you check the Debug checkbox you see a grid overlaying the selected map with data to check the values that you output.
  • You can select from a range of types of map (not all of which work for us). You could check out the cycling routes in Amsterdam, for example.
  • You can drag the map with the mouse.
  • If you check the double-buffering checkbox you change the performance of dragging.
  • You can get a feel for the distance represented by tiny changes in the latitude and longitude.
  • Inspect the cache folder inside the program folder to see the size of downloaded files.
  • Please use the code as a starting point for your own developments.

The code for the map selector demo follows a screenshot of the output.

Selection by Latitude and Longitude

Selection by Latitude and Longitude

The Pascal Code (Unit1.pas)

unit Unit1;
// Developed from the example at https://code.google.com/p/mapviewer/source/browse/example/Unit1.pas
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, kcMapViewer, kcMapViewerGLGeoNames
  {$IFDEF WIN32}, kcMapViewerDEWin32{$ELSE}, kcMapViewerDESynapse{$ENDIF WIN32};

type
  TForm1 = class(TForm)
    Button1, Button2: TButton;
    CheckBox1, CheckBox2, CheckBox3: TCheckBox;
    ComboBox1, cboLocations, cboLocs2: TComboBox;
    Edit1, edtLong, edtLat: TEdit;
    GroupBox1, GroupBox2, GroupBox3: TGroupBox;
    Label1, Label2, Label3, Label4, Label5, Label6, Label7, Label8, Label9, Label10: TLabel;
    mv: TMapViewer;
    MVGLGeoNames1: TMVGLGeoNames;
    Panel1: TPanel;
    TrackBar1: TTrackBar;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure cboLocationsSelect(Sender: TObject);
    procedure cboLocs2Select(Sender: TObject);
    procedure CheckBox1Change(Sender: TObject);
    procedure CheckBox2Change(Sender: TObject);
    procedure CheckBox3Change(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormDblClick(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
  private
    FDownloader: TCustomDownloadEngine;
    procedure DoBeforeDownload(Url: string; str: TStream; var CanHandle: Boolean);
    procedure DoAfterDownload(Url: string; str: TStream);
    procedure ShowMap(Loc: string);
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}
uses
  md5;
var
  Locs: array[0..16] of string = ('Aberdeen', 'Basingstoke', 'Birmingham', 'Brighton',
                                  'Derby', 'Exeter', 'Leeds', 'London',
                                  'Loughborough', 'Manchester', 'Northampton', 'Preston',
                                  'Sheffield', 'Shrewsbury', 'Wakefield', 'Watford',
                                  'Winchester');
  Locs2: array[0..22] of string = ('Bandung', 'Berlin', 'Bangkok', 'Belgrade', 'Bratislava',
                                   'Brussels', 'Hong Kong', 'Houston', 'Islamabad', 'Karachi',
                                   'Lahore', 'Montreal', 'Moscow', 'Mumbai', 'New Delhi',
                                   'New York',  'Paris', 'Poznan', 'Saint Petersburg',
                                   'Sao Paulo', 'Stockholm', 'Warsaw', 'Zurich');
  Lat, Long: real;
  Error: integer;

procedure TForm1.ShowMap(Loc: string);
var
  Centre: TRealPoint;
  Start: TDateTime;
  DownloadTime: real;
begin
  Start := Now;
  mv.BeginUpdate;
  MVGLGeoNames1.LocationName := Loc;
  mv.Zoom := 12;
  TrackBar1.Position := mv.Zoom;
  mv.Geolocate;
  mv.EndUpdate;
  DownloadTime := (Now - Start) * 24 * 60 * 60;
  Label10.Caption := Format('Download time: %.2f seconds', [DownloadTime]);
  Centre := mv.CenterLongLat;

  Label6.Caption := Format('Longitude: %.5f', [Centre.X]);
  Label7.Caption := Format('Latitude: %.5f', [Centre.Y]);
  edtLong.Text := Format('%.3f', [Centre.X]);
  edtLat.Text := Format('%.3f', [Centre.Y]);
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  Pixel, MouseTile: TIntPoint;
  Centre, Mouse: TRealPoint;
begin
  Pixel := mv.GetMouseMapPixel(X, Y);
  Label2.Caption := Format('Pixel: %d:%d', [Pixel.X, Pixel.Y]);
  MouseTile := mv.GetMouseMapTile(X, Y);
  Label3.Caption := Format('Tile: %d:%d', [MouseTile.X, MouseTile.Y]);
  Mouse := mv.GetMouseMapLongLat(X, Y);
  Label4.Caption := Format('Long: %.5f', [Mouse.X]);
  Label5.Caption := Format('Lat: %.5f', [Mouse.Y]);

  Centre := mv.CenterLongLat;
  Label6.Caption := Format('Long: %.5f', [Centre.X]);
  Label7.Caption := Format('Lat: %.5f', [Centre.Y]);
end;

procedure TForm1.FormDblClick(Sender: TObject);
begin
  TrackBar1.Position := mv.Zoom;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  if Sender = TrackBar1 then
    mv.Zoom := TrackBar1.Position;
end;

procedure TForm1.DoBeforeDownload(Url: string; str: TStream;
  var CanHandle: Boolean);
var
  x: string;
  f: TFileStream;
begin
  x := 'cache\'+MDPrint(MD5String(Url));
  if FileExists(x) then
    begin
      f := TFileStream.Create(x, fmOpenRead);
      try
        str.Position := 0;
        str.CopyFrom(f, f.Size);
        str.Position := 0;
        CanHandle := True;
      finally
        f.Free;
      end;
    end
  else
    CanHandle := False;
end;

procedure TForm1.DoAfterDownload(Url: string; str: TStream);
var
  x: string;
  f: TFileStream;
begin
  if not DirectoryExists('cache') then
    ForceDirectories('cache');
  x := 'cache\'+MDPrint(MD5String(Url));
  if (not FileExists(x)) and (not (str.Size = 0)) then
    begin
      f := TFileStream.Create(x, fmCreate);
      try
        str.Position := 0;
        f.CopyFrom(str, str.Size);
      finally
        f.Free;
      end;
    end;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  mv.Source := TMapSource(ComboBox1.ItemIndex);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  {$IFDEF WIN32}
  FDownloader := TMVDEWin32.Create(Self);
  {$ELSE}
  FDownloader := TMVDESynapse.Create(Self);
  {$ENDIF WIN32}

  FDownloader.OnAfterDownload := @DoAfterDownload;
  FDownloader.OnBeforeDownload := @DoBeforeDownload;
  mv.DownloadEngine := FDownloader;
  cboLocations.Items.AddStrings(Locs);
  cboLocations.ItemIndex := 0;
  cboLocs2.Items.AddStrings(Locs2);
  cboLocs2.ItemIndex := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FDownloader.Free
end;

procedure TForm1.cboLocationsSelect(Sender: TObject);
begin
  ShowMap(cboLocations.Items[cboLocations.ItemIndex]);
end;

procedure TForm1.cboLocs2Select(Sender: TObject);
begin
  ShowMap(cboLocs2.Items[cboLocs2.ItemIndex]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Centre: TRealPoint;
  Start: TDateTime;
  DownloadTime: real;
begin
  val(edtLong.Text, Long, Error);
  if Error = 0 then
    begin
      Centre.X := Long;
      val(edtLat.Text, Lat, Error);
      if Error = 0 then
        begin
          Centre.Y := Lat;
          Start := Now;
          mv.BeginUpdate;
          mv.Zoom := 12;
          TrackBar1.Position := mv.Zoom;
          mv.CenterLongLat := Centre;
          mv.EndUpdate;
          DownloadTime := (Now - Start) * 24 * 60 * 60;
          Label10.Caption := Format('Delay: %.2f seconds', [DownloadTime]);
          Label6.Caption := 'Longitude := ' + edtLong.Text;
          Label7.Caption := 'Latitude := ' + edtLat.Text;
        end
      else
        ShowMessage('Please enter a number for the latitude.');
    end
  else
    ShowMessage('Please enter a number for the longitude.');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMap(Edit1.Text);
end;

procedure TForm1.CheckBox1Change(Sender: TObject);
begin
  mv.Debug := CheckBox1.Checked;
end;

procedure TForm1.CheckBox2Change(Sender: TObject);
begin
  mv.UseThreads := CheckBox2.Checked;
end;

procedure TForm1.CheckBox3Change(Sender: TObject);
begin
  mv.DoubleBuffering := CheckBox3.Checked;
end;

end.

Code of Form (Unit1.lfm)

object Form1: TForm1
  Left = 354
  Height = 537
  Top = 121
  Width = 893
  Caption = 'Map Selector'
  ClientHeight = 537
  ClientWidth = 893
  Color = clBtnFace
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  OnMouseMove = FormMouseMove
  LCLVersion = '1.2.4.0'
  object mv: TMapViewer
    Left = 0
    Height = 537
    Top = 0
    Width = 624
    AutoZoom = True
    Zoom = 0
    Debug = False
    UseThreads = False
    GeolocationEngine = MVGLGeoNames1
    DoubleBuffering = False
    Align = alClient
    OnMouseMove = FormMouseMove
    OnDblClick = FormDblClick
  end
  object Panel1: TPanel
    Left = 624
    Height = 537
    Top = 0
    Width = 269
    Align = alRight
    ClientHeight = 537
    ClientWidth = 269
    TabOrder = 1
    object ComboBox1: TComboBox
      Left = 72
      Height = 21
      Top = 8
      Width = 192
      ItemHeight = 13
      ItemIndex = 1
      Items.Strings = (
        'None'
        'Google - Normal'
        'Google - Satellite'
        'Google - Hybrid'
        'Google - Physical'
        'Google - Physical Hybrid'
        'OpenStreetMap - Mapnik'
        'OpenStreetMap - Osmarender'
        'OpenCycleMap'
        'VE - Normal'
        'VE - Road'
        'VE - Aero'
        'VE - Hybrid'
        'Yahoo - Normal'
        'Yahoo - Satellite'
        'Yahoo - Hybrid'
        'Ovi - Normal'
        'Ovi - Satellite'
        'Ovi - Hybrid'
        'Ovi - Physical'
      )
      OnChange = ComboBox1Change
      Style = csDropDownList
      TabOrder = 0
      Text = 'Google - Normal'
    end
    object Label1: TLabel
      Left = 8
      Height = 13
      Top = 12
      Width = 45
      Caption = 'Map type'
      ParentColor = False
    end
    object CheckBox1: TCheckBox
      Left = 8
      Height = 19
      Top = 32
      Width = 51
      Caption = 'Debug'
      OnChange = CheckBox1Change
      TabOrder = 1
    end
    object TrackBar1: TTrackBar
      Left = 9
      Height = 40
      Top = 56
      Width = 148
      Max = 17
      Position = 0
      TickMarks = tmBoth
      OnClick = TrackBar1Change
      TabOrder = 2
    end
    object GroupBox1: TGroupBox
      Left = 8
      Height = 72
      Top = 264
      Width = 256
      Caption = 'Centre'
      ClientHeight = 54
      ClientWidth = 252
      TabOrder = 3
      object Label6: TLabel
        Left = 14
        Height = 13
        Top = 8
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
      object Label7: TLabel
        Left = 14
        Height = 13
        Top = 32
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
    end
    object GroupBox2: TGroupBox
      Left = 8
      Height = 73
      Top = 104
      Width = 257
      Caption = 'Screen'
      ClientHeight = 55
      ClientWidth = 253
      TabOrder = 4
      object Label2: TLabel
        Left = 14
        Height = 13
        Top = 8
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
      object Label3: TLabel
        Left = 14
        Height = 13
        Top = 32
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
    end
    object GroupBox3: TGroupBox
      Left = 8
      Height = 73
      Top = 184
      Width = 256
      Caption = 'Mouse Position'
      ClientHeight = 55
      ClientWidth = 252
      TabOrder = 5
      object Label4: TLabel
        Left = 14
        Height = 13
        Top = 8
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
      object Label5: TLabel
        Left = 14
        Height = 13
        Top = 32
        Width = 31
        Caption = 'Label2'
        ParentColor = False
      end
    end
    object CheckBox2: TCheckBox
      Left = 98
      Height = 19
      Top = 32
      Width = 59
      Caption = 'Threads'
      OnChange = CheckBox2Change
      TabOrder = 6
    end
    object CheckBox3: TCheckBox
      Left = 184
      Height = 19
      Top = 32
      Width = 79
      Caption = 'DblBuffering'
      OnChange = CheckBox3Change
      TabOrder = 7
    end
    object Button2: TButton
      Left = 176
      Height = 21
      Top = 344
      Width = 75
      Caption = 'Search'
      OnClick = Button2Click
      TabOrder = 8
    end
    object Edit1: TEdit
      Left = 8
      Height = 21
      Top = 344
      Width = 160
      TabOrder = 9
      Text = 'Kolkata'
    end
    object edtLat: TEdit
      Left = 99
      Height = 21
      Top = 442
      Width = 80
      TabOrder = 10
    end
    object edtLong: TEdit
      Left = 4
      Height = 21
      Top = 442
      Width = 80
      TabOrder = 11
    end
    object Label8: TLabel
      Left = 3
      Height = 13
      Top = 421
      Width = 64
      Caption = 'Longitude (X)'
      ParentColor = False
    end
    object Label9: TLabel
      Left = 99
      Height = 13
      Top = 421
      Width = 56
      Caption = 'Latitude (Y)'
      ParentColor = False
    end
    object Button1: TButton
      Left = 189
      Height = 21
      Top = 441
      Width = 75
      Caption = 'GoToXY'
      OnClick = Button1Click
      TabOrder = 12
    end
    object cboLocations: TComboBox
      Left = 8
      Height = 21
      Top = 376
      Width = 100
      ItemHeight = 13
      OnSelect = cboLocationsSelect
      Style = csDropDownList
      TabOrder = 13
    end
    object Label10: TLabel
      Left = 9
      Height = 1
      Top = 496
      Width = 1
      ParentColor = False
    end
    object cboLocs2: TComboBox
      Left = 128
      Height = 21
      Top = 377
      Width = 100
      ItemHeight = 13
      OnSelect = cboLocs2Select
      Style = csDropDownList
      TabOrder = 14
    end
  end
  object MVGLGeoNames1: TMVGLGeoNames
    left = 848
    top = 472
  end
end

Programming - a skill for life!

Using widgets (such as list boxes, combo boxes, string grids, DBgrids, charts and maps) and drawing on the canvas