You are hereTutorials / premiers pas

premiers pas


Premiers pas avec MSEide & MSEgui

 

par Jean-Pierre ANGHEL – 2009

 

 

 

Introduction

 

Qu'est ce que MSEide et MSEgui ?

C'est un outil de programmation visuelle qui, à l'instar du célèbre Delphi de Borland, est en langage Pascal. Licence GNU oblige, le Pascal employé ici est le FreePascal. Particularité très intéressante, la compilation des programmes se fait aussi bien sous Windows® que sous Linux en gardant le même résultat visuel sous les deux OS. L'astuce, si l'on peut dire, a consisté à construire une librairie graphique portable sur les deux systèmes en utilisant les primitives de plus bas niveau possible de ces deux systèmes : Win32 pour Windows et X11 pour Linux.

Autre particularité étonnante, c'est une seule et même personne qui est à l'origine de cet outil : un Suisse du nom de Martin Schreiber… chapeau!

 

 

 

Installation

 

Que ce soit pour Windows ou pour Linux, il faut tout d'abord installer Freepascal. Nous allons parler ici de la version 2.0 de MSEIde + MSEGui et les versions fpc 2.2.2 ou 2.2.4 du compilateur Pascal sont compatibles avec cette version. Vous trouverez sur le site www.freepascal.org les fichiers d'installation pour chaque OS, une auto-installable pour Windows et différentes versions pour Linux.

Freepascal existant en paquets Debian il ne devrait y avoir aucun problème pour l'installer sur la plupart des distributions Linux.

Tout ce qui suit a été testé sur Toutou Linux (Puppy Linux), une version ultra légère de Linux. Sur Toutou Linux vous aurez besoin en plus d'installer un linker inclus dans le paquet de dévelopement devx_411.sfs (411 étant le numéro de version de Puppy) que vous trouverez à l'adresse :

ftp://ibiblio.org/pub/linux/distributions/puppylinux/sfs-modules-4/devx_411.sfs

Ensuite téléchargez les fichiers de MSE sur le site de SourceForge. Vous trouverez tous les renseignements sur le site officiel de MSE : http://homepage.bluewin.ch/msegui/

A noter que petit à petit se construit aussi un wiki : http://wiki.freepascal.org/MSEide_&_MSEgui/

et qu'il existe depuis peu un site officiel : http://msegui.org

 

Une fois les deux fichiers mseide_bin_*.zip et mseide_msegui_src_*.zip en votre possession :

 

Sous Linux :

Extraire les fichiers dans le répertoire de votre choix : par exemple "MSE".

Lancer MSE/bin/i386-linux/mseide

Cliquer sur "Settings" - "Configure MSEide" et mettre l'alias "${MSEDIR}" à "MSE/msegui".

Cliquer sur "Project" – "Open" et choisir "MSE/msegui/apps/demo/demo.prj"

Cliquer sur "Target" – "Continue" (ou sur la flèche verte) et lancez dans le debugger.

 

Sous Windows :

Télécharger et installer le GDB debugger (voir site officiel MSE), en fait MinGW.

Extraire les fichiers de MSE dans le répertoire de votre choix : par exemple "C:/MSE".

Lancer C:/MSE/bin/i386-win32/mseide

Cliquer sur "Settings" - "Configure MSEide" et mettre l'alias "${MSEDIR}" à "C:/MSE/msegui".

Dans la même boîte de dialogue mettre l'alias "${COMPILER}" à l'adresse du fichier '.exe' du compilateur

de fpc : C:/fpc/2.2.2/bin/i386_win32/ppc386.exe

Dans la même boîte de dialogue mettre l'alias "${DEBUGGER}" à l'adresse du fichier '.exe' du fichier

GDB : C:/MSE/gdb/bin/gdb.exe

Cliquer sur "Project" – "Open" et choisir "MSE/msegui/apps/demo/demo.prj"

Cliquer sur "Target" – "Continue" (ou sur la flèche verte) pour construire "demo.exe" et lancer dans le

debugger.

 

Que ce soit sous Linux ou Windows vous obtiendrez le même résultat à savoir une fenêtre avec un simple bouton dessus doté de l'inscription "Exit".

 

 

Avant-propos.

 

