Pilotage de MapInfo par Delphi

AbdelHakim KELLOUCHE [Just-Soft]

Cet article présente comment piloter le Système d'Informations Géographiques (SIG) MapInfo via Delphi. Il se contente de donner les grandes lignes de l'exécution de MapInfo, de passer des commandes, de récupérer des données et de le personnaliser.

Grâce au pilotage de MapInfo, il est aisé de créer son propre SIG selon les spécificités du projet à réaliser.
Commentez cet article : Commentez

- Titre : Pilotage de MapInfo par Delphi

- Auteur : AbdelHakim KELLOUCHE [Just-Soft]

- Parution : 13 mai 2009

- Mise à jour : 30 mars 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2009 AbdelHakim Kellouche. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Les SIG en quelques lignes

- II-A. Vocation d'un SIG

- II-B. Quelques domaines d'application des SIG

- III. Pourquoi MapInfo ?

- IV. But

- V. Visionneuse de cartes MapInfo

- VI. Pourquoi ?

- VII. Qu'est-ce qu'une carte ?

- VIII. Éléments de notre application

- IX. Instanciation de l'objet MapInfo

- X. Description

- X-A. Un mot sur MapBasic

- X-B. Méthodes et propriétés de l'objet MapInfo

- X-C. Procédure Do

- X-D. Fonction Eval

- XI. Préparation de l'affichage

- XI-A. La ToolBar « tbMenu »

- XI-B. Le Panel « pnlLayer »

- XI-C. Le Panel « pnlMapper »

- XI-D. Source

- XII. Améliorations

- XIII. Avertissement

- XIV. Conclusion

- XV. Remerciements

- XVI. ANNEXE : description du fichier .wor

I - Introduction

Le logiciel MapInfo est un SIG Bureautique doté d'une interface graphique conviviale de type « pointercliquer », qui permet de charger facilement des données localisées et tabulaires (littérales) et de les afficher sous forme de cartes, de tables ou de diagrammes.

MapInfo fournit les outils nécessaires pour interroger et analyser ces données et présenter les résultats sur des documents cartographiques de qualité.

En plus, d'être réputé pour être un SIG bureautique, un grand nombre d'utilisateurs le considèrent comme un bon choix pour la gestion d'une cartographie ne nécessitant pas de grands moyens. Son runtime permet, en effet, de le piloter à travers un langage de haut niveau tel que Delphi. Ce tutoriel se veut comme une introduction non exhaustive dans le domaine du pilotage de MapInfo par Delphi.

II - Les SIG en quelques lignes

C'est la traduction de l'acronyme anglais GIS, qui signifie à la fois Geographic Information Systems et Geographic Information Science. Parmi une dizaine de définition reconnue on peut dire que le SIG est un Système informatique de matériels, de logiciels et de processus conçus pour permettre la collecte, la gestion, la manipulation, l'analyse, la modélisation et l'affichage des données à référence spatiale à fin de résoudre des problèmes complexes d'aménagement et de gestion.

II-A - Vocation d'un SIG

Rassembler au sein d'un outil informatique des données diverses, localisées dans le même espace géographique,relatives à la Terre et à l'homme, à leurs interactions et à leurs évolutions respectives. La finalité d'un SIG est l'aide à la décision.

La constitution de la base de données à référence spatiale suppose un géoréférencement des données. Une fois les données acquises et structurées dans la base, l'utilisateur va pouvoir les analyser, les visualiser et les manipuler. C'est un moyen d'accéder à la compréhension d'une réalité complexe selon une approche multicouche et multiscalaire.

L'information géographique est :

- géométrique ou graphique (attachée à un système de référence) ;

- sémantique ou descriptives (attributs).

Le contenu d'une base de données (BD) à référence spatiale présente donc une vue partielle du monde (représentation particulière). La complexité du monde réel est si grande que l'on crée des modèles de la réalité qui ne sont que des représentations de cette complexité du monde réel. Les mesures et les échantillons de la base de données doivent représenter le monde de manière aussi exhaustive et consistante que possible.

II-B - Quelques domaines d'application des SIG

Les SIG sont utilisés pour gérer et étudier une gamme très diversifiée de phénomènes et de réseaux de phénomènes :

Domaine

Application

Ressources naturelles

protection des zones humides, études d'impact environnemental, évaluation du potentiel panoramique, gestion des produits dangereux, modélisation des eaux souterraines et dépistage des contaminants, études des habitats fauniques et des migrations, recherche du potentiel minier, etc.

Réseaux urbains

localisation à partir des adresses civiques, planification des transports, développement de plan d'évacuation, sélection de sites, planification et distribution des flux de véhicules, localisation des accidents, sélection d'itinéraires, etc.

Administration municipale

gestion du cadastre, zonage, évaluation foncière, gestion de la qualité des eaux, entretien des infrastructures, études d'impact environnemental, schémas d'aménagement, etc.

