VI. Création de ressources▲
Les ressources sont des structures binaires stockées à la fin d'un fichier exécutable.
En principe, c'est-à -dire sauf spécification contraire lors de leur création, les ressources ne sont chargées en mémoire que lorsque le programme en a besoin.
Il existe plusieurs types de ressources, dont voici les plus courants :
- Menus
- Tables d'accélérateurs (raccourcis clavier)
- Boîtes de dialogue
- Icônes
- Bitmaps
- Curseurs
- Polices de caractères
- Tables de chaînes
- Informations de version
Pas mal d'outils RAD créent des ressources de manière complètement transparente au programmeur. Nous, nous allons les créer de toutes pièces.
Faites l'expérience d'aller visionner les ressources de programmes existants sur votre machine. Vous pouvez utiliser un utilitaire comme Resource Hacker.
On distingue d'un côté le script de ressources, qui est un fichier source avec une syntaxe relativement simple et dont l'extension est .RC,
et, de l'autre côté, le fichier binaire, qui est le résultat de la compilation du script de ressources par un compilateur de ressources et dont l'extension est .RES. C'est ce fichier binaire qui est lié à l'exécutable du programme.
En théorie, n'importe quel éditeur de texte peut permettre d'écrire des scripts de ressources. Mais en pratique, il est bien plus confortable de voir ce que l'on fait.
Assez curieusement, les éditeurs visuels permettant de créer des scripts de ressources en partant de rien ne courent pas les rues. Dans le présent tutoriel, l'éditeur de ressources utilisé est Borland Resource Workshop 4.5, qui accompagne plusieurs produits de la gamme Borland dont Borland C++, Turbo C++ et Delphi.
Dans la suite du tutoriel, nous utiliserons l'abréviation BRW.
VI-A. Utilisation de Borland Resource Workshop 4.5▲
Comme toujours, nous allons prendre appui sur un exemple pratique pour découvrir à la fois la création de différents types de ressources et l'utilisation de ces ressources dans un programme.
Le programme que nous allons réaliser contiendra :
- Un menu principal
- Une table d'accélérateurs
- Une icône
- Un curseur personnalisé
- Des bitmaps
Nous nous attaquerons aux boîtes de dialogue beaucoup plus tard dans le tutoriel.
Tout ce que le programme sera capable de réaliser sera d'appliquer comme fond de fenêtre un motif choisi par l'utilisateur. Nous l'appellerons CHGFOND.PAS.
VI-A-1. Plateforme de destination et génération des identificateurs▲
La première chose à régler est la plateforme de destination, via le menu File --> Preferences :
Vous avez deviné, il faut bien sûr sélectionner Win32 dans le groupe Target Windows version.
Ensuite, il faut décocher la case Generate identifiers automatically, ce qui nous permettra d'attribuer nous-même aux identificateurs les valeurs qui nous conviennent.
VI-A-2. Création du projet▲
Pour créer un nouveau projet, il faut sélectionner le menu File --> New Project. Un petit dialogue de choix apparaît :
BRW permet de créer et d'éditer des curseurs (.CUR), des images bitmap (.BMP), des icônes (.ICO) et des polices de caractères (.FNT).
Ce qui nous intéresse dans le cas présent, c'est de créer un script complet de ressources et donc nous sélectionnons .RC.
L'option .RES ne nous intéresse pas car nous demanderons à BRW de compiler notre script de ressources pour créer un fichier .RES.
Immédiatement après avoir coché OK, un dialogue apparaît :
Ignorez-le.
Avant toute autre chose, nous allons enregistrer notre projet... même s'il est vide. Cela permettra de lui donner un nom et ensuite de lui ajouter certaines choses.
Sélectionnez le menu File --> Save project :
Il est assez logique d'enregistrer le script dans le même répertoire que le programme auquel il est destiné. Nous lui donnons le même nom que le programme : chgfond.
A présent, nous allons demander à BRW de créer automatiquement un fichier .RES. Cela se fait dans le même dialogue que lors du choix de la plateforme de destination, c'est-à -dire par le menu File --> Preferences :
Cochez la case .RES dans le groupe Multi-save. Par défaut, le nom du fichier est déjà indiqué. Pour permettre à Virtual Pascal de lier le fichier .RES au programme, précisez le nom du dossier des ressources Win32 spécifié dans les répertoires par défaut de VP.
Sur ma configuration, c'est C:\Progra~1\VP21\Res.W32.
BRW étant un programme fort ancien, n'utilisez que des noms de dossiers au format 8.3 (MS-DOS)
VI-A-3. Ajout d'un fichier include▲
Par facilité, nous allons demander à BRW de stocker tous les identificateurs qui seront créés dans un fichier include.
Pour ce faire, sélectionnez le menu File --> Add to project :
Sélectionnez le type de fichier INC Pascal constant include et donnez également le même nom que le programme : un fichier chgfond.inc sera enregistré dans le dossier du programme.
Répondez ensuite par l'affirmative dans le dialogue de confirmation de création du fichier include.
VI-A-4. Création de bitmaps▲
Pour personnaliser le fond de notre fenêtre principale, nous allons créer deux images bitmaps (mais rien ne vous empêche d'en faire plus). Pour l'exemple, il s'agira de deux motifs qui seront automatiquement répétés par Windows pour remplir le fond de fenêtre.
Windows 95 ne supporte pas de motifs de taille supérieure à 8 pixels de côté.
Ce genre de détails est important si vous voulez assurer une compatibilité maximale à vos programmes
Utilisez le menu Resource --> New et, dans la liste des types de ressources possibles, sélectionnez BITMAP :
BRW affiche ensuite le dialogue de choix qui se trouve sur la droite du screenshot.
En fait, la question posée revient à savoir si l'image que nous allons créer doit être incluse dans le script de ressource (bouton Source) ou bien si elle doit être enregistrée dans un fichier séparé (bouton Binary).
Si la taille de l'image n'est pas très élevée, la première des deux possibilités convient très bien.
VI-A-4-a. Création complète d'une image▲
Nous allons créer nous-même une petite bitmap; sélectionnez le bouton Source :
Dans ce dialogue, nous devons indiquer les attributs de l'image, c'est-à -dire sa taille et le nombre de couleurs. Par exemple, une image de 15 pixels de côté en 16 couleurs.
Lorsque vous avez pressé OK, la fenêtre d'édition apparaît :
Si l'image de départ est aussi petite que celle du screenshot ci-dessus, vous pouvez l'agrandir via le menu View --> Zoom in ou la combinaison de touches Ctrl-Z.
La sélection d'une couleur dans la palette se fait à l'aide de la souris. Le principe suivant est valable dans toutes les fenêtres d'édition de ressources :
- Bouton gauche pour la couleur d'avant plan - notée FG (ForeGround) sur la palette
- Bouton droit pour la couleur de fond - notée BG (BackGround) sur la palette
A l'aide de l'outil cercle et de l'outil crayon, j'ai dessiné un smiley :
Pour refermer la fenêtre d'édition, pressez Ctrl-F4.
VI-A-4-b. Utilisation d'une image existante▲
La seconde bitmap, nous n'allons pas la créer nous-même mais utiliser une bitmap existante. Car nous sommes là pour apprendre.
Nous allons ajouter un fichier BMP au projet. Utilisez le menu File --> Add to project, choisissez le type BMP, RLE device-independant bitmap et sélectionnez votre fichier BMP :
Immédiatement, une seconde ressource de type bitmap est créée :
L'est mignon, hein ?
VI-A-5. Création d'un menu▲
Nous utilisons toujours le même menu Resource --> New pour créer une nouvelle ressource. Cette fois, sélectionnez le type MENU.
Voici la fenêtre d'édition du menu :
L'appellation POPUP correspond au titre d'un menu déroulant. Les commandes qui apparaissent dans la partie déroulante du menu sont appelés MENUITEMS.
Généralement, les menus qui apparaissent dans la barre de menu d'une application sont des popups mais il est possible d'y inclure directement des items. Le fait de les sélectionner provoque non pas le déroulement d'un menu mais bien l'exécution d'une commande.
Le premier popup est créé d'office par BRW et porte le libellé Popup, que nous nous empressons de modifier en &Fichier dans le champ Item text en haut à gauche.
Dans les menus, le caractère & provoque le soulignement de la lettre qui le suit immédiatement et permet d'utiliser cette lettre comme raccourci clavier avec la touche Alt
Dans notre programme, la lettre F de Fichier sera donc soulignée et l'utilisateur pourra accéder au menu Fichier en tapant Alt-F.
A présent, nous allons changer le nom du premier item créé d'office par BRW et qui porte le nom Item.
Sélectionnez la ligne MENUITEM "Item" dans la colonne de droite de la fenêtre d'édition. Vous constatez que les propriétés de la colonne de gauche sont adaptées en conséquence :
Inscrivez &Quitter dans le champ Item text. Cette fois, le caractère & permettra d'activer l'item Quitter rien qu'en tapant la lettre Q, lorsque le menu Fichier sera déroulé.
Nous allons à présent nous occuper du contenu du champ Item Id.
Contrairement aux popups, les items doivent obligatoirement recevoir un identificateur. Celui-ci peut être soit une valeur entière, soit une chaîne de caractères. Pour des raisons de performances, nous privilégierons toujours l'utilisation d'une valeur entière
Inscrivez cm_Exit dans le champ Item Id. Rappelez-vous, nous avons déjà abordé le sujet des identificateurs de messages dans le chapitre V.C.
Les identificateurs de commandes de menu portent le code mnémonique cm_.
Lorsque vous pressez Enter, BRW vous demande si vous souhaitez créer un nouvel identificateur :
Confirmez à l'aide du bouton Yes. A présent, nous pouvons attribuer une valeur à l'identificateur cm_Exit :
Inscrivez 24340. Pourquoi cette valeur ? Parce que certaines commandes de menu sont universelles dans le monde Windows.
Nous allons nous simplifier la vie car l'identificateur cm_Exit est déjà déclaré dans l'unité OWindows comme ayant la valeur 24340.
Je vous invite à vérifier la chose en regardant le contenu du fichier OWindows.inc, qui se trouve dans les sources de la bibliothèque OWL.
Un petit tableau comprenant les identificateurs standards les plus utilisés se trouve à la fin de ce chapitre.
A présent, nous allons créer un second popup. Dans la partie droite de la fenêtre, placez la surbrillance sur la directive __End Popup__ puis tapez Ctrl-P. Ce second popup, nous l'appelons F&onds.
Comme le caractère & a déjà été affecté à la lettre F du premier popup, il n'est plus question de l'affecter de nouveau à cette même lettre pour le second popup sinon, tout simplement, ce popup sera inaccessible par le raccourci Alt-F : à tous les coups, ce sera le premier popup qui sera appelé.
Nous affectons donc le & Ã une autre lettre, par exemple le O.
De la même manière que lorsque nous avons créé la commande Quitter du menu Fichier, renommez l'item créé par BRW en &Défaut et affectez-lui l'identificateur cm_FondDefaut :
Lorsque vous pressez Enter, BRW vous demande s'il faut créer ce nouvel identificateur; répondez par l'affirmative et donnez lui comme valeur 101.
Pour les identificateurs de commandes non standards, il est recommandé de donner une valeur supérieure à 100
Généralement, donc, les identificateurs commencent à 101. Certaines valeurs inférieures sont utilisées par défaut par Windows et, en les utilisant, vous risqueriez de voir votre programme effectuer ou tenter d'effectuer des actions non désirées.
Laissez la surbrillance sur le nouvel item puis tapez Ctrl-P : vous créez un sous-menu, un sous-popup. Appelez-le &Personnalisés.
Modifiez l'item créé par BRW pour qu'il s'appelle Fond &1 et donnez-lui cm_Fond1 comme identificateur, avec la valeur 102. La fenêtre d'édition ressemble maintenant à ceci :
A présent, nous allons créer un nouvel item. Laissez la surbrillance sur l'item Fond 1 et pressez Insert : un nouvel item se crée. Appelez-le Fond &2 et donnez-lui cm_Fond2 comme identificateur, avec la valeur 103.
Rien ne vous oblige bien sûr à vous arrêter là , si vous souhaitez proposer plus de motifs de fonds.
Le menu est maintenant créé; vous pouvez le tester directement en haut de la partie de droite de la fenêtre d'édition.
Pour fermer la fenêtre d'édition, pressez Ctrl-F4. Vous constatez que, dans la partie droite de la fenêtre principale, se trouve la ressource sous forme de script :
Vous voyez que la syntaxe est somme toute relativement simple. Mais le fait d'utiliser un éditeur visuel de ressources permet de voir et tester le résultat beaucoup plus facilement et rapidement.
Voici un petit résumé des combinaisons de touches rapides utilisables pour créer un menu :
- Ctrl-P pour créer un popup
- Insert pour créer un item
- Ctrl-S pour créer une ligne séparatrice
VI-A-5-a. Identificateurs standards de commandes de menu▲
Voici la liste des commandes de menu standards dans l'environnement Windows les plus utilisées :
Identificateur | Valeur | Commande |
---|---|---|
cm_FileNew | 24329 | Fichier --> Nouveau |
cm_FileOpen | 24330 | Fichier -- > Ouvrir |
cm_FileSave | 24333 | Fichier -- > Enregistrer |
cm_FileSaveAs | 24334 | Fichier -- > Enregistrer sous |
cm_Exit | 24340 | Fichier -- > Quitter |
cm_TileChildren | 24336 | Fenêtre --> Mosaïque |
cm_CascadeChildren | 24337 | Fenêtre --> Cascade |
cm_EditCut | 24320 | Edition --> Couper |
cm_EditCopy | 24321 | Edition --> Copier |
cm_EditPaste | 24322 | Edition --> Coller |
cm_EditDelete | 24323 | Edition --> Supprimer |
cm_EditUndo | 24325 | Edition --> Annuler la dernière action |
cm_EditFind | 24326 | Edition --> Rechercher |
cm_EditReplace | 24327 | Edition --> Remplacer |
cm_EditFindNext | 24328 | Edition --> Rechercher suivant |
VI-A-6. Création d'une table d'accélérateurs▲
A présent, nous allons créer quelques raccourcis clavier, appelés accélerateurs, pour commander les changements de motifs de fond de fenêtre.
Nous pouvons affecter ces accélérateurs à des commandes existantes (déjà reprises dans un menu) ou bien leur affecter de nouvelles commandes.
Lorsqu'il sont bien choisis, les accélérateurs constituent une bonne plus-value pour une application.
Evitez d'utiliser des combinaisons de touches reconnues par Windows (comme Alt-F4, Ctrl-Insert, Shift-Insert...)
Exécutez le menu Resource --> New et sélectionnez ACCELERATORS comme type de ressource. Voici la fenêtre d'édition :
Nous allons affecter un raccourci aux trois commandes du menu Fonds.
Pour la première, inscrivez cm_FondDefaut dans le champ Command puis pressez la touche de tabulation pour déplacer le curseur vers le champ Key :
BRW attend que vous exécutiez directement la combinaison de touches du raccourci. Par exemple, pressez Ctrl-d. Cliquez avec la souris ou pressez Escape pour stopper l'enregistrement.
Pour ajouter un second accélérateur, il suffit de presser Insert et de recommencer le processus.
Affectons la combinaisons de touches Ctrl-1 Ã la commande cm_Fond1 et Ctrl-2 Ã la commande cm_Fond2 :
C'est simple, non ? Pour fermer la fenêtre d'édition, pressez Ctrl-F4. Vous découvrez le script de la table d'accélérateurs créée :
VI-A-6-a. Ajout des raccourcis dans les menus▲
Il est très courant d'aider les utilisateurs d'un programme en mentionnant les raccourcis clavier dans les items de menu correspondants.
Retournez dans l'éditeur de menu (en double-cliquant sur la ressource MENU_1).
Nous allons compléter le libellé des commandes du menu Fonds en ajoutant la directive \t suivie du raccourci :
La directive \t insère une tabulation de manière que, lorsque le menu est déroulé, tous les raccourcis soient correctement alignés à droite.
VI-A-7. Création d'une icône▲
Comme pour toutes les ressources créées jusqu'à présent, utilisez le menu Resource --> New et sélectionnez ICON dans la liste des types :
Tout comme lors de la création de bitmap, BRW vous permet soit d'enregistrer l'icône directement dans le script de ressources, soit dans un fichier séparé (dialogue de droite). Sélectionnez Source.
Vous pouvez à présent choisir la résolution et le nombre de couleurs de la première icône :
Pourquoi ai-je dit "la première" ? Parce que :
Une icône n'est pas une image simple mais peut être composée de plusieurs images de résolutions et nombres de couleurs différents
Windows choisira l'image qui donnera le meilleur résultat à l'affichage.
Les possibilités proposées par BRW en matière de résolution et de nombre de couleurs sont devenues un peu obsolètes.
Pour le présent programme, je me suis contenté d'une image 32 X 32 en 16 couleurs dans un but didactique mais vous pouvez très bien expérimenter,
en utilisant le même procédé que lors de la création de la seconde bitmap, l'ajout d'un fichier .ICO au projet (menu File --> Add to project).
Non seulement une icône peut être composée de plusieurs images de résolutions et nombres de couleurs différents mais, en plus, chacune des images est constituée de deux bitmaps. La première est appelée masque xor et représente l'image réelle; la seconde est appelée masque and et représente un motif monochrome (0 ou 1) qui définit la transparence de l'icône.
Lors de l'affichage d'une icône, Windows effectue l'opération logique suivante :
Ecran := (Ecran and MasqueAND) xor MasqueXOR
Ainsi, pour chaque pixel affiché : si la valeur du masque and est 1 alors le pixel de l'écran reste visible sinon il est effacé. Ensuite, le pixel devient une combinaison xor avec le point correspondant de l'image de l'icône.
Typiquement, le masque and correspond au contour de l'image à afficher mais ce n'est pas obligatoire. Cela permet quelques effets, que rien ne vous empêche également d'expérimenter.
Tous ces détails vont vous aider à comprendre pourquoi il y a une couleur transparente et une couleur inversée (inverted) dans l'éditeur d'icônes de BRW : elles vont servir, de manière interne, à définir le masque and.
L'éditeur d'icônes ressemble comme deux gouttes d'eau à l'éditeur de bitmaps. J'ai de nouveau rassemblé tout mon talent pour dessiner un magnifique smiley rose sur un fond entièrement transparent :
Fermez l'éditeur à l'aide des touches Ctrl-F4 pour retourner à la liste des images qui composent l'icône.
Nous allons ajouter une seconde image, forcément d'une résolution différente et/ou d'un nombre de couleurs différent, et nous verrons bien, lorsque le programme sera terminé, laquelle des deux Windows choisira pour obtenir le meilleur rendu possible en créant, par exemple, un raccourci sur le bureau.
Utilisez le menu Images --> New image et créez une nouvelle image. J'ai personnellement choisi une résolution de 64 X 64 pixels en 256 couleurs et ai dessiné un smiley (j'adore les smileys) d'un jaune complexe sur un fond non pas transparent mais inversé.
Ce sera moche mais cela illustrera bien ce qui précède.
VI-A-8. Création d'un curseur▲
Le dernier type de ressource que nous allons inclure dans notre programme sera un curseur.
Tout comme une icône, un curseur peut contenir plusieurs images de tailles différentes composées de masques and et xor
Le curseur possède cependant un élément supplémentaire : un point actif ou hot spot. C'est un unique pixel dont la position sera considérée par Windows comme la position du curseur tout entier.
Par exemple, le hot spot d'une flèche sera le pixel qui constitue sa pointe.
Un curseur avec une image bien choisie peut être une aide précieuse à l'utilisateur de votre programme, lui indiquant soit une action en cours (par exemple, un sablier) soit une action possible à un emplacement particulier
(par exemple, une quadruple flèche ou une main qui indique qu'un élément peut être déplacé).
Pour accéder à l'éditeur de curseurs de BRW, sélectionnez le menu Resource --> New puis le type CURSOR. La manoeuvre vous est désormais familière.
De nouveau, BRW vous demande si le curseur doit être inclus directement dans le script de ressource (Source) ou bien sous forme de fichier séparé (Binary). La faible taille de la ressource nous permet d'opter sans hésiter pour la première solution.
Vu sa relative obsolescence, BRW ne permet de créer que des curseurs inanimés de 32 X 32 pixels. Vous pouvez ajouter des curseurs plus modernes stockés dans des fichiers .CUR via le menu File --> Add to project.
J'ai dessiné... un smiley (c'est le dernier, promis) nanti d'une petite flèche qui pointe au nord-ouest et dont la pointe sera le hot spot. Pour définir ce dernier, il faut passer par le menu Cursor --> Set hot spot :
Les coordonnées de la pointe de la flèche sont bien entendu (0,0).
VI-A-9. Attribution d'identificateurs aux ressources▲
Jusqu'à présent, nous nous sommes contentés de laisser BRW attribuer ses propres identificateurs par défaut aux ressources que nous avons créées.
L'identificateur du menu est MENU_1, celui des bitmaps BITMAP_1 et BITMAP_2, etc. Pour notre petit programme, nous allons affecter nos propres identificateurs aux ressources.
Pour ce faire, on surbrille une ressource, on active le menu Resource --> Rename et on inscrit le nom de l'identificateur :
Ensuite, BRW demande si l'on veut créer le nouvel identificateur (affirmatif !) et, enfin, attend la valeur de l'identificateur :
N'utilisez pas de valeurs s'approchant de 32767 car pas mal de ressources internes de Windows ont des identificateurs dans la plage immédiatement inférieure à cette valeur
Le fait d'attribuer une constante non typée à une ressource n'est pas obligatoire. Nous pourrions directement attribuer un identificateur numérique - mais c'est beaucoup moins parlant dans le source d'une application - ou même une chaîne littérale.
Mais cette dernière possibilité est à proscrire car moins performante qu'une constante ou un identificateur numérique. Vous comprendrez pourquoi lorsque nous détaillerons le processus de chargement d'une ressource.
Voici les valeurs des identificateurs qui ont été choisis pour le présent programme :
Identificateur | Valeur |
---|---|
id_MenuPrincipal | 1 |
id_IconeFenetrePrincipale | 11 |
id_Accel | 21 |
id_Curseur | 31 |
id_Bitmap1 | 41 |
id_Bitmap2 | 42 |
A tout moment, vous pouvez accéder à la liste des identificateurs via le menu Resource --> Identifiers :
Dans ce dialogue, vous pouvez ajouter, supprimer ou modifier la valeur d'un identificateur.
Voici à présent le contenu du fichier CHGFOND.INC :
(****************************************************************************
chgfond.inc
produced by Borland Resource Workshop
*****************************************************************************)
const
cm_Exit = 24340
;
cm_FondDefaut = 101
;
cm_Fond1 = 102
;
cm_Fond2 = 103
;
id_MenuPrincipal = 1
;
id_IconeFenetrePrincipale = 11
;
id_Accel = 21
;
id_Curseur = 31
;
id_Bitmap1 = 41
;
id_Bitmap2 = 42
;
VI-A-10. Options de gestion des ressources en mémoire▲
Le menu Resource --> Memory options (après avoir surbrillé une ressource) vous permet de choisir de quelle manière une ressource est chargée et conservée en mémoire par le système :
Voici les options par défaut :
- Load on call : la ressource ne sera chargée en mémoire qu'en cas de besoin et non lors du chargement de l'exécutable
- Moveable : permet à Windows de déplacer la ressource en mémoire dans le cadre de sa gestion interne
- Discardable : permet à Windows d'expurger la ressource de la mémoire quand elle n'est plus utilisée. Au besoin, elle sera rechargée
- Pure : rend la ressource inaccessible en écriture, ce qui empêche de la modifier en mémoire
Ces options par défaut répondent à une saine politique de gestion de la mémoire système et sont rarement modifiées. Un exemple de raison qui pourrait justifier un changement serait la possibilité pour un programme de modifier une ressource chargée en mémoire. Dans ce cas, les options Discardable et Pure seraient désactivées.
VI-A-11. Enregistrement et compilation du projet▲
Avec les préférences que nous avons réglées au début du projet, le fait de sauvegarder celui-ci entraîne automatiquement sa compilation en un fichier .RES (binaires) et .INC (identificateurs), qui seront utilisables directement par Virtual Pascal.
Une modification n'est donc pas prise en compte par Virtual Pascal tant que le projet n'a pas été recompilé.
Voici le script complet créé par BRW, stocké dans le fichier CHGFOND.RC :
/****************************************************************************
chgfond.rc
produced by Borland Resource Workshop
*****************************************************************************/
#include "chgfond.inc"
id_Bitmap1 BITMAP
{
'42 4D EE 00 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 0F 00 00 00 0F 00 00 00 01 00 04 00 00 00'
'00 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 FF FF F0 00 00 FF FF F0 FF F0'
'0B BB BB 00 FF F0 FF 0B BB BB BB BB 0F F0 F0 BB'
'BB BB BB BB B0 F0 F0 BB B0 00 00 BB B0 F0 0B BB'
'0B BB BB 0B BB 00 0B B0 BB BB BB B0 BB 00 0B BB'
'BB BB BB BB BB 00 0B BB BB BB BB BB BB 00 0B BB'
'BB BB BB BB BB 00 F0 BB 0B BB BB 0B B0 F0 F0 BB'
'BB BB BB BB B0 F0 FF 0B BB BB BB BB 0F F0 FF F0'
'0B BB BB 00 FF F0 FF FF F0 00 00 FF FF F0'
}
id_Bitmap2 BITMAP "chat.bmp"
id_MenuPrincipal MENU
{
POPUP "&Fichier"
{
MENUITEM "&Quitter", cm_Exit
}
POPUP "F&onds"
{
MENUITEM "&Défaut\tCtrl-D", cm_FondDefaut
POPUP "&Personnalisés"
{
MENUITEM "Fond &1\tCtrl-1", cm_Fond1
MENUITEM "Fond &2\tCtrl-2", cm_Fond2
}
}
}
id_Accel ACCELERATORS
{
"D", cm_FondDefaut, VIRTKEY, CONTROL
"1", cm_Fond1, VIRTKEY, CONTROL
"2", cm_Fond2, VIRTKEY, CONTROL
}
id_IconeFenetrePrincipale ICON
{
'00 00 01 00 02 00 20 20 10 00 00 00 00 00 E8 02'
'00 00 26 00 00 00 40 40 00 01 00 00 00 00 28 16'
'00 00 0E 03 00 00 28 00 00 00 20 00 00 00 40 00'
'00 00 01 00 04 00 00 00 00 00 80 02 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 80 00 00 80 00 00 00 80 80 00 80 00'
'00 00 80 00 80 00 80 80 00 00 80 80 80 00 C0 C0'
'C0 00 00 00 FF 00 00 FF 00 00 00 FF FF 00 FF 00'
'00 00 FF 00 FF 00 FF FF 00 00 FF FF FF 00 00 00'
'00 00 00 00 00 DD DD 00 00 00 00 00 00 00 00 00'
'00 00 00 DD DD DD DD DD DD 00 00 00 00 00 00 00'
'00 00 DD DD DD DD DD DD DD DD 00 00 00 00 00 00'
'00 0D DD DD DD DD DD DD DD DD D0 00 00 00 00 00'
'0D DD DD DD DD 00 00 DD DD DD DD D0 00 00 00 00'
'DD DD DD 00 00 00 00 00 00 DD DD DD 00 00 00 00'
'DD DD D0 00 00 00 00 00 00 0D DD DD 00 00 00 0D'
'DD D0 00 00 00 00 00 00 00 00 0D DD D0 00 00 DD'
'DD D0 00 00 00 00 00 00 00 00 0D DD DD 00 00 DD'
'DD 00 00 00 00 DD DD 00 00 00 00 DD DD 00 0D DD'
'D0 00 00 0D DD DD DD DD D0 00 00 0D DD D0 0D DD'
'D0 00 00 DD D0 00 00 0D DD 00 00 0D DD D0 0D DD'
'D0 00 0D DD 00 00 00 00 DD D0 00 0D DD D0 DD DD'
'D0 00 0D D0 00 00 00 00 0D D0 00 0D DD DD DD DD'
'00 00 0D 00 00 00 00 00 00 D0 00 00 DD DD DD DD'
'00 00 00 00 00 00 00 00 00 00 00 00 DD DD DD DD'
'00 00 00 00 00 00 00 00 00 00 00 00 DD DD DD DD'
'00 00 00 00 00 00 00 00 00 00 00 00 DD DD DD DD'
'D0 00 00 00 00 00 00 00 00 00 00 0D DD DD 0D DD'
'D0 00 00 0D D0 00 00 0D D0 00 00 0D DD D0 0D DD'
'D0 00 00 0D D0 00 00 0D D0 00 00 0D DD D0 0D DD'
'D0 00 00 00 00 00 00 00 00 00 00 0D DD D0 00 DD'
'DD 00 00 00 00 00 00 00 00 00 00 DD DD 00 00 DD'
'DD D0 00 00 00 00 00 00 00 00 0D DD DD 00 00 0D'
'DD D0 00 00 00 00 00 00 00 00 0D DD D0 00 00 00'
'DD DD D0 00 00 00 00 00 00 0D DD DD 00 00 00 00'
'DD DD DD 00 00 00 00 00 00 DD DD DD 00 00 00 00'
'0D DD DD DD DD 00 00 DD DD DD DD D0 00 00 00 00'
'00 0D DD DD DD DD DD DD DD DD D0 00 00 00 00 00'
'00 00 DD DD DD DD DD DD DD DD 00 00 00 00 00 00'
'00 00 00 DD DD DD DD DD DD 00 00 00 00 00 00 00'
'00 00 00 00 00 DD DD 00 00 00 00 00 00 00 FF FC'
'3F FF FF C0 03 FF FF 00 00 FF FE 00 00 7F F8 03'
'C0 1F F0 3F FC 0F F0 7F FE 0F E1 FF FF 87 C1 FF'
'FF 83 C3 FC 3F C3 87 E0 07 E1 87 C7 E3 E1 87 8F'
'F1 E1 07 9F F9 E0 0F BF FD F0 0F FF FF F0 0F FF'
'FF F0 0F FF FF F0 07 FF FF E0 87 E7 E7 E1 87 E7'
'E7 E1 87 FF FF E1 C3 FF FF C3 C1 FF FF 83 E1 FF'
'FF 87 F0 7F FE 0F F0 3F FC 0F F8 03 C0 1F FE 00'
'00 7F FF 00 00 FF FF C0 03 FF FF FC 3F FF 28 00'
'00 00 40 00 00 00 80 00 00 00 01 00 08 00 00 00'
'00 00 00 12 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 C0 DC C0 00 F0 CA A6 00 00 20'
'40 00 00 20 60 00 00 20 80 00 00 20 A0 00 00 20'
'C0 00 00 20 E0 00 00 40 00 00 00 40 20 00 00 40'
'40 00 00 40 60 00 00 40 80 00 00 40 A0 00 00 40'
'C0 00 00 40 E0 00 00 60 00 00 00 60 20 00 00 60'
'40 00 00 60 60 00 00 60 80 00 00 60 A0 00 00 60'
'C0 00 00 60 E0 00 00 80 00 00 00 80 20 00 00 80'
'40 00 00 80 60 00 00 80 80 00 00 80 A0 00 00 80'
'C0 00 00 80 E0 00 00 A0 00 00 00 A0 20 00 00 A0'
'40 00 00 A0 60 00 00 A0 80 00 00 A0 A0 00 00 A0'
'C0 00 00 A0 E0 00 00 C0 00 00 00 C0 20 00 00 C0'
'40 00 00 C0 60 00 00 C0 80 00 00 C0 A0 00 00 C0'
'C0 00 00 C0 E0 00 00 E0 00 00 00 E0 20 00 00 E0'
'40 00 00 E0 60 00 00 E0 80 00 00 E0 A0 00 00 E0'
'C0 00 00 E0 E0 00 40 00 00 00 40 00 20 00 40 00'
'40 00 40 00 60 00 40 00 80 00 40 00 A0 00 40 00'
'C0 00 40 00 E0 00 40 20 00 00 40 20 20 00 40 20'
'40 00 40 20 60 00 40 20 80 00 40 20 A0 00 40 20'
'C0 00 40 20 E0 00 40 40 00 00 40 40 20 00 40 40'
'40 00 40 40 60 00 40 40 80 00 40 40 A0 00 40 40'
'C0 00 40 40 E0 00 40 60 00 00 40 60 20 00 40 60'
'40 00 40 60 60 00 40 60 80 00 40 60 A0 00 40 60'
'C0 00 40 60 E0 00 40 80 00 00 40 80 20 00 40 80'
'40 00 40 80 60 00 40 80 80 00 40 80 A0 00 40 80'
'C0 00 40 80 E0 00 40 A0 00 00 40 A0 20 00 40 A0'
'40 00 40 A0 60 00 40 A0 80 00 40 A0 A0 00 40 A0'
'C0 00 40 A0 E0 00 40 C0 00 00 40 C0 20 00 40 C0'
'40 00 40 C0 60 00 40 C0 80 00 40 C0 A0 00 40 C0'
'C0 00 40 C0 E0 00 40 E0 00 00 40 E0 20 00 40 E0'
'40 00 40 E0 60 00 40 E0 80 00 40 E0 A0 00 40 E0'
'C0 00 40 E0 E0 00 80 00 00 00 80 00 20 00 80 00'
'40 00 80 00 60 00 80 00 80 00 80 00 A0 00 80 00'
'C0 00 80 00 E0 00 80 20 00 00 80 20 20 00 80 20'
'40 00 80 20 60 00 80 20 80 00 80 20 A0 00 80 20'
'C0 00 80 20 E0 00 80 40 00 00 80 40 20 00 80 40'
'40 00 80 40 60 00 80 40 80 00 80 40 A0 00 80 40'
'C0 00 80 40 E0 00 80 60 00 00 80 60 20 00 80 60'
'40 00 80 60 60 00 80 60 80 00 80 60 A0 00 80 60'
'C0 00 80 60 E0 00 80 80 00 00 80 80 20 00 80 80'
'40 00 80 80 60 00 80 80 80 00 80 80 A0 00 80 80'
'C0 00 80 80 E0 00 80 A0 00 00 80 A0 20 00 80 A0'
'40 00 80 A0 60 00 80 A0 80 00 80 A0 A0 00 80 A0'
'C0 00 80 A0 E0 00 80 C0 00 00 80 C0 20 00 80 C0'
'40 00 80 C0 60 00 80 C0 80 00 80 C0 A0 00 80 C0'
'C0 00 80 C0 E0 00 80 E0 00 00 80 E0 20 00 80 E0'
'40 00 80 E0 60 00 80 E0 80 00 80 E0 A0 00 80 E0'
'C0 00 80 E0 E0 00 C0 00 00 00 C0 00 20 00 C0 00'
'40 00 C0 00 60 00 C0 00 80 00 C0 00 A0 00 C0 00'
'C0 00 C0 00 E0 00 C0 20 00 00 C0 20 20 00 C0 20'
'40 00 C0 20 60 00 C0 20 80 00 C0 20 A0 00 C0 20'
'C0 00 C0 20 E0 00 C0 40 00 00 C0 40 20 00 C0 40'
'40 00 C0 40 60 00 C0 40 80 00 C0 40 A0 00 C0 40'
'C0 00 C0 40 E0 00 C0 60 00 00 C0 60 20 00 C0 60'
'40 00 C0 60 60 00 C0 60 80 00 C0 60 A0 00 C0 60'
'C0 00 C0 60 E0 00 C0 80 00 00 C0 80 20 00 C0 80'
'40 00 C0 80 60 00 C0 80 80 00 C0 80 A0 00 C0 80'
'C0 00 C0 80 E0 00 C0 A0 00 00 C0 A0 20 00 C0 A0'
'40 00 C0 A0 60 00 C0 A0 80 00 C0 A0 A0 00 C0 A0'
'C0 00 C0 A0 E0 00 C0 C0 00 00 C0 C0 20 00 C0 C0'
'40 00 C0 C0 60 00 C0 C0 80 00 C0 C0 A0 00 F0 FB'
'FF 00 A4 A0 A0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E'
'3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E'
'3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E'
'3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E'
'3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 00'
'00 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E'
'00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E'
'3E 00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E'
'3E 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E 3E 00 00 00 00 00 00 3E 3E 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E 3E 3E 00 00 00 00 00 3E 3E 3E 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E 3E 3E 3E 00 00 00 00 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E 3E 3E 3E FF FF FF 3E 3E 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 00 00 00 00 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 00 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF 3E 3E 3E FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF 3E FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF 3E 3E FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF 3E 3E FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF 3E FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF 3E FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF 3E 3E FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF 3E 3E FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF 3E FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF 3E FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF 3E FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 3E 3E 3E 3E 3E FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'3E 3E 3E 3E 3E 00 00 00 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 00 00 00 00 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 00 00 00 00 3E 3E 3E 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E 3E 3E 3E 00 00 00 00 00 3E 3E 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E 3E 3E 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E FF'
'FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E'
'3E 3E 3E 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E'
'3E 00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E'
'3E 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E'
'3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E'
'00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E'
'3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E'
'3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E'
'3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3E'
'3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E FF FF FF FF FF FF FF FF FF FF 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 3E 3E 3E 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E'
'3E 3E 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 3E 3E 3E'
'3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 FF FF FF E0 07 FF FF FF FF FF'
'FE 00 00 7F FF FF FF FF F0 00 00 0F FF FF FF FF'
'C0 00 00 03 FF FF FF FF 00 00 00 00 FF FF FF FC'
'00 1F F8 00 3F FF FF F8 01 FF FF 80 1F FF FF F0'
'07 FF FF E0 0F FF FF E0 1F FF FF F8 07 FF FF 80'
'3F FF FF FC 01 FF FF 80 FF FF FF FF 01 FF FF 01'
'FF FF FF FF 80 FF FE 07 FF FF FF FF E0 7F FC 0F'
'FF FF FF FF F0 3F F8 0F FF FF FF FF F0 1F F8 1F'
'FF FF FF FF F8 1F F0 3F FF FF FF FF FC 0F F0 3F'
'FF FF FF FF FC 0F E0 7F FF FF FF FF FE 07 E0 FF'
'FF F8 0F FF FF 07 C0 FF FF C0 01 FF FF 03 C1 FF'
'FE 01 C0 7F FF 83 C1 FF F8 3F FE 3F FF 83 83 FF'
'F1 FF FF 8F FF C1 83 FF E3 FF FF C7 FF C1 83 FF'
'C7 FF FF E3 FF C1 83 FF 8F FF FF FB FF C1 07 FF'
'3F FF FF F9 FF E0 07 FF 7F FF FF FD FF E0 07 FE'
'7F FF FF FC FF E0 07 FE FF FF FF FE FF E0 07 FF'
'FF FF FF FE FF E0 07 FF FF FF FF FF FF E0 07 FF'
'FF FF FF FF FF E0 07 FF FF FF FF FF FF E0 07 FF'
'FF FF FF FF FF E0 07 FF FF FF FF FF FF E0 83 FF'
'FF FF FF FF FF C1 83 FF FF FF FF FF FF C1 83 FF'
'FF FF FF FF FF C1 83 FF FF FF FF FF FF C1 C1 FF'
'F8 FF FF 1F FF 83 C1 FF F0 7F FE 0F FF 83 C0 FF'
'F0 7F FE 0F FF 03 E0 FF F0 7F FE 0F FF 07 E0 7F'
'F8 FF FF 1F FE 07 F0 3F FF FF FF FF FC 0F F0 3F'
'FF FF FF FF FC 0F F8 1F FF FF FF FF F8 1F F8 0F'
'FF FF FF FF F0 1F FC 0F FF FF FF FF F0 3F FE 07'
'FF FF FF FF E0 7F FF 01 FF FF FF FF 80 FF FF 80'
'FF FF FF FF 01 FF FF 80 3F FF FF FC 01 FF FF E0'
'1F FF FF F8 07 FF FF F0 07 FF FF E0 0F FF FF F8'
'01 FF FF 80 1F FF FF FC 00 1F F8 00 3F FF FF FF'
'00 00 00 00 FF FF FF FF C0 00 00 03 FF FF FF FF'
'F0 00 00 0F FF FF FF FF FE 00 00 7F FF FF FF FF'
'FF E0 07 FF FF FF'
}
id_Curseur CURSOR
{
'00 00 02 00 01 00 20 20 00 00 00 00 00 00 30 01'
'00 00 16 00 00 00 28 00 00 00 20 00 00 00 40 00'
'00 00 01 00 01 00 00 00 00 00 00 02 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 FF FF 87 FF FF F8 78 7F FF F7'
'FF BF FF CF FF CF FF BF FF F7 FF BF FF F7 FF 7F'
'FF FB FE FF 83 FD FE FE 00 FD FE FC 7C 7D FE F9'
'FF 3D FD F3 FF 9E FD F7 FF DE FD FF FF FE FD FF'
'FF FE FE FF FF FD FE FF FF FD FE FE FD FD FE FC'
'78 FD FF 7E FD FB FF BF FF F7 FF BF FF F7 FF 0F'
'FF CF FE 37 FF BF 7C 78 78 7F 78 FF 87 FF 71 FF'
'FF FF 23 FF FF FF 07 FF FF FF 0F FF FF FF 07 FF'
'FF FF 00 FF FF FF'
}
Vous voyez que l'icône (composée de plusieurs images, rappelons-le), le curseur et la première bitmap sont codés en hexadécimal. Pour la seconde bitmap, rappelez-vous que nous avons choisi de la stocker dans un fichier séparé; BRW inclut l'image dans le fichier .RES au moment de la compilation.
VI-A-11-a. Fichier de configuration▲
Vous avez peut-être remarqué qu'en plus des fichiers .RC, .RES et .INC, BRW enregistre également un fichier CHGFOND.RWS. Ce fichier contient la configuration de BRW liée au projet : les options d'affichage et, surtout, les préférences que nous avons définies. Il n'est donc pas superflu de le conserver avec les sources du projet.
VI-B. Utilisation des ressources dans un programme▲
Nous allons à présent voir de quelle façon utiliser les différentes ressources que nous avons créées.
VI-B-1. Menu▲
Le menu principal est affecté à la fenêtre principale de l'application dès la création de celle-ci, c'est-à -dire dans son constructeur.
Une fonction de l'API permet de charger une ressource de type menu : LoadMenu. Voici sa déclaration :
Function
LoadMenu (Instance : hInst; MenuName : pChar) : hMenu;
- Instance est le handle de l'instance du programme. On passe généralement la constante typée hInstance (voir ci-dessous)
- MenuName est l'identificateur de la ressource
- La valeur retournée par la fonction est le handle du menu chargé
Tout d'abord, hInstance est une constante typée (de type LongInt) définie dans l'unité System. Elle représente le handle de l'application.
Lors de l'initialisation de l'exécutable, la valeur de hInstance est automatiquement demandée au système.
Autres chose : vous voyez que l'identificateur de la ressource est passé comme un paramètre de type pChar. Pour un identificateur défini sous forme de chaîne de caractères, c'est évident mais... quid pour un identificateur numérique comme ceux que nous avons attribués à toutes nos ressources ?
Eh bien, nous devons recourir à un transtypage :
Attr.Menu := LoadMenu(hInstance,pChar(id_MenuPrincipal));
Que se passe-t-il concrètement ? Grâce au transtypage, le mot de poids fort de l'adresse vaut 0000h et le mot de poids faible a la valeur de id_MenuPrincipal. Lorsqu'elle détecte un mot de poids fort égal à 0000h, la fonction LoadMenu sait qu'elle a affaire non pas à l'adresse d'une chaîne de caractères mais bien à un identificateur stocké dans le mot de poids faible.
La technique du transtypage sera utilisée systématiquement pour passer un identificateur numérique à un paramètre pChar
Une dernière chose : le handle du menu retourné par la fonction LoadMenu est affecté au champ Attr.Menu de l'objet tWindow.
Voici la déclaration du champ Attr :
Type
tWindowAttr = Record
Title : pChar;
Style : LongInt
;
ExStyle : LongInt
;
X, Y, W, H : Integer
;
Param : Pointer
;
case
Integer
of
0
: (Menu : hMenu);
1
: (Id : Integer
);
end
;
tWindow = Object
(tWindowsObject)
Attr : tWindowAttr;
... etc
Attr contient les attributs qui définissent l'aspect de la fenêtre au moment de sa création.
Nous aurons l'occasion de détailler tous les champs du type tWindowAttr au fur et à mesure que nous les rencontrerons.
En fait, nous avons déjà croisé, sans en parler, les champs X, Y, W et H dans le constructeur INIT de la fenêtre principale du programme CLIC.PAS.
Ces quatre champs représentent respectivement l'abscisse (X), l'ordonnée (Y), la largeur (W comme width) et la hauteur (H comme height) de la fenêtre à l'écran.
Le champ Menu, lui, contient le handle du menu affecté à la fenêtre.
Dans le constructeur Init de l'objet descendant de tWindow, il ne faut pas oublier d'appeler le constructeur de l'objet ancêtre :
Constructor
tFenetrePrincipale.INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement du menu *)
Begin
tWindow.INIT(aParent,aTitle);
Attr.Menu := LoadMenu(hInstance,pChar(id_MenuPrincipal))
End
;
VI-B-2. Table d'accélérateurs▲
Le principe du chargement d'une table d'accélérateurs est identique à celui d'un menu, mis à part que la fonction de l'API utilisée est LoadAccelerators :
Function
LoadAccelerators (Instance : hInst; TableName : pChar) : hAccel;
De la même façon, on passera hInstance comme handle d'instance et, à l'aide du transtypage, l'identificateur de la ressource comme nom de ressource.
Par contre, à la différence du menu, qui est propre à une fenêtre, la table d'accélérateurs est unique pour toute l'application et doit être chargée dans une méthode InitInstance de l'objet descendant de tApplication.
Dès que le handle de la table d'accélérateurs retourné par LoadAccelerators est affecté au champ hAccTable de l'objet descendant de tApplication,
ce dernier commence à convertir les combinaisons de touches en messages de commandes similaires à ceux générés par un menu.
Voici le code de chargement de la table d'accélérateurs :
Procedure
tProgramme.INITINSTANCE;
(* Chargement de la table d'accélérateurs *)
Begin
tApplication.INITINSTANCE;
hAccTable := LoadAccelerators(hInstance,pChar(id_Accel));
End
;
VI-B-3. Icône▲
Toute fenêtre Windows est susceptible de posséder son icône. Donc, pas seulement la fenêtre principale d'une application.
Une icône est liée à une classe de fenêtre; on parle d'ailleurs d'icône de classe.
La fonction de l'API dédiée au chargement d'une icône est LoadIcon :
Function
LoadIcon (Instance : hInst; IconName : pChar) : hIcon;
Le fonctionnement de cette fonction est identique à celui de LoadMenu et LoadAccelerators, que nous venons de voir.
Pour affecter une icône à une fenêtre, il faut modifier les paramètres de classe de celle-ci.
Typiquement, cela se fait dans la méthode GetWindowClass de l'objet descendant de tWindow :
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
(* Chargement de l'icône de classe de la fenêtre *)
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hIcon := LoadIcon(hInstance,pChar(id_IconeFenetrePrincipale));
End
;
Le fait d'appeler la méthode GetWindowClass de l'objet ancêtre initialise la classe de fenêtre avec ses valeurs par défaut.
Dans un second temps, l'icône de classe est affectée au champ hIcon de la structure aWndClass.
Cette structure, de type tWndClass, contient les paramètres de la classe de fenêtre.
Cette dernière est alors prête à être enregistrée par le système.
Si l'application ne comporte qu'une seule fenêtre (je parle bien de fenêtre, pas de dialogue - que nous aborderons bien plus tard), la méthode qui vient d'être exposée est suffisante.
Par contre, si elle comporte plusieurs fenêtres qui doivent avoir des icônes différentes, il faut les lier à des classes différentes.
On ne peut plus se contenter du nom de classe par défaut attribué par OWL, TurboWindow, mais il faudra définir un nom de classe unique pour chaque fenêtre.
La méthode GetClassName de l'objet descendant de tWindow est faite pour cela. Par exemple :
Function
tFenetrePrincipale.GETCLASSNAME : pChar;
(* Retourne le nom de classe de la fenêtre *)
Begin
GETCLASSNAME := 'ChgFond'
;
End
;
VI-B-4. Curseur▲
Tout comme nous avons pu définir une icône de classe, nous pouvons définir un curseur de classe pour une fenêtre. Ce curseur sera alors utilisé par Windows à l'intérieur de la zone client de la fenêtre.
Il n'est pas question, avec la technique présentée ici, de redéfinir les curseurs que Windows affiche par défaut lorsque la souris survole une barre de menu, une bordure ou tout autre élément
La fonction de l'API utilisée pour charger un curseur est LoadCursor :
Function
LoadCursor (Instance : hInst; CursorName : pChar) : hCursor;
Tout comme pour l'icône de classe, le curseur est chargé dans la méthode GetWindowClass de l'objet descendant de tWindow :
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
(* Chargement du curseur de classe de la fenêtre *)
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hCursor := LoadCursor(hInstance,pChar(id_Curseur));
End
;
C'est au champ hCursor de la structure aWndClass qu'il est affecté.
VI-B-5. Bitmap▲
Vous connaissez la musique, à présent, puisque les fonctions de chargement de ressources se ressemblent toutes. Voici LoadBitmap :
Function
LoadBitmap (Instance : hInst; BitmapName : pChar) : hBitmap;
Il n'y a pas de méthode d'objet privilégiée dans laquelle charger une bitmap : c'est selon les besoins.
Il faut détruire la bitmap chargée par LoadBitmap avant la fermeture du programme. C'est important, sinon l'espace mémoire alloué pour la ressource ne sera pas libéré par Windows
La fonction de l'API qui permet de détruire la bitmap est DeleteObject :
Function
DeleteObject (GDIObject : tHandle) : Bool;
Nous utiliserons très souvent DeleteObject dans les programmes de ce tutoriel, pour détruire tout un tas d'objets de l'interface graphique (pinceaux, crayons, bitmaps, polices de caractères, etc). Elle attend comme paramètre le handle de l'objet à détruire.
VI-B-6. En résumé▲
Pour charger une ressource :
- On utilise un transtypage en pChar pour passer un identificateur numérique comme paramètre
- On charge un menu à l'aide de LoadMenu dans le constructeur Init de la fenêtre
- On charge une table d'accélérateurs à l'aide de LoadAccelerators dans la méthode InitInstance de l'application
- On charge une icône de classe à l'aide de LoadIcon dans la méthode GetWindowClass de la fenêtre
- On charge un curseur de classe à l'aide de LoadCursor dans la méthode GetWindowClass de la fenêtre
- On charge une bitmap à l'aide de LoadBitmap et on la détruit à l'aide de DeleteObject
VI-C. Le programme CHGFOND.PAS▲
Nous allons à présent rassembler toutes ces notions dans notre programme.
Son but est particulièrement transcendant : en utilisant les commandes du menu ou les accélérateurs, nous pouvons changer le motif de fond de la fenêtre.
Voici le source complet :
Program
CHGFOND;
(* Illustration création et utilisation de ressources.
Réalisé par Alcatîz pour Developpez.com - 17-08-2006 *)
{$R CHGFOND.RES}
Uses
Windows, (* API Win32 *)
OWindows; (* Objets OWL *)
{$I CHGFOND.INC}
Type
pFenetrePrincipale = ^tFenetrePrincipale;
tFenetrePrincipale = Object
(tWindow)
AncienPinceauFond : hBrush;
PinceauFond1, PinceauFond2 : hBrush;
Constructor
INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement du menu et des bitmaps.
Création des pinceaux pour le fond *)
Function
GETCLASSNAME : pChar;
virtual
;
(* Retourne le nom de classe de la fenêtre *)
Procedure
GETWINDOWCLASS (var
aWndClass : tWndClass);
virtual
;
(* Chargement de l'icône de classe de la fenêtre *)
Procedure
CMFONDDEFAUT (var
Msg : tMessage);
virtual
cm_First + cm_FondDefaut;
(* Restauration du fond par défaut *)
Procedure
CMFOND1 (var
Msg : tMessage);
virtual
cm_First + cm_Fond1;
(* Utilisation de la bitmap id_Bitmap1 comme fond *)
Procedure
CMFOND2 (var
Msg : tMessage);
virtual
cm_First + cm_Fond2;
(* Utilisation de la bitmap id_Bitmap2 comme fond *)
Destructor
DONE; virtual
;
(* Restaure le fond original.
Détruit les pinceaux créés *)
end
;
tProgramme = Object
(tApplication)
Procedure
INITINSTANCE;
virtual
;
(* Chargement de la table d'accélérateurs *)
Procedure
INITMAINWINDOW;
virtual
;
(* Allocation de la fenêtre principale du programme *)
end
;
(* ----- Méthodes de l'objet tFenetrePrincipale ----- *)
Constructor
tFenetrePrincipale.INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement du menu et des bitmaps - Création des pinceaux pour le fond *)
Var
h : hBitmap;
Begin
tWindow.INIT(aParent,aTitle);
Attr.Menu := LoadMenu(hInstance,pChar(id_MenuPrincipal));
h := LoadBitmap(hInstance,pChar(id_Bitmap1));
if
h <> 0
then
begin
PinceauFond1 := CreatePatternBrush(h);
DeleteObject(h);
end
;
h := LoadBitmap(hInstance,pChar(id_Bitmap2));
if
h <> 0
then
begin
PinceauFond2 := CreatePatternBrush(h);
DeleteObject(h);
end
;
End
;
Function
tFenetrePrincipale.GETCLASSNAME : pChar;
(* Retourne le nom de classe de la fenêtre *)
Begin
GETCLASSNAME := 'ChgFond'
;
End
;
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
(* Chargement de l'icône et du curseur de classe de la fenêtre.
Détermination du fond par défaut *)
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hIcon := LoadIcon(hInstance,pChar(id_IconeFenetrePrincipale));
aWndClass.hCursor := LoadCursor(hInstance,pChar(id_Curseur));
AncienPinceauFond := aWndClass.hbrBackground;
End
;
Procedure
tFenetrePrincipale.CMFONDDEFAUT (var
Msg : tMessage);
(* Restauration du fond par défaut *)
Begin
SetClassLong(hWindow,gcl_hbrBackground,AncienPinceauFond);
InvalidateRect(hWindow,Nil
,True
);
End
;
Procedure
tFenetrePrincipale.CMFOND1 (var
Msg : tMessage);
(* Utilisation de la bitmap id_Bitmap1 comme fond *)
Begin
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond1);
InvalidateRect(hWindow,Nil
,True
);
End
;
Procedure
tFenetrePrincipale.CMFOND2 (var
Msg : tMessage);
(* Utilisation de la bitmap id_Bitmap2 comme fond *)
Begin
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond2);
InvalidateRect(hWindow,Nil
,True
);
End
;
Destructor
tFenetrePrincipale.DONE;
(* Restaure le fond original - Détruit les pinceaux créés *)
Begin
SetClassLong(hWindow,gcw_HbrBackground,AncienPinceauFond);
DeleteObject(PinceauFond1);
DeleteObject(PinceauFond2);
tWindow.DONE;
End
;
(* ----- Méthodes de l'objet tProgramme ----- *)
Procedure
tProgramme.INITINSTANCE;
(* Chargement de la table d'accélérateurs *)
Begin
tApplication.INITINSTANCE;
hAccTable := LoadAccelerators(hInstance,pChar(id_Accel));
End
;
Procedure
tProgramme.INITMAINWINDOW;
(* Allocation de la fenêtre principale du programme *)
Begin
MainWindow := New(pFenetrePrincipale,INIT(Nil
,'Travail avec les ressources'
));
End
;
Var
Programme : tProgramme;
(* ----- Programme principal ----- *)
Begin
Programme.INIT('ChgFond'
);
Programme.RUN;
Programme.DONE;
End
.
VI-C-1. Directives de compilation▲
Pour demander à Virtual Pascal de lier le fichier binaire de ressources, il faut inclure en tout début de programme la directive $R suivie du nom de fichier :
{$R CHGFOND.RES}
Astuce : si le nom du fichier .RES est le même que celui du source compilé, vous pouvez utiliser un joker :
{$R *.RES}
Virtual Pascal attend le fichier .RES dans le dossier défini dans les options (menu Options --> Directories --> Resource directories).
Parallèlement, il faut indiquer au compilateur qu'il doit inclure les constantes qui se trouvent dans le fichier .INC.
Cela se fait idéalement dans la section de déclaration des constantes non typées, au moyen de la directive $I :
{$I CHGFOND.INC}
Virtual Pascal attend le fichier .INC dans le même dossier que le source à compiler, à moins qu'un chemin soit spécifié dans la directive.
VI-C-2. Les bitmaps et les fonds de fenêtre▲
Le fond d'une fenêtre est dessiné par Windows en répétant un motif. Généralement, il s'agit d'un motif plein dont la répétition donne une surface unie.
Comme tout bon écolier, pour dessiner, Windows utilise des crayons et des pinceaux; les premiers servent à dessiner des lignes et des bordures de figures géométriques, les seconds servent à peindre des surfaces.
Nous aurons l'occasion de détailler tout cela dans le chapitre consacré à l'interface graphique (GDI).
Notre programme permet de choisir entre trois motifs différents : le fond par défaut et les deux ressources de type bitmap que nous avons créées.
Dans le constructeur de la fenêtre principale du programme, nous chargeons les deux bitmaps et nous en faisons des motifs utilisables par Windows pour peindre le fond de la fenêtre :
h := LoadBitmap(hInstance,pChar(id_Bitmap1));
if
h <> 0
then
begin
PinceauFond1 := CreatePatternBrush(h);
DeleteObject(h);
end
;
La fonction LoadBitmap charge la ressource de type bitmap en mémoire et retourne son handle. Si celui-ci est non nul, c'est que le chargement a réussi. Nous créons ensuite le motif de fond à l'aide de CreatePatternBrush :
Function
CreatePatternBrush (Bitmap : hBitmap) : hBrush;
Cette fonction reçoit comme paramètre un handle de bitmap (hBitmap) et retourne un handle de pinceau (hBrush).
A partir du moment où le motif de fond est créé, nous n'avons plus besoin de la bitmap et nous pouvons immédiatement la détruire avec DeleteObject.
Mais attention : avant la fermeture du programme, nous devrons également détruire les pinceaux qui viennent d'être créés.
Vous devez absolument garder ce principe à l'esprit : tout objet créé doit être détruit.
L'endroit idéal pour détruire des objets créés par le programme et utilisés pendant toute la durée de son exécution est soit le destructeur de la fenêtre principale, soit le destructeur de l'objet descendant de tApplication
Comme les handles des deux motifs créés à partir de nos ressources sont des champs déclarés dans l'objet tFenetrePrincipale, nous détruisons ces motifs dans le destructeur de cet objet :
Destructor
tFenetrePrincipale.DONE;
Begin
...
DeleteObject(PinceauFond1);
DeleteObject(PinceauFond2);
tWindow.DONE;
End
;
N'oubliez pas de détruire les motifs avant d'appeler le destructeur Done de l'objet ancêtre tWindow.
Maintenant que nous savons créer des motifs utilisables par Windows pour peindre le fond de la fenêtre, nous allons voir comment demander à Windows de les utiliser.
Selon que l'on veut redéfinir le fond de la fenêtre au démarrage du programme ou en cours d'exécution, la technique est différente.
Nous sommes ici dans le second cas, puisque nous laissons le programme démarrer avec le fond de fenêtre par défaut et que ce n'est qu'en réponse aux commandes de l'utilisateur que le fond changera.
Malgré tout, nous allons détailler les deux techniques.
VI-C-2-a. Définir un fond de fenêtre au démarrage du programme▲
Rappelons donc que ce paragraphe ne s'applique pas au programme CHGFOND.PAS.
La technique consiste à inclure le nouveau motif de fond dans les informations de classe de la fenêtre principale avant que celle-ci devienne visible.
Voici un petit programme d'exemple :
Program
FONDEMAR;
(* Définition d'un fond de fenêtre au démarrage du programme.
Réalisé par Alcatîz pour Developpez.com - 18-08-2006 *)
{$R FONDEMAR.RES}
Uses
Windows, (* API Win32 *)
OWindows; (* Objets OWL *)
{$I FONDEMAR.INC}
Type
pFenetrePrincipale = ^tFenetrePrincipale;
tFenetrePrincipale = Object
(tWindow)
PinceauFond : hBrush;
Constructor
INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement de la bitmap - Création du pinceau pour le fond *)
Function
GETCLASSNAME : pChar;
virtual
;
(* Retourne le nom de classe de la fenêtre *)
Procedure
GETWINDOWCLASS (var
aWndClass : tWndClass);
virtual
;
(* Définition du nouveau fond *)
Destructor
DONE;
virtual
;
(* Destruction du pinceau pour le fond *)
end
;
tProgramme = Object
(tApplication)
Procedure
INITMAINWINDOW;
virtual
;
(* Allocation de la fenêtre principale du programme *)
end
;
(* ----- Méthodes de l'objet tFenetrePrincipale ----- *)
Constructor
tFenetrePrincipale.INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement de la bitmap - Création du pinceau pour le fond *)
Var
h : hBitmap;
Begin
tWindow.INIT(aParent,aTitle);
h := LoadBitmap(hInstance,pChar(id_Bitmap1));
if
h <> 0
then
begin
PinceauFond := CreatePatternBrush(h);
DeleteObject(h);
end
;
End
;
Function
tFenetrePrincipale.GETCLASSNAME : pChar;
(* Retourne le nom de classe de la fenêtre *)
Begin
GETCLASSNAME := 'FonDemar'
;
End
;
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
(* Définition du nouveau fond *)
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hbrBackground := PinceauFond;
End
;
Destructor
tFenetrePrincipale.DONE;
(* Destruction du pinceau pour le fond *)
Begin
DeleteObject(PinceauFond);
tWindow.DONE;
End
;
(* ----- Méthodes de l'objet tProgramme ----- *)
Procedure
tProgramme.INITMAINWINDOW;
(* Allocation de la fenêtre principale du programme *)
Begin
MainWindow := New(pFenetrePrincipale,INIT(Nil
,'Fond de fen'#234'tre au d'#233'marrage'
));
End
;
Var
Programme : tProgramme;
(* ----- Programme principal ----- *)
Begin
Programme.INIT('FonDemar'
);
Programme.RUN;
Programme.DONE;
End
.
Le chargement de la ressource de type bitmap et la création du pinceau devant servir de motif peuvent se dérouler dans le constructeur de la fenêtre principale.
Ensuite, il faut redéfinir deux méthodes de tWindow : GetClassName et GetWindowClass.
Dans cette dernière méthode,nous affectons le handle du pinceau créé au champ hbrBackground de la structure aWndClass,
que nous avons déjà rencontrée lorsque nous avons parlé des icônes de classe et des curseurs.
Enfin, vous voyez que nous n'avons pas oublié de détruire le pinceau dans le destructeur de la fenêtre principale.
VI-C-2-b. Définir un fond de fenêtre en cours de programme▲
Pour changer le fond de la fenêtre une fois qu'elle est visible, comme dans notre programme CHGFOND.PAS, il faut utiliser une tout autre technique.
En effet, les méthodes GetClassName et GetWindowClass ne sont appelées qu'au démarrage du programme, pour enregistrer la classe de fenêtre auprès du système.
Par la suite, il faut aller directement modifier les paramètres de la classe de fenêtre.
Voici donc ce qui se passe dans chaque méthode virtuelle indexée chargée de répondre aux commandes de changement de fond :
Procedure
tFenetrePrincipale.CMFOND1 (var
Msg : tMessage);
(* Utilisation de la bitmap id_Bitmap1 comme fond *)
Begin
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond1);
InvalidateRect(hWindow,Nil
,True
);
End
;
La fonction SetClasslong permet d'aller changer une valeur dans les paramètres de la classe de fenêtre à laquelle appartient la fenêtre dont le handle est passé comme premier paramètre :
Function
SetClassLong (Wnd : hWnd; Index
: Integer
; NewLong : LongInt
) : DWord;
Je vous laisse voir la documentation du SDK pour les détails sur cette structure de type tWndClass (WNDCLASS dans le SDK);
ce qui nous intéresse ici est le champ hbrBackground, que l'on peut modifier à l'aide de SetClasslong en spécifiant gcl_hbrBackground comme index.
Une fois la modification faite dans les paramètres de la classe de fenêtre, il faut forcer la fenêtre à se réafficher.
C'est le but de la fonction InvalidateRect :
Function
InvalidateRect (Wnd : hWnd; Rect : pRect; Erase : Bool) : Bool;
Nous rencontrerons cette fonction à de nombreuses reprises. Elle rend "invalide" un rectangle dans la zone client de la fenêtre, de sorte que Windows est forcé de le redessiner.
Le paramètre Rect doit recevoir l'adresse d'une structure de type tRect, qui contient les coordonnées d'un rectangle.
Le fait de passer Nil comme adresse rend invalide toute la zone client de la fenêtre.
Le dernier paramètre, Erase, indique si le fond de la fenêtre doit être redessiné par Windows.
VI-C-2-c. Déterminer le fond par défaut▲
Parmi les commandes qui permettent de changer le fond de la fenêtre de notre programme, il y en a une qui restaure le fond par défaut.
Donc, au démarrage du programme, nous devons déterminer quel pinceau est utilisé par Windows.
Même si elle est inutilisable pour notre programme, nous avons vu au paragraphe VI-C-2-a la technique qui permet de définir un fond de fenêtre au démarrage.
Eh bien, nous allons nous en inspirer : dans la méthode GetWindowClass, au lieu de modifier le champ hbrBackground de la structure aWndClass, nous allons le lire et sauvegarder sa valeur !
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
Begin
tWindow.GETWINDOWCLASS(aWndClass);
...
AncienPinceauFond := aWndClass.hbrBackground;
End
;
Tout simplement, en réponse à la commande cm_FondDefaut, nous utilisons ce handle de pinceau sauvegardé :
Procedure
tFenetrePrincipale.CMFONDDEFAUT (var
Msg : tMessage);
(* Restauration du fond par défaut *)
Begin
SetClassLong(hWindow,gcl_hbrBackground,AncienPinceauFond);
InvalidateRect(hWindow,Nil
,True
);
End
;
Nous allons clôturer ici tous ces aspects théoriques sur les fonds de fenêtre pour nous pencher sur l'utilisation des autres ressources que nous avons créées.
VI-C-3. Les autres ressources▲
Les autres ressources que les bitmaps sont chargées de la manière expliquée précédemment dans ce chapitre (voyez le résumé).
Le menu :
Constructor
tFenetrePrincipale.INIT (aParent : pWindowsObject; aTitle : pChar);
Begin
tWindow.INIT(aParent,aTitle);
Attr.Menu := LoadMenu(hInstance,pChar(id_MenuPrincipal));
...
End
;
La table d'accélérateurs :
Procedure
tProgramme.INITINSTANCE;
Begin
tApplication.INITINSTANCE;
hAccTable := LoadAccelerators(hInstance,pChar(id_Accel));
End
;
L'icône et le curseur de classe :
Function
tFenetrePrincipale.GETCLASSNAME : pChar;
Begin
GETCLASSNAME := 'ChgFond'
;
End
;
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hIcon := LoadIcon(hInstance,pChar(id_IconeFenetrePrincipale));
aWndClass.hCursor := LoadCursor(hInstance,pChar(id_Curseur));
...
End
;
VI-C-4. Version avec une méthode WMCOMMAND▲
Dans notre programme, nous avons géré les commandes du menu et des accélérateurs à l'aide de méthodes virtuelles dynamiques indexées.
Pour chaque message cm_XXX, nous avons créé une méthode tFenetreprincipale.CMXXX.
Imaginons à présent qu'au lieu de trois commandes, il faille répondre à plusieurs dizaines de commandes.
Créer une méthode virtuelle dynamique indexée pour chacune d'entre elles alourdirait le programme et, de plus, serait particulièrement fastidieux.
Voici donc une variante du programme qui, au lieu de répondre individuellement aux messages de commandes, ne répond qu'à l'unique message wm_Command :
Program
CHGFOND2;
(* Illustration création et utilisation de ressources.
Version utilisant une méthode WMCOMMAND pour traiter les messages de commandes.
Réalisé par Alcatîz pour Developpez.com - 17-08-2006 *)
{$R CHGFOND.RES}
Uses
Windows, (* API Win32 *)
OWindows; (* Objets OWL *)
{$I CHGFOND.INC}
Type
pFenetrePrincipale = ^tFenetrePrincipale;
tFenetrePrincipale = Object
(tWindow)
AncienPinceauFond : hBrush;
PinceauFond1, PinceauFond2 : hBrush;
Constructor
INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement du menu et des bitmaps.
Création des pinceaux pour le fond *)
Function
GETCLASSNAME : pChar;
virtual
;
(* Retourne le nom de classe de la fenêtre *)
Procedure
GETWINDOWCLASS (var
aWndClass : tWndClass);
virtual
;
(* Chargement de l'icône de classe de la fenêtre *)
Procedure
WMCOMMAND (var
Msg : tMessage);
virtual
wm_First + wm_Command;
(* Réponse aux messages de commandes *)
Destructor
DONE; virtual
;
(* Restaure le fond original.
Détruit les pinceaux créés *)
end
;
tProgramme = Object
(tApplication)
Procedure
INITINSTANCE;
virtual
;
(* Chargement de la table d'accélérateurs *)
Procedure
INITMAINWINDOW;
virtual
;
(* Allocation de la fenêtre principale du programme *)
end
;
(* ----- Méthodes de l'objet tFenetrePrincipale ----- *)
Constructor
tFenetrePrincipale.INIT (aParent : pWindowsObject; aTitle : pChar);
(* Chargement du menu et des bitmaps - Création des pinceaux pour le fond *)
Var
h : hBitmap;
Begin
tWindow.INIT(aParent,aTitle);
Attr.Menu := LoadMenu(hInstance,pChar(id_MenuPrincipal));
h := LoadBitmap(hInstance,pChar(id_Bitmap1));
if
h <> 0
then
begin
PinceauFond1 := CreatePatternBrush(h);
DeleteObject(h);
end
;
h := LoadBitmap(hInstance,pChar(id_Bitmap2));
if
h <> 0
then
begin
PinceauFond2 := CreatePatternBrush(h);
DeleteObject(h);
end
;
End
;
Function
tFenetrePrincipale.GETCLASSNAME : pChar;
(* Retourne le nom de classe de la fenêtre *)
Begin
GETCLASSNAME := 'ChgFond'
;
End
;
Procedure
tFenetrePrincipale.GETWINDOWCLASS (var
aWndClass : tWndClass);
(* Chargement de l'icône et du curseur de classe de la fenêtre.
Détermination du fond par défaut *)
Begin
tWindow.GETWINDOWCLASS(aWndClass);
aWndClass.hIcon := LoadIcon(hInstance,pChar(id_IconeFenetrePrincipale));
aWndClass.hCursor := LoadCursor(hInstance,pChar(id_Curseur));
AncienPinceauFond := aWndClass.hbrBackground;
End
;
Procedure
tFenetrePrincipale.WMCOMMAND (var
Msg : tMessage);
(* Réponse aux messages de commandes *)
Begin
case
LoWord(Msg.wParam) of
cm_FondDefaut : begin
(* Restauration du fond par défaut *)
SetClassLong(hWindow,gcl_hbrBackground,AncienPinceauFond);
InvalidateRect(hWindow,Nil
,True
);
end
;
cm_Fond1 : begin
(* Utilisation de la bitmap id_Bitmap1 comme fond *)
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond1);
InvalidateRect(hWindow,Nil
,True
);
end
;
cm_Fond2 : begin
(* Utilisation de la bitmap id_Bitmap2 comme fond *)
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond2);
InvalidateRect(hWindow,Nil
,True
);
end
;
else
tWindow.WMCOMMAND(Msg);
end
;
End
;
Destructor
tFenetrePrincipale.DONE;
(* Restaure le fond original - Détruit les pinceaux créés *)
Begin
SetClassLong(hWindow,gcw_HbrBackground,AncienPinceauFond);
DeleteObject(PinceauFond1);
DeleteObject(PinceauFond2);
tWindow.DONE;
End
;
(* ----- Méthodes de l'objet tProgramme ----- *)
Procedure
tProgramme.INITINSTANCE;
(* Chargement de la table d'accélérateurs *)
Begin
tApplication.INITINSTANCE;
hAccTable := LoadAccelerators(hInstance,pChar(id_Accel));
End
;
Procedure
tProgramme.INITMAINWINDOW;
(* Allocation de la fenêtre principale du programme *)
Begin
MainWindow := New(pFenetrePrincipale,INIT(Nil
,'Travail avec les ressources'
));
End
;
Var
Programme : tProgramme;
(* ----- Programme principal ----- *)
Begin
Programme.INIT('ChgFond'
);
Programme.RUN;
Programme.DONE;
End
.
Le message wm_Command est généré, notamment, chaque fois qu'un utilisateur sélectionne une commande de menu ou presse un raccourci clavier.
Nous verrons beaucoup plus tard d'autres cas où ce message est généré.
Voici la signification des champs, que vous pouvez trouver dans le SDK :
- wNotifyCode = HiWord(wParam) : code de notification (0 si menu, 1 si accélérateur)
- wID = LoWord(wParam) : identificateur du menu ou de l'accélérateur
- hwndCtl = lParam : handle de contrôle (0 si menu ou accélérateur)
Dans le cas qui nous occupe, c'est-à -dire dans le cas de messages de commandes de menu ou d'accélérateurs, seul le mot de poids faible du champ wParam nous intéresse. A la place des trois méthodes virtuelles indexées, nous avons donc créé une unique méthode WMCOMMAND dans laquelle la valeur de ce champ est testée :
Procedure
tFenetrePrincipale.WMCOMMAND (var
Msg : tMessage);
(* Réponse aux messages de commandes *)
Begin
case
LoWord(Msg.wParam) of
cm_FondDefaut : begin
(* Restauration du fond par défaut *)
SetClassLong(hWindow,gcl_hbrBackground,AncienPinceauFond);
InvalidateRect(hWindow,Nil
,True
);
end
;
cm_Fond1 : begin
(* Utilisation de la bitmap id_Bitmap1 comme fond *)
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond1);
InvalidateRect(hWindow,Nil
,True
);
end
;
cm_Fond2 : begin
(* Utilisation de la bitmap id_Bitmap2 comme fond *)
SetClassLong(hWindow,gcl_hbrBackground,PinceauFond2);
InvalidateRect(hWindow,Nil
,True
);
end
;
else
tWindow.WMCOMMAND(Msg);
end
;
End
;
Pour toutes les commandes non traitées, surtout n'oubliez pas d'appeler la méthode WMCOMMAND de l'objet ancêtre tWindow !