Bien trop souvent les "Premiers pas avec…" se contentent d'afficher "Hello world" dans une fenêtre munie (ou non !) d'un bouton de fermeture et vous laissent vous dépatouiller tout seul pour la suite. Nous allons au contraire construire un programme entier, fonctionnel, en utilisant quelques objets de MSE. Il n'est bien sûr pas envisageable d'utiliser toutes les fonctionnalités de MSE, il faudrait un ouvrage entier. Mais à la fin de ce texte vous pourrez vous lancer plus loin, l'important étant de vous "mettre le pied à l'étrier", l'aide en ligne ou non étant à l'heure actuelle pratiquement inexistante.

Au début les explications seront donc le plus détaillées possible et s'estomperont peu à peu pour éviter les répétitions et ne s'attarderont que sur ce qui n'a pas été vu auparavant. L'analyse du code source dans l'Ide vous permettra de comprendre beaucoup de choses. L'inspecteur d'objet aussi !

Cet exemple est extrait d'un logiciel complet dédié à la généalogie ce qui explique la présence des outils bizarres et la lecture de fichiers textes dans une grille.

 

 

Premiers pas.

 

La première image que vous apervevez en lançant le programme est une image de ce style :

 

 

 

Figure 1

 

Si vous voyez un peu plus que ça, c'est qu'un programme (une démo par exemple) a déjà été exécuté et vous voyez une image de ce style :

 

 

 

 

Figure 2

 

Le bandeau supérieur indique alors entre parenthèses le titre du programme en cours.

Pour remettre tout au propre cliquez sur "Project" puis sur "Close".

Quitter le programme ("File" puis "Exit") et le relancer. L'image de la figure 1 apparaît alors.

 

Remarque :

MSE utilise un fichier d'initialisation situé pour Windows dans :

C:/Documents ans settings/nom utilisateur/Application Data/.mseide/msewi.sta

pour Linux :

root/.mseide/mseideli.sta

Ce fichier conserve la dernière appli exécutée et l'ouvre donc automatiquement au démarrage.

 

Démarrage :

Pour créer un projet, s'il y en a déjà un d'affiché sur l'écran faire comme ci-dessus : "Project"-"Close" puis/sinon faire "Project" - "New" – "From template" et sélectionner "default.prj".

Pour ouvrir un projet existant faire "Project"-"Open" et faire défiler les répertoires en s'aidant de la flèche "Up". Attention pour les habitués de Windows : un seul clic sur les icones des répertoires pour les développer!

 

Dans ce qui suit nous allons expliquer la construction d'un projet à l'aide des fichiers joints dans le répertoire "Demo" de ce tutoriel. En ouvrant le projet comme indiqué ci-dessus vous pourrez visualiser les différents fichiers dans l'IDE de MSE.

 

 

Le Menu.

 

A tout seigneur tout honneur. Commençons par l'installation d'un menu qui nous permettra ensuite, en cliquant sur ses items, de lancer diverses opérations.

Pour installer un widget sur la forme rien de plus simple : il suffit de le sélectionner dans la palette des composants ("Component palette"). A l'onglet "Dialog" choisir le widget tmainmenu. Un clic dessus, le bouton s'enfonce, un clic sur la forme et un tmainmenu est déposé sur cette dernière. Tout se joue ensuite dans l'inspecteur d'objet. Le menu va se construire en cascade en développant et fermant les propriétés, l'indentation facilite la compréhension. Pour un menu "classique", c'est-à-dire à l'horizontale, on commence par indiquer dans la propriété "submenu.count" le nombre d'en-têtes souhaitées : ici 5. Immédiatement apparaissent 5 sous menus intitulés "Item0, Item1"…etc. Ces sous-menus se conduisent comme précédemment avec des propriétés "submenu.count" et d'autres items qui font leur apparition en fonction du nombre indiqué dans le "count". En fait le premier sous-menu représente les en-têtes horizontales, et les suivants les items verticaux pour chaque en-tête.

Pour supprimer un "item" il suffit de faire un clic droit sur celui-ci et cliquer sur "Delete item".

 

Histoire d'embellir un peu la présentation on adjoint un tframe, un cadre, à chaque item.

Nous verrons par la suite comment les items répondent à un évènement.

 

 

La calculette.

 

Bien que le fichier source soit disponible nous allons faire comme s'il ne l'était pas et entrer un peu dans le détail de la construction de cette première fiche pour aider à sa compréhension.

Le but est de faire apparaître une calculette en cliquant sur l'item du menu "Outils"-"Calculette".

Nous allons donc créer une nouvelle forme : "File"- "New"- "Form" –"Dockingform".