Gestion des installations

localisation des câbles et tuyaux souterrains, rééquilibrage des réseaux électriques, planification et entretien des installations, localisation des dépenses énergétiques, etc.

Commerce

analyse de la structure des marchés, planification des développements et ciblage des clientèles visées, analyse de la concurrence et des tendances des marchés, etc.

Santé

épidémiologie, répartition et évolution des maladies et des décès, distribution des services sociaux-sanitaires, plans d'urgence.

Protection de l'environnement

étude des changements globaux, suivi des changements climatiques, biologiques, morphologiques, océaniques, etc.

III - Pourquoi MapInfo ?

Sans doute parce que je le maitrise. De plus, il est livré en une seule application contrairement à ArcGIS qui est un ensemble de modules très complet, mais aussi plus difficile à mettre en œuvre et à piloter (avis personnel).

IV - But

Il est tout à fait possible de contrôler MapInfo 4 et plus via un langage de haut niveau tel que Delphi. Par exemple, vous pouvez intégrer une fenêtre MapInfo dans une application Delphi. Pour être plus précis, il s'agit d'intégrer des éléments de MapInfo dans une autre application. Vous allez trouver qu'il est relativement facile d'intégrer MapInfo dans vos applications sans, avoir à passer par MapBasic le langage accompagnant MapInfo. Cette technique permet aussi de personnaliser votre MapInfo qui peut être très différent de l'interface MapInfo connu. Une fois MapInfo intégrée, l'utilisateur peut interagir avec votre fenêtre comme s'il était sous MapInfo, la seule contrainte étant ce que vous lui avez proposé comme routines. Nous allons à travers ce tutoriel vous apprendre comment réaliser une application de navigation cartographique en se basant sur le noyau MapInfo. On personnalisera entre autres le menu contextuel de MapInfo.

La démarche à suivre est la suivante :

- instancier un objet automation via une variable type OleVariant : pour rappel, les types OleVariant [peuvent contenir des interfaces, dont les méthodes et les propriétés peuvent être accédées grâce à eux] ;

- ouvrir un document MapInfo ;

- intercepter les couches constituant le document MapInfo chargé pour visualisation ;

- afficher les informations de la couche sélectionnée ;

- utiliser des méthodes Do et Eval ;

- envoyer de commandes à MapInfo (Do) ;

- récupérer des informations depuis MapInfo (Eval).

À la fin de ce tutoriel, notre petit navigateur ressemblera à ceci :

V - Visionneuse de cartes MapInfo

Il faut voir ce tutoriel comme un training de pilotage. Et si vous êtes tenté par le pilotage de MapInfo via Delphi c'est un bon début pour perfectionner une visionneuse qui aura la caractéristique principale d'être légère.

VI - Pourquoi ?

Imaginons un moment que vous ayez des documents à présenter, nul besoin d'ouvrir MapInfo avec toute sa panoplie d'outils, avec juste une petite application, le show est assuré. Autre avantage d'un tel choix, votre entreprise ou établissement veut donner la possibilité à d'autres employés de bénéficier d'un navigateur cartographique, sans pour autant leur donner la possibilité de modifier les données qu'elles soient textuelles ou graphiques. Une application pareille à trois avantages incontournables :

- personnalisation des fonctions ;

- légèreté ;

- contrôle des mises à jour des données.

VII - Qu'est-ce qu'une carte ?

Une carte modélise les objets du monde réel en utilisant des formes géométriques (entités cartographiques) et en leur associant des caractéristiques de représentation graphiques (symboles) qui permettent de les distinguer.

Les cartes peuvent être pensées comme des clichés de la réalité dans lesquelles seules les caractéristiques significatives (déterminés par le cartographe) sont représentées. Représentation simplifiée et schématisée de la réalité, les cartes permettent l'étude thématique d'un territoire. Par exemple, une carte des cours d'eau devrait probablement inclure tous les ruisseaux, les lacs, les canaux, les sources et ainsi de suite, localisés dans la zone de l'étude cartographique, cette carte devrait aussi probablement contenir les routes principales et les divisions administratives, ainsi que les repères importants, mais ne contiendrait probablement pas le type de végétation, le sol, les routes et voies ferrées secondaires ou les parcelles recensées.

VIII - Éléments de notre application

L'application est constituée d'une forme principale qu'on a appelée « visionneuse ». Celle-ci sert, principalement, à afficher et à manipuler les tables MapInfo. Dans ce qui suit, nous allons détailler cette forme ainsi que les éléments qui la constituent. Notre forme contient une ToolBar et deux Panels ; l'un pour visualiser le document MapInfo et l'autre pour voir l'affichage des couches interceptées avec l'application de quelques fonctions primaires telles que sélection, déplacement, zoom, etc.

