Plain and Simple About MapInfo and Delphi
Plain and Simple About MapInfo and Delphi
With this article, I begin a series of articles on the possibilities of integrated MapInfo
cartography and the possibility of embedding a geographic information system into
your program. Notes : All examples are distributed freely and are developed for
educational purposes on Delphi 6. See the attached source codes for all information on
how to work.
We now have access to vast amounts of information. The data is stored in spreadsheets,
trade and marketing reporting. A wealth of information about customers, stores,
personnel, equipment and resources is on paper and in computer memory. Thematic
Map containing a layer of ranges (percentage of employment) and pie charts
(production of agricultural products) Almost all of this data has a geographical
component. According to various estimates, up to 85 percent of all databases contain
some kind of geographic information.
This estimate took into account data volumes containing addresses, city names, state
names, state names, postal codes, and even phone numbers, including dial-up codes
and extensions. Desktop cartography will allow your computer to not just process data,
but to quickly and visually represent it using geographical data components so that you
can capture their general meaning reflected on maps.
How can desktop cartography work for you? MapInfo, as a desktop mapping tool, is a
powerful data analysis tool. You can give a graphical appearance to statistical and other
data. You can display your data as points, as thematic areas, pie and bar graphs,
districts, and more. Geographic operators can be applied to the data, such as zoning,
feature combination and slicing, and buffering. Data can be accessed as queries,
including access to remote databases directly from MapInfo. For example, which store
is closer to your firm's biggest customers? The map makes it easy to see features and
trends that are almost impossible to detect in list-organized data. You can easily
calculate the distances between customers and stores; you can see the location of the
office of the client who spent the largest amount over the past year; the size of the
symbols marking the location of stores on the Map may depend on the volume of sales.
All this makes the visualization of your data more visual. So a brief preface from the
user's guide gives you a general idea of MapInfo.
Integrated mapping allows you to manage the MapInfo package using programming
languages other than MapBasic. For example, if you are familiar with programming in
Visual Basic or C++ or Delphi (which will be discussed later ...), you can include a
MapInfo window in your application, thereby ensuring the integration of the MapInfo
package with the logic (business rules) of your programs.
Moreover, MapInfo (MapBasic) takes on the main work of maintaining vector maps,
and you can create and assign handlers and interaction mechanisms that are not
characteristic of MapBasic, as well as those mechanisms that MapBasic does not
directly support (for example, updating a map via the Internet, picking up information
from sensors on the territory and updating on the map, etc.)
So let's get started: in a series of articles the following things will be considered
To create an Integrated Map application, you must write a program - not a MapBasic
program. Applications with an Integrated Map can be written in several programming
languages, among which C, Visual Basic, Delphi are the most commonly used.
Your program must have a statement that runs MapInfo in the background. For
example, in a program, you can start MapInfo by calling the CreateObject() function.
MapInfo runs in the background without the user noticing it, without displaying a
splash screen. Your program controls the MapInfo program by constructing strings that
represent MapBasic language statements, which are then passed to MapInfo through
the OLE Object Engine (OLE Automation) or Dynamic Data Exchange (DDE).
MapInfo executes these statements exactly as if the user were typing them into a
MapBasic window.
Note:
System requirements
Integrated mapping requires MapInfo version 4.0 or higher on your computer. You can
use the full version of MapInfo or the so-called runtime module (a truncated version of
MapInfo supplied as the basis for specialized applications)
Your program must be able to act as an OLE Automation Controller (OLE) controller
or DDE client. The use of an OLE controller is recommended as a faster and more
reliable method than DDE. We will consider it
Integrated mapping uses the OLE management engine but does not use OLE
embedding.
Integrated cartography does not use VBX or OCX controls (this is not quite the
case - there is an OCX MapX module - for working with MapInfo GIS (not
included in the standard package), but this is no longer integrated cartography
and will not be considered).
Integrated mapping does not provide you with any header files or libraries
Integrated Mapping includes several DLLs but does not provide direct access to
them.
So let's consider the simplest component for launching and managing MapInfo
(TKDMapInfoServer), it should be noted that I did not write a specialized component -
I present the basics.
unit KDMapInfoServer;
interface
uses
ComObj, Controls, Variants, ExtCtrls, Windows, Messages,
SysUtils, Classes;
const
scMapInfoWindowClass = 'xvt320mditask100';
icWinMapinfo = 1011;
icWinInfoWindowid = 13;
type
TEvalResult = record
AsVariant: OLEVariant;
AsString: string ;
AsInteger: Integer;
AsFloat: Extended;
AsBoolean: Boolean;
end ;
// OLE server
FServer : Variant;
FHandle : THandle;
FActive : Boolean;
FPanel : TPanel;
Connected : Boolean;
MapperID : Cardinal;
MapperNum : Cardinal;
procedure SetActive( const Value: Boolean);
procedure SetPanel( const Value: TPanel);
procedure CreateMapInfoServer;
procedure DestroyMapInfoServer;
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override ;
destructor Destroy; override ;
// This procedure executes the MapInfo Server method - Do
procedure ExecuteCommandMapBasic(Command: string ; const
Args: array of const );
// This procedure executes the MapInfo server method - Eval
function Eval(Command: string ; const Args: array of
const ): TEvalResult; virtual ;
procedure WindowMapDef;
procedure OpenMap(Path : string );
published
{ Published declarations }
// Creates a connection to the MapInfo server
property Active: Boolean read FActive write SetActive;
property PanelMap : TPanel read FPanel write SetPanel;
end ;
procedure register ;
implementation
procedure register ;
begin
RegisterComponents('Kuzan', [TKDMapInfoServer]);
end ;
{ TKDMapInfoServer }
constructor TKDMapInfoServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FOwner := AOwner as TWinControl;
FHandle := 0;
FActive := False;
Connected := False;
end ;
destructor TKDMapInfoServer.Destroy;
begin
DestroyMapInfoServer;
inherited Destroy;
end ;
procedure TKDMapInfoServer.CreateMapInfoServer;
begin
try
FServer := CreateOleObject('MapInfo.Application');
except
FServer := Unassigned;
end ;
FServer.Application.Visible := True;
if IsIconic(FOwner.Handle) then
ShowWindow(FOwner.Handle, SW_Restore);
BringWindowToTop(FOwner.Handle);
end ;
procedure TKDMapInfoServer.DestroyMapInfoServer;
begin
ExecuteCommandMapBasic('End MapInfo', []);
FServer := Unassigned;
end ;
var
ds_save: Char;
begin
if Connected then
begin
Result.AsVariant := FServer.Eval(Format(Command, Args));
Result.AsString := Result.AsVariant;
Result.AsBoolean := (Result.AsString = 'T') or
(Result.AsString = 't');
if IsInt(Result.AsVariant) then
begin
try
ds_save := DecimalSeparator;
try
DecimalSeparator := '.';
Result.AsFloat := StrToFloat(Result.AsString);
//Result.AsVariant;
finally
DecimalSeparator := ds_save;
end ;
except
Result.AsFloat := 0.00;
end ;
try
Result.AsInteger := Trunc(Result.AsFloat);
except
Result.AsInteger := 0;
end ;
end
else
begin
Result.AsInteger := 0;
Result.AsFloat := 0.00;
end ;
end ;
end ;
procedure TKDMapInfoServer.WindowMapDef;
begin
ExecuteCommandMapBasic('Set Next Document Parent %D Style 1',
[FPanel.Handle]);
end ;
end .
And so we have -
Good to start
For example:
FServer := CreateOleObject('MapInfo.Application');
To connect to a previously running MapInfo instance that was not started by a call to
the CreateObject() function, use the GetObject() function.
Attention:
If you are using a Runtime version of MapInfo rather than a full copy, use
"MapInfo.Runtime" instead of "MapInfo.Application". The runtime version and the
full version can run at the same time.
The CreateObject() and GetObject() functions use the OLE Object Management (OLE
Automation) mechanism to communicate with MapInfo.
Note:
On a 32-bit version of Windows (Windows95 or Windows NT), you can run multiple
instances of MapInfo. If you run MapInfo followed by a program that uses Integrated
Mapping and calls CreateObjectf), then two independent instances of MapInfo will run.
However, in the 16-bit version, a program using Integrated Mapping with MapInfo
running will not work.
After running the MapInfo program, you must construct text strings that represent Map
Basic language statements.
For example:
Note:
When using the Do method, MapInfo executes the command line exactly as if it were
entered in the MapBasic command window.
Note:
You can pass a statement to a MapInfo program if that statement is valid in a MapBasic
window. For example, you cannot send a MapBasic Dialog statement because its use is
not allowed in a MapBasic window.
To query a MapBasic value from your client program, use the OLE method Eval.
For example:
Note:
In the component, this is implemented by the Eval procedure, but in the entity,
FServer.Eval is called
When you use the Eval method, MapInfo interprets the string as a MapBasic
expression, determines the value of the expression, and returns that value as a string.
Note: If the expression evaluates to a boolean value (type Logical), MapInfo returns a
single character string, "T" or "F" respectively.
After starting MapInfo, use the Set Application Window statement of the MapBasic
language to ensure that your client program takes control of the dialog boxes and error
messages of the MapInfo program.
Then, at the point you want to include a MapInfo window in your application, pass
MapInfo a Set Next Document statement followed by a MapBasic statement that
creates the window.
The Set Next Document statement allows you to "reparent" document windows. The
syntax of this statement requires you to specify a unique HWND number for the
control in your program. When a MapInfo document window is subsequently created
(using the Map, Graph, Browse, Layout, or Create Legend statements), the newly
created window becomes the window's parent object.
Examples are given from the component, but the same can be done with the Do method
directly, but I think you already understood this
Note:
For each window you resubordinate, you need to pass a pair of statements from your
program to MapInfo - the Set Next Document Parent statement, and then the statement
that creates the window. After the window has been created, you may need to query
MapInfo for the value of the WindowID(0) function, MapInfo's integer Window ID
number, as many MapBasic statements require this number to be specified. This query
is executed on a component basis like this:
WindowID := Eval('WindowID(%D)',[0]).AsInteger;
Note that even after reparenting the Maps window, MapInfo continues to control it. the
client program may not pay attention to messages about redrawing, I will leave the
implementation of this feature for later.
To change (subordinate) window data, the MapBasic Set Window... Parent statement is
used.
Note that the way to resubordinate the Info window is different than for the Map
window. In the latter case, the Set Next Document clause is not used. The fact is that
there can be several Map windows.
Windows Legends is a special case. Usually there is only one Legend window, as well
as one Information window. However, you can create additional Legend windows
using the MapBasic Create Legend statement.
For a single Legend window, use the MapBasic Window Legend Parent statement.
To create an additional Legend window, use the MapBasic Set Next Document
statement and the Create Legend statement. Note that in this case you are creating a
Legend that is tied to one specific Map window or Graph window. Such a Legend
window does not change when another window becomes active.
Tip:
You can create a "floating" Legend window inside the Map window. In the Set Next
Document statement, specify the Map window as the parent window. See the
MapBasic documentation for more information.
To be continued….