MSEide nous demande d'entrer un nom pour l'unité qui va être créée. Appelons la "Ucalc". Nous aurons donc un fichier "Ucalc.pas" contenant l'unité avec le code que nous allons écrire et un fichier "Ucalc.mfm" qui contiendra la description de la forme pour le compilateur.

Ajoutons au fichier "main.pas", dans la description du type de la classe, la procédure suivante :

 

procedure AfficheCalc(const sender:tobject);

 

et developpons la dans la partie implementation :

 

procedure tmainfo.AfficheCalc(const sender:tobject);

var UCalc :tUCalcfo;

begin

UCalc:=tUCalcfo.create(nil); // Création d'un objet tUCalcfo

try

UCalc.show(true) // exécution de l'objet

finally

UCalc.free; // Libération de la mémoire par destruction de l'objet

end;

end;

 

Nous créons donc une instance de tUCalcfo et nous nous contentons de l'afficher. Ucalc.show(true) suffit à afficher la forme et à la rendre modale par le booléen passé en paramètre.

Il faut encore préciser au programme comment appeler cette procédure. On retourne sur la forme principale, on clique sur le tmainmenu et dans l'inspecteur d'objet on se rend à l'item appelé "Calculette". En cliquant sur l'ellipse de l'évènement "onexecute" apparaît la procédure que nous venons de taper : "AfficheCalc". Un clic pour la saisir et c'est tout ! Pendant que nous y sommes choisissons le mode d'affichage de la forme :

dans l'inspecteur d'objet attribuons à la propriété "optionwindow" la valeur "wo_message".

 

A noter :

pour "optionswindow" :

wo_popup : pendant l'exécution, cache toutes les icônes des OS windows-manager (WM), barre de titre,

boutons "Fermer/Redimenssionner, Min/Max" etc…

wo_message : identique à "wo_popup" mais permet à la fenêtre d'être fermée par le bouton "Fermer" et

d'être déplacée.

 

Compilons, exécutons et admirons la forme vide qui ne possède qu'une icône de fermeture dans le bandeau.

Posons ensuite un tlabel et 20 trichbuttons qui représenteront les touches de la calculette. Pour chaque bouton on indiquera dans la propriété "caption" les chiffres ou les symboles comme indiqué en Fig 3.

 

 

Figure 3

 

Ajoutons au fichier "main", dans la description du type de la classe, la procédure suivante :

 

procedure tUCalcfo.ButtonClick(const Sender: TObject);

begin

CalcKey(TRichButton(Sender).Caption[1]);

end;

 

et pour chaque bouton, dans l'inspecteur d'objet, attribuons à "onexecute", en cliquant sur l'ellipse, la procédure ButtonClick. Laquelle procédure récupère par transtypage le premier caractère du "caption" de chaque bouton.

 

Comme il est tout de même plus pratique de se servir du clavier numérique pour une calculette, il nous faut intercepter les évènements clavier. Ceci est fait par la procédure suivante :

 

procedure tUCalcfo.KeyDo(const Sender: TWidget; var info: keyeventinfoty);

begin

CalcKey(info.chars[1]);

end;

 

procédure qui renvoit à la même procédure "CalcKey" que les boutons. D'une façon identique nous transmettons le premier caractère de la chaîne : le premier caractère du "caption" des boutons, et le premier caractère de l'évènement clavier "info". C'est à l'évènement "onkeydown" de la forme qu'est attribuée, dans l'inspecteur d'objet, la procédure "KeyDo". Remarquez la différence de paramètres. Pour comprendre quels paramètres passer dans une procédure rien ne vaut de consulter le code source. On trouve la description de "keyeventinfoty" dans le fichier "mseguiglob.pas" :

 

keyeventinfoty = record

eventkind: eventkindty;

key,keynomod: keyty;

chars: msestring;

shiftstate: shiftstatesty;

eventstate: eventstatesty;

timestamp: cardinal; //usec

end;

 

Le résultat est affiché dans un simple tlabel dont la couleur et les caractères d'affichage sont choisis dans l'inspecteur d'objet.

Le code source de la calculette est un exemple donné, il y a longtemps, dans Turbo Pascal 6 (1990) pour la première apparition de la programmation évènementielle (Turbo Vision)… C'est simple et ça fonctionne encore !

 