Chacune des trois zones de ce mininavigateur mérite une explication. Mais commençons par le commencement.

IX - Instanciation de l'objet MapInfo

Pour l'instanciation d'un objet automation, on utilise la fonction CreateOleObject de l'unité ComObj. La syntaxe de cette fonction est la suivante : CreateOleObject (constClassName : string) : Idispatch. À ce sujet, l'aide de Delphi 7 donne les précisions suivantes : CreateOleObject crée un objet unique non initialisé de la classe spécifiée par le paramètre ClassName. ClassName spécifie la représentation sous forme de chaine de l'identificateur de classe (CLSID). CreateOleObject est utilisée pour créer un objet du type spécifié lorsque le CLSID est connu et lorsque l'objet est sur serveur local ou en processus. Seuls les objets qui ne font pas partie d'un agrégat sont créés avec CreateOleObject. L'appel de cette fonction est fait, tout naturellement, dans la méthode OnCreate de notre forme.

code création

procedure TfmVisionneuse.FormCreate(Sender: TObject);
var
MsgString: String;
begin
Vue := 0;
// Instanciation de l'objet MapInfo.
try
OleMapInfo := CreateOLEObject('MapInfo.Application');
except
begin
ShowMessage('Impossible de démarrer l''application' + #13
+ 'MapInfo ou runtime MapInfo est requis pour faire démarrer l''application');
Application.Terminate;
end
end;
...
end;

OleMapInfo est une variable globale de type OleVariant. Notre code est protégé par un try … except …end pour gérer une éventuelle erreur d'instanciation. À ce stade, si notre programme ne retourne pas de message d'erreur, notre objet est instancié et n'attend qu'à être exploité.

X - Description

Le pilotage de MapInfo se fait par l'envoi de commandes MapBasic par notre application, et ce, grâce à la technologie OLE comme il peut-être fait en utilisant DDE. À ce stade, MapInfo exécute ces commandes comme si elles étaient saisies dans le volet MapBasic (voir ci-dessous). En plus des commandes MapBasic connues vous avez besoin dans le cas d'un pilotage d'invoquer des commandes supplémentaires par exemple 'Next Document Parent' pour faire passer la fenêtre carte à votre programme. Cette technique est connue sous le nom de « reparenting ». Vous pouvez cloner les fenêtres carte, consultation de données, graphe, couches et légende.

X-A - Un mot sur MapBasic

1. Tapez la commande.

2. Appuyez sur « ENTRÉE ».

MapInfo exécute la commande. Si vous n'obtenez pas le résultat escompté, modifiez l'énoncé de la commande en supprimant des éléments, en ajoutant de nouveaux éléments ou en modifiant l'ordre des éléments. J'avoue que cette technique est bien adaptée pour apprendre les commandes générales de MapInfo. Dans un second temps, l'aide MapBasic sera indispensable pour une maîtrise et un perfectionnement de l'utilisation des commandes.
Pour en avoir la certitude, voici ci-dessous une capture d'écran MapInfo dans laquelle on voit clairement des commandes MapBasic passées sous forme de chaines de caractères reconnues par le système.
Dans le cas d'un pilotage, pour faire passer des commandes MapBasic vous utilisez la méthode Do. MapInfo exécute la commande passée sous forme de chaine de caractères comme si vous l'aviez tapée à la main dans la fenêtre MapBasic de MapInfo. Note : il existe des commandes MapBasic qui ne sont pas exécutées dans la fenêtre MapInfo. Pour connaitre les restrictions de ces appels, veuillez consulter l'aide MapBasic.

X-B - Méthodes et propriétés de l'objet MapInfo

Comme tout objet OLE, le nôtre possède des méthodes et propriétés, une petite consultation de fichier MapInfo_tlb.pas montre ce qui suit :

IMapInfo = interface(IUnknown)
['{1D42EC62-7B28-11CE-B83D-00AA002C4F58}']
function Get_Application: IDispatch; stdcall;
function Get_Parent: IDispatch; stdcall;
function Get_Name: WideString; stdcall;
function Get_FullName: WideString; stdcall;
function Get_Version: WideString; stdcall;
function Get_Visible: WordBool; stdcall;
procedure Set_Visible(Param1: WordBool); stdcall;
function Get_LastErrorCode: Integer; stdcall;
procedure Set_LastErrorCode(Param1: Integer); stdcall;
function Get_LastErrorMessage: WideString; stdcall;
function Get_MBApplications: IDispatch; stdcall;
procedure Do_(const command: WideString); stdcall;
function Eval(const expression: WideString): WideString; stdcall;
procedure RunCommand(const command: WideString); stdcall;
procedure RunMenuCommand(id: SYSINT); stdcall;
function DataObject(windowID: Integer): IUnknown; stdcall;
procedure SetCallback(const callbackobject: IDispatch); stdcall;
function Get_ProductLevel: Integer; stdcall;
function Get_MIMapGen: IDispatch; stdcall;
end;

