La programmation Win32 en Virtual Pascal avec OWL


précédentsommairesuivant

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

Immédiatement, une seconde ressource de type bitmap est créée :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

Confirmez à l'aide du bouton Yes. A présent, nous pouvons attribuer une valeur à l'identificateur cm_Exit :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

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 :

 
Sélectionnez

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 :

Image non disponible

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 :

Image non disponible

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 :

Image non disponible

Ensuite, BRW demande si l'on veut créer le nouvel identificateur (affirmatif !) et, enfin, attend la valeur de l'identificateur :

Image non disponible

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 :

Image non disponible

Dans ce dialogue, vous pouvez ajouter, supprimer ou modifier la valeur d'un identificateur.

Voici à présent le contenu du fichier CHGFOND.INC :

 
Sélectionnez

(****************************************************************************

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 :

Image non disponible

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 :

 
Sélectionnez

/****************************************************************************


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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

{$R CHGFOND.RES}

Astuce : si le nom du fichier .RES est le même que celui du source compilé, vous pouvez utiliser un joker :

 
Sélectionnez

{$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 :

 
Sélectionnez

{$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 :

 
Sélectionnez

  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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 !

 
Sélectionnez

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é :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

Procedure tProgramme.INITINSTANCE;
Begin
  tApplication.INITINSTANCE;
  hAccTable := LoadAccelerators(hInstance,pChar(id_Accel));
End;


L'icône et le curseur de classe :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 !

VI-C-5. Téléchargement des sources des programmes de cette page


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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