A noter :
Martin Schreiber m'a fait remarqué que habituellement Linux utilise un codage utf-8 pour les caractères accentués et qu'il vaut mieux utiliser des msestring (= widestring) que des string tout court. C'est ce que j'ai donc fait dans le calendrier républicain qui suit (je ne me suis rendu compte de rien avec Toutou Linux…).
Il ne devrait pas y avoir de problèmes avec la calculette mais pour ceux qui voudraient uniformiser leur code par des msestring il faudrait coder ainsi :

 


  Number: msestring;

  uses UCalc_mfm,StrUtils;

  procedure SetDisplay(R: Real);
  var S: msestring;
  begin
   …
    if S[1] <> '-' then Sign := ' ' else
    begin
      S:=RightStr(S,Length(S)-1);
      Sign := '-';
    end;
   …
    else
    begin
      while S[Length(S)] = '0' do S:=LeftStr(S,Length(S)-1); //Dec(S[0]);
      if S[Length(S)] = '.' then S:=LeftStr(S,Length(S)-1); //Dec(S[0]);
      Number := S;
    end;
  end;

begin         { CalcKey }

#8, #27,'<' :
          begin
            CheckFirst;
            if Length(Number) = 1 then Number := '0' else                          Number:=LeftStr(Number,Length(Number)-1);
          end;

end;

 

Le calendrier Républicain.

 

Nous allons maintenant essayer un autre composant : la grille.

Le but est de construire un calendrier républicain. C'est-à-dire un calendrier qui affiche automatiquement la conversion d'une date exprimée en langage révolutionnaire en date utilisée dans le calendrier grégorien.

Grâce à lui nous verrons l'utilisation d'une tstringgrid en mode "readonly", mais avec la possibilité toutefois de sélectionner une cellule. C'est un simple calendrier, on va donc choisir une fenêtre modale.

Commençons donc par créer une nouvelle forme : "File"- "New"- "Form" –"Dockingform".

Une nouvelle forme s'affiche à l'écran. Choisissons tout de suite son mode de fonctionnement : pas besoin de mise en icône, ni d'agrandissement de fenêtre. Nous choisissons donc dans l'inspecteur d'objet la propriété "optionwindow" à laquelle nous attribuons la valeur "wo_message".

Déposons ensuite une stringgrid sur la forme. Le calendrier républicain comptait 10 jours par semaine et trois semaines par mois. Nous allons donc avoir besoin d'une ligne fixe pour indiquer les jours et 3 lignes pour les semaines.

Attribuons dons les valeurs adéquates aux propriétés :

"name" = "Calendrier Républicain" pour le titre de la fenêtre.

"datacols.count" = 10 pour le nombre de colonnes.

"fixrows.count" = 1 pour la ligne fixe indiquant les jours de la semaine.

"rowcount" = 3 pour le nombre de lignes c'est-à-dire de semaines.

Pendant que nous y sommes attribuons aussi les couleurs des lignes et de sélection :

"fixrows.count" – "coloractive" = cl_red

Ajoutons 4 boutons pour le changement de mois et d'années, et deux tlabel pour l'affichage.

Notons une nouveauté : l'affichage des bulles de renseignements sous les boutons. Celles-ci sont renseignées dans l'inspecteur d'objet dans la propriété "Hint".

 

 

 

Figure 4

 

 

 

A noter :

Freepascal prend comme origine des temps le 30/12/1899, au contraire de certaines versions de Delphi (Delphi 1 et 7 par exemple) qui débutent le 01/01/01. Ici nous soustreyons donc 38815 pour nous retrouver le 22/09/1793, sous Delphi 7 il faudrait ajouter 654779… le tout est de le savoir.

 

 

La boîte "A propos" et les messages.

 

La fenêtre "A propos" n'est là que pour montrer l'option "wo_popup". Plus de cadre, plus de boutons système etc… Un timage est déposé sur une forme, on met ses propriétés "anchors" à "true" , on charge une image en cliquant sur l'ellipse de la propriété "Bitmap" et c'est tout.

Les messages s'affichent avec la procédure

showmessage( texte )

Notons que les fenêtres de messages peuvent être redimensionnées. En fait en dehors de l'option "wo_popup" toutes les fenêtres sont redimensionnables.

 

 

L'éditeur de texte.

 

Parmi les widgets de MSE figure un objet ttextedit. C'est lui que nous allons utiliser pour visualiser des fichiers. MAIS, car il y a un gros "mais", il ne s'utilise pas tout seul. Il faut l'inclure dans un twidgetgrid !