Nous allons détailler deux méthodes très fréquentes dans notre cas, il s'agit de la procédure sans retour Do et de la fonction Eval.

X-C - Procédure Do

Cette procédure permet de transmettre toutes les commandes valables à MapInfo pour que celui-ci les exécute. Par exemple, si vous voulez ouvrir une table rien de plus simple :

msg := 'Open Table' + nom _table;
MapInfo.Do(msg);

Avec msg chaine de caractères et MapInfo type Olevariant. En règle générale, quand vous utilisez la méthode Do, MapInfo exécute ces commandes comme si vous les aviez saisies dans la fenêtre MapBasic.

X-D - Fonction Eval

Cette fonction permet d'avoir en retour une information selon la commande passée en argument. La valeur retournée est de type chaine de caractères tout comme l'argument. Cette valeur peut-être exploitée pour un usage ultérieur. Par exemple, si vous voulez déterminer la valeur retournée par la fonction WindowID(0) voici la façon de procéder :

var result : String
result = mapinfo.Eval('WindowID(0)')

Quand vous utilisez la fonction Eval, MapInfo interprète la chaine de caractères comme étant une commande MapBasic, et retourne le résultat sous forme d'une chaine de caractères. À noter que si l'expression et type logique le résultat est « T » ou « F ».

XI - Préparation de l'affichage

Pour afficher une carte MapInfo dans notre panel « pnlMapper » celui-ci devra être capable de recevoir les commandes MapInfo. Donc, c'est dans cet espace que notre fenêtre exécutera les commandes MapInfo. Pour ce faire voici la commande prévue :

Set Application Window sWinHand

La commande Set Window détermine quelle fenêtre sera le parent de toutes les autres fenêtres et boites de dialogues MapInfo. sWinHand est un entier représentant le handle de la fenêtre parent. Dans notre cas c'est bien le panel « pnlMapper ». On récupère notre entier par l'appel de la fonction standard de la bibliothèque system Str :

Str(pnlMapper.Handle, sWinHand);

L'exécution de cette commande est faite via l'appel à la méthode Do. Cette méthode joue un rôle important, on lui passe en paramètre une commande valide sous forme d'une chaine de caractères, à l'exécution, notre objet réalisera ce qui lui a été demandé, si la commande passée n'est pas reconnue comme étant une commande MapInfo valide, une erreur sera générée.
Voici le code complet permettant de préparer notre fenêtre pour accepter l'exécution des commandes qui lui seront passées.

Str(pnlMapper.Handle, sWinHand);
// Préparation de l'affichage nécessaire sinon aucune vue ne sera présente
MsgString := 'Set Application Window ' + sWinHand +
'Set Window Info Parent ' + sWinHand +
'Set Window Info ReadOnly '+
'Set Next Document Parent ' + sWinHand + ' Style ' + IntToStr(WIN_STYLE_CHILD);
OleMapInfo.Do(MsgString);
'Set Window Info Parent ' + sWinHand +

Vous voyez bien que la seule différence réside dans le passage de « info Parent + sWindHand ». Cette commande permet de faire apparaître la fenêtre info dont le parent est le handle passé par sWindHand en l'occurrence notre fenêtre MapInfo (onlMap).

'Set Window Info ReadOnly '

Afin d'empêcher la modification des attributs lors d'une demande des informations d'une couche particulière, la fenêtre Info doit être en lecture seule.

'Set Next Document Parent ' + sWinHand + ' Style ' + IntToStr(WIN_STYLE_CHILD);

Ayant fini avec les fenêtres dont nous avons besoin, plus rien qu'à dire à notre application que notre document MapInfo doit être affiché dans la fenêtre préparée à cet effet. Et oui vous avez compris, un petit F1 sur l'aide MapBasic pour avoir une idée sur les commandes qui ont été passées sans trop de détails. En effet, le but de ce tutoriel n'est pas de donner tous les détails des commandes MapBasic, mais plutôt une introduction du pilotage de MapInfo par Delphi.
Le plus dur étant fait, pour l'affichage d'un document MapInfo il n'y a plus grand-chose à dire, la commande appropriée est :

MsgString := 'Run Application "' + Doc_carte + '"';
OleMapInfo.Do(MsgString);

Avec Doc_carte le chemin complet du document à afficher ! Le résultat obtenu est comme celui-ci.

Maintenant, passons en revue les trois volets de notre petite application.

XI-A - La ToolBar « tbMenu »

La ToolBar regroupe six boutons de type « TToolButton ». Chacun d'eux prend en charge une fonction de base du SIG MapInfo :