Dans l'ordre :

  • Posons donc un twidgetgrid sur la forme principale.

  • Sélectionnons un ttextedit dans la palette des composants.

  • D'un clic droit de la souris sur le twidgetgrid faisons apparaître un pop-up menu : cliquons sur l'item "Insert component". Le twidgetgrid montre alors un embrion de colonne et un objet sélectionné en dessous. Dans l'inspecteur d'objet, et dans la fenêtre concernant le twidgetgrid, remarquons que la rubrique "datacols.count" est passée à "1" et que le premier item indique "<> ttextedit1", c'est-à-dire le nom que vous aurez attribué à l'objet ttextedit.

 

Nous pouvons maintenant utiliser la méthode "loadfromfile" de "ttextedit1" en lui passant en paramètre le nom du fichier récupéré dans la propriété " controller.filename " de "Openfiledialog1".

Nous ne nous attardons pas sur l'utilisation du tfiledialog qui est classique : on dépose un objet tfiledialog sur la forme et on l'appelle de façon normale dans le menu. La récupération du nom du fichier choisi se comprend aisément au vu du code source. A noter les propriétés " controller.captionopen = 'Ouvrir un fichier texte' " et "controller.captionsave = 'Sauver un fichier texte'" ce qui indique que l'objet peut aussi bien être utilisé en ouverture qu'en sauvegarde de fichier.

Observez dans l'inspecteur d'objet (propriété "controller.filterlist" et cliquer sur l'ellipse) la façon de mettre un filtre dans un tfiledialog et comment cela se traduit dans le fichier ".mfm".

 

 

 

Figure 5

 

Posons ensuite un tstringgrid juste en dessous du couple twigetgrid-ttextedit.

Nous allons faire d'une pierre deux coups et voir l'utilisation du ttextedit et du tstringgrid en même temps. Pour cela nous ouvrons un fichier texte dans un flux, lisons la première ligne et si cette ligne contient un caractère de tabulation (#9) c'est que c'est un tableau et nous l'ouvrons donc dans le tstringgrid. Au contraire, en l'absence de caractère #9 nous ouvrons le fichier dans le ttextedit. Vous l'aurez compris, le code source est simplissime. Il n'est là que pour argumenter quelques spécificités des composants.

 

Le tstringgrid d'abord :

La première ligne est à part des autres et est réservée pour les titres des colonnes. D'ailleurs les lignes suivantes voient leur numérotation débuter à "0". Dans le Calendrier républicain" nous avions rempli la première ligne en utilisant l'inspecteur d'objet, ici nous le faisons de façon dynamique:

 

tstringgrid1.fixrows[-1].captions[numéro colonne].caption:=nom de la colonne;

 

L'attribution de valeurs aux autres cellules se fait par l'utilisation des descriptifs de colonnes et lignes entre crochets:

 

tstringgrid1[NoCol][NoLigne]:=valeur;

 

Attention : "Col" avant "Row". Que celui qui n'a jamais interverti les deux, lève la main !

 

Le ttextedit :

Afin de ne pas avoir des séparations disgracieuses dans le texte on fixe l'épaisseur des traits du twidgetgrid à 0 :

"datarowlinewidth = 0"

"datarowheight = 15"

Ensuite le chargement du fichier se fait de façon transparente, le widget possédant la méthode "loadfromfile"

 

A noter :

Les fichiers ".txt" de test indiquent dans leurs noms la terminaison de chaque ligne : CR, LF ou CRLF pour Windows. MSE lit les trois sans problème.

Pour les sauvegardes, le ttextedit possède une méthode "savetofile" tandis qu'il faut développer une méthode pour celle du ttstringgrid.

 

La figure 6 montre à quoi ressemble le logiciel en cours d'exécution.

 

 

 

Figure 6

 

Pour la sauvegarde on utilise le même tfiledialog et sa propriété "controller.filename" qui a conservé le nom du fichier ouvert.

 

A noter :

En incluant dans la propriété "options" du tfiledialog " la valeur fdo_checkexist, si le nom du fichier existe déjà un message de confirmation est demandé automatiquement.

 

 

Conclusion.

 

Pour les nostalgiques de Delphi qui regrettent de ne plus avoir ce formidable outil de développement sous Linux, Kylix ayant disparu et n'étant d'ailleurs pas très au point, MSE est LE programme qu'il leur faut !

Quant aux programmeurs Pascal qui hésitent entre Gtk+ et Qt ils ont maintenant une troisième voie offerte et quelle voie !

 

AttachmentSize
Demo.zip50.76 KB