- tbOuvrir : permet de naviguer dans les dossiers et de choisir un document MapInfo (*.wor) (voir la description du format *.wor) pour l'afficher dans la visionneuse. Un document MapInfo est constitué de commandes, c'est d'ailleurs ces « commandes » qui vont être manipulées par notre visionneuse, donc une bonne connaissance de ces commandes est nécessaire pour être capable de les appeler via des méthodes appropriées telles que Do et Eval.

- tbSelection : permet de sélectionner une région (polygone), une ligne ou un point. La multi sélection est prise en charge avec comme contrainte multi sélection dans la même couche (on parle le plus souvent de tables dans MapInfo). Ceci est d'ailleurs très correct puisque les objets sont regroupés par table.

- tbDeplacement : lorsqu'on a une vue étendue qui ne tient pas en totalité sur notre écran, on a besoin à un moment donné de visualiser une partie « cachée » c'est le rôle de ce bouton d'ailleurs très présent dans bon nombre d'applications (par exemple AutoCad).

- tbZoomAvant : agrandissement de la vue ; en relation avec l'échelle puisque c'est un SIG donc pas de problème avec la résolution de votre écran.

- tbZoomArrire : effet inverse du bouton tbZoomAvant.

- tbInfo : cet outil est très pratique du fait qu'il affiche l'information de la table de données. Notons, en même temps, que si on pointe sur une zone où sont superposés plusieurs objets, notre outil nous propose autant de couches que d'objets et à la sélection de la couche s'affichent les informations concernées.

une couche, au sens MapInfo, est constituée de plusieurs fichiers dont le plus important est celui stockant la structure de la couche. Ce fichier est un fichier texte que l'on peut éditer à l'aide de n'importe quel éditeur. Un autre fichier pas moins important et celui stockant les données.

Voici un extrait d'une table MapInfo, l'extension du fichier est .tab :

!table
!version 300
!charset WindowsLatin1

Definition Table
Type NATIVE Charset "WindowsLatin1"
Fields 3
Id_iris Char (9) Index 1 ;
PSDC99 Integer ;
MENAGES99 Integer ;

Comme nous disposons de six boutons sur la ToolBar, chacun d'eux doit avoir un travail à faire. Prenons l'exemple du bouton sélection (icône flèche), son rôle est de mettre en couleur différente l'objet sélectionné qui peut être un polygone (région), une ligne (route) ou un point (aéroport). L'appel des éléments de menu se fait en invoquant son numéro (Number) ou son identifiant (Identifier Code). Au passage, signalons que les identifiants sont précisés dans l'aide de MapInfo dont voici un extrait :

Main Toolbar Buttons

Number

Identifier Code

Select

1701

M_TOOLS_SELECTOR

Marquee Select

1722

M_TOOLS_SEARCH_RECT

Radius Select

1703

M_TOOLS_SEARCH_RADIUS

Boundary Select

1704

M_TOOLS_SEARCH_BOUNDARY

Zoom In

1705

M_TOOLS_EXPAND

Zoom Out

1706

M_TOOLS_SHRINK

Grabber

1702

M_TOOLS_RECENTER

Info

1707

M_TOOLS_PNT_QUERY

Label

1708

M_TOOLS_LABELER

Ruler

1710

M_TOOLS_RULER

Drag Window

1734

M_TOOLS_DRAGWINDOW

La syntaxe est la même pour chacun des éléments, seul l'identifiant diffère :

Partie ToolBar

procedure TfmVisionneuse.tbSelectionClick(Sender: TObject);
begin
// Sélection
OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_SELECTOR));
end;

procedure TfmVisionneuse.tbDeplacementClick(Sender: TObject);
begin
// Déplacement
OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_RECENTER));
end;

procedure TfmVisionneuse.tbZoomAvantClick(Sender: TObject);
begin
// Zoom avant
OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_EXPAND));
end;

procedure TfmVisionneuse.tbZoomAriereClick(Sender: TObject);
begin
// Zoom arrière
OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_SHRINK));
end;

procedure TfmVisionneuse.tbInfoClick(Sender: TObject);
begin
// Info
OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_PNT_QUERY));
end;

Avouez que l'utilisation de l'identifiant est plus pratique que le numéro. Les deux lignes suivantes ont le même rôle, mais la première est plus parlante !

OleMapInfo.do('Run Menu Command '+ IntToStr(M_TOOLS_SELECTOR));
OleMapInfo.do('Run Menu Command 1701);

XI-B - Le Panel « pnlLayer »

Ce volet sert à afficher les couches constituant le document en cours ainsi qu'une description de la couche sélectionnée ; on y trouve le nom de la couche, sa projection, son type (table, image, requête ou vue), le nombre de colonnes (champs) et le nombre de lignes (enregistrements). En premier lieu, on commence par avoir le nombre de couches puis dans une boucle on récupère le nom de chacune des couches constituant notre document. Voici le de code responsable de ça :

// Recherche du nombre de tables ouvertes dans la vue carte
MsgString := 'MapperInfo(' + IntToStr(hDoc) + ',' + IntToStr(MAPPER_INFO_LAYERS) + ')';
MsgString := OleMapInfo.Eval(MsgString);
nb_Table := StrToInt(MsgString);

// Liste des tables ouvertes
lbCouches.Clear;
lbCouches.Height := (lbCouches.Font.Size + 6) * nb_Table;
for i := 1 to nb_Table do
begin
MsgString := 'LayerInfo(' + IntToStr(hDoc) + ',' + IntToStr(i) + ',' + IntToStr(LAYER_INFO_NAME) + ')';
MsgString := OleMapInfo.Eval(MsgString);
lbCouches.Items.Add(MsgString);
end;

Avant de passer au code, j'attire votre attention sur la variable hDoc de type entier. En fait, celle-ci sert à récupérer le handle de la fenêtre qui va servir à l'affichage de la vue. D'ailleurs voici le de code responsable de cette capture :

// Interception de la fenêtre carte
hDoc := OleMapInfo.Eval('WindowID(' + IntToStr(Vue) + ')');

La variable Vue de type entier est initialisée à 1 et est incrémentée à chaque ouverture d'un nouveau document. Maintenant, voyons de plus près les commandes MapBasic méritant une petite explication à savoir MapperInfo et LayerInfo. MapperInfo est une fonction retournant des informations sur la fenêtre carte, sous-entendu celle qui est chargée d'afficher notre carte. Il est tout à fait possible d'avoir des informations d'autres fenêtres MapInfo en spécifiant l'identifiant de la fenêtre considérée. Dans ce tutoriel nous avons travaillé jusque là avec la fenêtre carte (Map window), il existe d'autres fenêtres spécialisées telles que celle chargée d'afficher la légende ou les attributs d'une ou de plusieurs entités. Les informations que peut retourner cette fonction sont riches et constituent une mine d'or. Ces attributs sont définis dans le fichier MAPBASIC.DEF, voici un petit extrait de l'aide MapBasic sur les attributs de cette fonction :

attribute setting

MapperInfo( ) Return Value

MAPPER_INFO_AREAUNITS

String representing the map's abbreviated area unit name, e.g. « sq mi » for square miles.

MAPPER_INFO_CENTERX

The x-coordinate of the Map window's center.

MAPPER_INFO_CENTERY

The x-coordinate of the Map window's center.

MAPPER_INFO_COORDSYS_CLAUSE

String result, indicating the window's CoordSys clause.

MAPPER_INFO_COORDSYS_CLAUSE_WITH_BOUNDS

String result, indicating the window's CoordSys clause including the bounds.

La fonction LayerInfo retourne les informations sur une des couches constituant notre carte MapInfo. Tout comme la fonction précédente, l'information en retour est spécifiée dans le fichier MAPBASIC.DEF.

Une dernière chose sur ce volet, le fait de cliquer sur l'une des couches interceptées provoque l'affichage de quelques informations, bien utiles, de cette couche. Voici le code de l'évènement OnClick du composant ListBox contenant les couches de notre document.

Info Layer

procedure TfmVisionneuse.lbCouchesClick(Sender: TObject);
var
MsgString : string;
Nom, Projection, TypeTable, Nb_Champs, Nb_Enr : string;
begin
if lbCouches.ItemIndex < 0 then
MsgString := 'LayerInfo(' + IntToStr(hDoc) + ',' + IntToStr(1) + ',' + IntToStr(LAYER_INFO_NAME) + ')'
else MsgString := 'LayerInfo(' + IntToStr(hDoc) + ',' + IntToStr(lbCouches.ItemIndex + 1) + ',' + IntToStr(LAYER_INFO_NAME) + ')';

Nom := OleMapInfo.Eval('TableInfo(' + MsgString +  ',' + IntToStr(TAB_INFO_NAME) + ')');
Projection := OleMapInfo.Eval('TableInfo(' + MsgString +  ',' + IntToStr(TAB_INFO_COORDSYS_CLAUSE) + ')');
TypeTable := OleMapInfo.Eval('TableInfo(' + MsgString +  ',' + IntToStr(TAB_INFO_TYPE) + ')');
Nb_Champs := OleMapInfo.Eval('TableInfo(' + MsgString +  ',' + IntToStr(TAB_INFO_NCOLS) + ')');
Nb_Enr := OleMapInfo.Eval('TableInfo(' + MsgString +  ',' + IntToStr(TAB_INFO_NROWS) + ')');

// remplissage des infos générales sur la table sélectionnée
sgInfoTable.Cells[1, 0] := Nom;
sgInfoTable.Cells[1, 1] := Projection;
case StrToInt(TypeTable) of
1 : sgInfoTable.Cells[1, 2] := 'Table MapInfo';
2 : sgInfoTable.Cells[1, 2] := 'Requête';
3 : sgInfoTable.Cells[1, 2] := 'Image Raster';
4 : sgInfoTable.Cells[1, 2] := 'Vue';
else sgInfoTable.Cells[1, 2] := 'Inconnu';
end;
sgInfoTable.Cells[1, 3] := Nb_Champs;
sgInfoTable.Cells[1, 4] := Nb_Enr;
end;

Dans ce code on a utilisé une autre fonction MapBasic aussi intéressante que LayerInfo, il s'agit de la fonction TableInfo. À ce niveau, il faut savoir qu'il y a une nette différence entre la couche (layer) et table. La plupart des utilisateurs du SIG MapInfo confondent souvent ces deux notions. Voilà d'ailleurs un autre avantage du développement d'outils spécifiques, il nous permet d'aller au bout des définitions.
Comme précédemment voici quelques informations que l'on peut récupérer grâce à cette fonction :

attribute code

TableInfo( ) returns

TAB_INFO_COORDSYS_CLAUSE

String result, indicating the table's CoordSys clause, such as « CoordSys Earth Projection 1, 0 ». Returns empty string if table is not mappable

TAB_INFO_COORDSYS_MINX, TAB_INFO_COORDSYS_MINY, TAB_INFO_COORDSYS_MAXX, TAB_INFO_COORDSYS_MAXY

Float results, indicating the minimum or maximum x or y map coordinates that the table is able to store; if table is not mappable, returns zero

TAB_INFO_COORDSYS_NAME

Float results, indicating the minimum or maximum x or y map coordinates that the table is able to store; if table is not mappable, returns zero

TAB_INFO_EDITED

String result, representing the name of the CoordSys as listed in MAPINFOW.PRJ (but without the optional « \p… » suffix that appears in MAPINFOW.PRJ). Returns empty string if table is not mappable, or if CoordSys is not found in MAPINFOW.PRJ

TAB_INFO_EDITED

Logical result; TRUE if table has unsaved edits

TAB_INFO_FASTEDIT

Logical result; TRUE if the table has FastEdit mode turned on, FALSE otherwise. (See Set Table for information on FastEdit mode.)

TAB_INFO_MAPPABLE

String result indicating the name of the table containing graphical objects. Use this code when you are working with a table that is actually a relational join of two other tables, and you need to know the name of the base table that contains the graphical objects

TAB_INFO_MINX, TAB_INFO_MINY, TAB_INFO_MAXX, TAB_INFO_MAXY

Float results, indicating the minimum and maximum x- and y-coordinates of all objects in the table

TAB_INFO_NAME

String result, indicating the name of the table

XI-C - Le Panel « pnlMapper »

Pour rappel, ce panel sert à afficher un document MapInfo. Le cas échéant, il retourne un message d'erreur signalant son incapacité d'ouvrir ledit document. L'essentiel de ce que fait ce panel a été décortiqué plus haut. Reste cependant un petit détail, c'est celui du menu contextuel qui a été personnalisé pour répondre à notre visionneuse. Comme il est question d'un simple affichage de documents MapInfo, sans permettre à l'utilisateur de modifier les données ni les graphiques, notre menu ressemblera à cette fenêtre. L'appel du menu contextuel et la personnalisation de ses éléments sont donnés dans le code suivant :

MsgString := 'Create Menu "MapperShortcut" As ' +
'"Redessiner" Calling ' + IntToStr(M_WINDOW_REDRAW) + ',' +
'"(-",' +
'"Déplacer" Calling ' + IntToStr(M_TOOLS_RECENTER) + ',' +
'"Agrandir (Zoom +)" Calling ' + IntToStr(M_TOOLS_EXPAND) + ',' +
'"Réduir   (Zoom -)" Calling '+ IntToStr(M_TOOLS_SHRINK) + ',' +
'"Vue Personnalisée (Zoom ?)" Calling ' + IntToStr(M_MAP_CHANGE_VIEW) + ',' +
'"(-",' +
'"Afficher Toute la couche" Calling ' + IntToStr(M_MAP_ENTIRE_LAYER) + ',' +
'"Zoom précédent" Calling ' + IntToStr(M_MAP_PREVIOUS) + ',' +
'"(-",' +
'"Just-Soft janvier 2009 - Pilotage de MapInfo"';
OleMapInfo.do(MsgString);

On travaille toujours avec une chaine de caractères même si celle-ci apparaît plus longue que les autres. Mais c'est toujours le même principe. On crée le menu en premier puis on lui rajoute les éléments qui nous intéressent dans l'ordre voulu ! Pour découvrir toutes les possibilités de cette fonction, je vous invite à faire un tour dans l'aide MapBasic que je trouve personnellement exhaustive pour cette fonction.

XI-D - Source

Vous pouvez télécharger les sources depuis cet emplacement source

XII - Améliorations

En guise d'exercice vous pouvez commencer par la gestion des erreurs qui a été totalement ignorée dans ce tutoriel ; couche portant un même nom, document mal formaté, document introuvable, table non associée à un fichier, etc. Dans un second lieu, si vous êtes tenté par l'écriture de routines spécifiques (méthode de calcul, itinéraire le plus court entre deux points, modèle numérique de terrain basé sur des données topographiques, etc.) alors n'hésitez pas à utiliser MapBasic qui s'intègre bien dans l'environnement MapInfo même s'il est un peu plus bas niveau que les langages de développement de nos jours.

XIII - Avertissement

Il se peut que lors de l'ouverture d'une carte, vous ayez un message d'erreur, car il semble que MapInfo exécute les commandes du fichier carte qui n'est autre qu'un fichier texte d'une façon séquentielle. Il est très courant qu'il échoue avant d'avoir terminé à interpréter toutes les lignes ! N'empêche que la partie qui a été lue à partir du fichier a tout de même été interprétée et exécutée.

XIV - Conclusion

À mon avis, le pilotage d'une application via Delphi possède beaucoup d'avantages, sans doute, le plus important c'est de ne pas avoir à réécrire du code déjà fait, mais de savoir l'utiliser, restreindre son champ d'application et personnaliser les parties spécifiques au projet. Dans cette première approche, j'espère avoir touché ces trois points et contribué à l'ouverture d'une brèche qui me semblait dans un passé proche hors de ma portée.

XV - Remerciements

Je ne saurais remercier l'équipe de Developpez qui m'a donné la chance de faire ce que j'ai toujours voulu faire.

- Un grand merci à arnolem qui a eu la gentillesse de m'ouvrir les portes de la rédaction.

- Merci à Nono40 qui fut un plaisir pour moi de l'avoir comme encadreur de ce premier travail.

- Mes remerciements vont également à ram0000 pour sa lecture avisée et ses corrections qui ont donné une touche assez spéciale à ce document.

- Comme je remercie bbil pour m'avoir supporté et orienté dans la mise en forme de cet article. sans oublier eclesia notre grand sigiste.

XVI - ANNEXE : description du fichier .wor

Regardons de plus près à quoi ressemble un document MapInfo. À l'aide de votre éditeur de texte, ouvrez le document « canada.wor » qui est dans le dossier « Canada ».

!Workspace
!Version 400
!Charset WindowsLatin1
Open Table "Capitales" As Capitales Interactive
Open Table "canada" As Provinces Interactive
Open Table "Highways" As Highways Interactive
Open Table "Villes_principales" As Villes_principales Interactive
Open Table "Villes" As Villes Interactive
Map From Capitales,Villes_principales,Villes,Highways,Provinces
Position (0,0.03125) Units "in"
Width 5.89583 Units "in" Height 3.20833 Units "in"
Set Window FrontWindow() ScrollBars Off Autoscroll On
Set Map
CoordSys Earth Projection 9, 62, "m", -96, 23, 20, 60, 0, 0
Center (307490.7913,4324173.976)
Zoom 4500 Units "mi"
Preserve Zoom Display Zoom
XY Units "degree" Distance Units "mi" Area Units "sq mi"
Set Map
Layer 1
Display Graphic
Global   Symbol (58,16711680,12,"MapInfo Cartographic",256,0)
Zoom (750, 4500) Units "mi"
Label Line Arrow Position Right Font ("Arial",5,8,0) Pen (1,2,0)
With Capital
Parallel On Auto On Overlap Off Duplicates On Offset 5
Visibility On
Layer 2
Display Graphic
Zoom (300, 750) Units "mi"
Label Line Arrow Position Right Font ("Arial",0,9,0) Pen (1,2,0)
With City
Parallel On Auto On Overlap Off Duplicates On Offset 5
Visibility On
Layer 3
Display Graphic
Zoom (0, 300) Units "mi"
Label Line Arrow Position Right Font ("Arial",0,8,0) Pen (1,2,0)
With City
Parallel On Auto On Overlap Off Duplicates On Offset 5
Visibility On
Layer 4
Display Graphic
Zoom (0, 1500) Units "mi"
Label Line Arrow Position Above Font ("Arial",0,9,0) Pen (1,2,0)
With Highway
Parallel On Auto Off Overlap Off Duplicates Off Offset 2
Visibility On
Layer 5
Display Graphic
Label Line None Position Center Font ("Arial",1,9,8388608) Pen (1,2,0)
With Province_Name
Parallel On Auto On Overlap Off Duplicates On Offset 2
Visibility Zoom (1501, 5000) Units "mi"
Set Window FrontWindow() Title "Canada"
Set Window Frontwindow() Max