Vous êtes sur la page 1sur 50

DEVELOPPEMENT ORIENTE OBJET

VISUAL C++
MFC et AppWizards

ELABORE PAR :
Dr. Amine BOUFAIED

www.functionx.com

© Copyright 2008

1
Amine BOUFAIED
Table des matières

1. – Introduction à la programmation sous Windows

Différence principale entre application Win32 et Dos

Caractéristiques des programmes sous Windows

Structure d'un programme Windows

Avantages apportés par l'utilisation des MFC et d’AppWizard

2. – Les MFC et les outils de développement proposés par Visual C++

Introduction

Boîte de dialogue, boutons et zones de saisie

Gestion des menus, des données et de la souris

Création des menus et des barres d’outils

3. – Création d'un agenda grâce aux MFC

4. – Connexion aux sources de données


NOTER BIEN !!

CE COURS EST INCOMPLET.


C’EST UN DOCUMENT EN COURS
DE CONSTRUCTION.

2
Amine BOUFAIED
Introduction

Nous allons décrire dans ce cours la conception d'une application Windows sur Visual C++
6.0, assistée par AppWizard et les MFC.

Dans un premier lieu, pour démontrer l'avantage apporté par l'utilisation des MFC, nous
vous décrierons très rapidement la structure d'une application Win32 sans faire appel aux MFC.
Ensuite, pour entrer dans le vif du sujet, nous présenterons les solutions fournies par Microsoft
dans le cadre d'un développement rapide et efficace : AppWizard, ClassWizard.

Pour cela, nous étudierons la création de Boîtes de dialogue, de boutons et zones de


saisie. Aussi, nous aborderons la gestion des menus, des données et de la souris, mais aussi
Création des menus et des barres d’outils

Enfin, nous réaliserons un agenda grâce aux MFC.

3
Amine BOUFAIED
1er partie : Introduction à la programmation sous Windows

Caractéristiques des programmes sous Windows

Les programmes Windows réagissent à des événements. Le code d'une application Windows est en grande
partie consacré au traitement des événements provoqués par l'intervention de l'utilisateur. Concrètement, vous aurez
par exemple, une partie de code définie pour répondre à un clic sur un bouton "OK".

Windows enregistre chaque événement dans un message, et place ce dernier dans une file d'attente associée au
programme auquel le message est destiné. Ce message est traité par une fonction déterminée pour la gestion de ces
messages. En détails, lors de l'envoi d'un message à votre programme, Windows transmet les données nécessaires à
votre programme pour répondre à l'évènement, sous la forme d'arguments de cette fonction.

Click Bouton Click Bouton


Entrée clavier …
Gauche Souris Droit Souris

Windows

Traitement Traitement click Traitement click



Entrée clavier Bouton Gauche Bouton Droit

Données

Programme

Remarque : Toutes les communications entre une application et Windows font appel à l'interface de programmation
d'application Windows ou API Windows. Il s'agit en fait d'un millier de fonctions fournies en standard avec
Windows et destinées à être employées par votre application.

Structure d'un programme Windows

Sous sa forme la plus réduite, un programme écrit exclusivement à l'aide de l'API Windows comporte deux fonctions
:
- une fonction WinMain( ) appelée au début de l'exécution du programme et contenant son initialisation, par
analogie, il s'agit de la fonction main( ) d'un programme C,
- et la fonction WindowsProc ( ).

Ces deux fonctions composent un programme complet, mais elles ne sont pas directement liées. En effet, WinMain( )
n'appelle pas WindowsProc( ). C'est Windows qui assure l'intégration du programme, en établissant le lien avec ces

4
Amine BOUFAIED
deux fonctions : la fonction WinMain( ) communique avec Windows en appelant certaines des fonctions de l'API
Windows. Il en va de même pour WinProc( ).

Avantages apportés par l'utilisation des MFC et d’AppWizard

La bibliothèque MFC est une adaptation de Win32 ajoutant les notions d’objet. Contrairement à Win32,
l'assimilation des notions concernant la création et l'affichage d'une fenêtre, la boucle de messages et l'analyse des
messages transmis à une application sont tous inclus dans le code que Visual C++ peut générer automatiquement.

Visual C++ présente les fonctions de l'API Windows selon une approche orientée objet et facilite l'utilisation de
l'interface (API) en proposant davantage de fonctionnalités par défaut sous une forme beaucoup plus structurée et
conviviale grâce à la bibliothèque Microsoft Foundation Classes ou MFC.
Visual C++ offre des outils de développement : AppWizard, ClassWizard, pour simplifier l'édition et la gestion de
notre code. Nous détaillerons ces outils dans la suite de ce cours.

5
Amine BOUFAIED
2e partie : Les MFC et les outils de développement proposés par Visual
C++

1 Introduction
1.1 Objets et classes
A grande échelle, une classe est comparable à une structure, à un petit détail près : une classe contient du
code et des données, alors qu’une structure ne contient que des données. Poursuivons cette analogie; lorsque
l’on définit une structure - par exemple la structure Adresse composée d’un champ de caractère pour le nom
de la rue, et d’un champ d’entier pour le numéro de rue - l’on définit ensuite une variable du type que l’on
vient de créer (Adresse), cette variable est appelée instance de la structure. Un objet n’est rien d’autre que
l’instance d’une classe, au même titre que la variable l’était pour la structure.
A plus fine échelle, le modèle de programmation objets est basé sur trois éléments majeurs:
•l’encapsulation permet d’occulter les détails de l’implémentation d’un objet. On parle aussi de masquage
de l’information.
•la modularité est la propriété d’un système partitionné en éléments appelés modules. La cohérence et le
faible couplage de ces modules aident à contrôler la complexité du système.
•la hiérarchie est un classement des abstractions. Le mécanisme d’héritage, simple ou multiple, permet de
représenter une hiérarchie d’abstractions.

Pour des informations plus détaillées, consultez le site de cours en ligne fourni par l’Université Virtuelle de
Tunis.

1.2 Les MFC (Microsoft Foundation Classes)

Les MFC constituent un ensemble de classes prédéfinies autour desquelles s'articule la programmation Windows
avec Visual C++ : l'écriture d'un programme Windows entraîne la création et l'utilisation d'objets MFC, ou d'objets
de classes dérivées des MFC. Les objets créés contiennent des fonctions membres permettant la communication
avec Windows, et le traitement des messages Windows.

Les MFC représentent un vaste domaine et font intervenir un grand nombre de classes. Elles composent une
structure complète de développement d'applications, où il vous suffit d'effectuer les opérations de personnalisation
dont vous avez besoin pour adapter les programmes à vos exigences.

Par convention, sachez que toutes :


- les classes des MFC portent des noms qui commencent par C, comme CDocument ou CView ;
- les données membres d'une classe MFC commencent par le préfixe m_.

L’utilisateur du programme déclenche des événements par des actions :


 L’utilisateur clique sur un bouton
 L’utilisateur modifie la taille d’une fenêtre
 Etc.

En fait, les événements Windows sont traduits en messages par le MFC. Ils sont liés aux éléments de l’interface
graphique et sont appelés notifications. Une grande partie du travail d’un programme Windows consiste à traiter les
messages et les notifications. On appelle aussi le modèle de Windows la programmation événementielle. Le
nom d’un message commence généralement par WM_, et l’événement qui est l’action d’envoyer un message par
ON_.

6
Amine BOUFAIED
The first decision to communicate to AppWizard, as shown in Figure 1.2, is whether your application should be
MDI, SDI, or dialog based. AppWizard generates different code and classes for each of these application types.

FIG. 1.2 The first step in building a typical application with AppWizard is choosing the interface.

The three application types to choose from are as follows:

 A single document interface (SDI) application, such as Notepad, has only one document open at a time.
When you choose File, Open, the currently open file is closed before the new one is opened.
 A multiple document interface (MDI) application, such as Excel or Word, can open many documents
(typically files) at once. There is a Window menu and a Close item on the File menu. It's a quirk of MFC
that if you like multiple views on a single document, you must build an MDI application.
 A dialog-based application, such as the Character Map utility that comes with Windows and is shown in
Figure 1.3, does not have a document at all. There are no menus. (If you'd like to see Character Map in
action, it's usually in the Accessories folder, reached by clicking Start. You may need to install it by using
Add/Remove programs under Control Panel.)

Databases

The second step in creating an executable Windows program with AppWizard is to choose the level of database
support, as shown in Figure 1.4.

FIG. 1.4 The second step to building a typical application with AppWizard is to set the database options you will
use.

There are four choices for database support:

 If you aren't writing a database application, choose None.


 If you want to have access to a database but don't want to derive your view from CFormView or have a
Record menu, choose Header Files Only.
 If you want to derive your view from CFormView and have a Record menu but don't need to serialize a
document, choose Database View Without File Support. You can update database records with CRecordset,
an MFC class discussed in more detail in Chapter 22, "Database Access."
 If you want to support databases as in the previous option but also need to save a document on disk (perhaps
some user options), choose Database View With File Support.

Le MFC comprend :

 Classes représentant les éléments de l’interface graphique : fenêtres, boutons, listes déroulantes, combo box,
etc…
 Classes utilitaires facilitant la programmation orientée objet
o Point (coordonnées de la souris, dimension des fenêtres, etc…)
o Date, fichiers, etc…
o Enveloppes (wrappers) des fonctions systèmes Win32
 Classe CObject : classe de base abstraite utilisée pour la dérivation des autres classes de MFC. Elle est
l’ancêtre de la plupart des classes de MFC. Elle entrepose les informations nécessaires pour la détermination
des classes (runtime classe information)
 Classe CWinApp : Elle représente une application Windows. Le AppWizard génère une classe dérivée de
CWinApp pour chaque programme.

Il existe une fonction membre très importante dans la classe CWinApp, il s’agit de InitInstance(). C’est
dans cette fonction membre que l’on règle les paramètres de l’application :
- indiquer le type de bibliothèque à utiliser, enregistrer/créer les clés appropriées dans le registre de
Windows, enregistrer le patron document/vue, charger l’icône de l’application, etc…
* Classe CWnd : classe abstraite représentant une fenêtre. En effet, dans le MFC, tous les contrôles (éléments de
l’interface graphique) sont des fenêtres !. Donc, CWnd est la classe de base de tous les contrôles. Cette classe
dispose d’un ensemble de fonctions membres pour réaliser la gestion et la manipulation d’une fenêtre. CWnd est

7
Amine BOUFAIED
dérivée de CObject,
* Classe CDialog : elle est dérivée de CWnd. Elle représente un panneau de dialogue. De plus, elle possède la
capacité de gérer le traçage des contrôles déposés.

Hiérarchie de la bibliothèque des classes MFC

CObject

CCmdTarget CGdiObject CDC

CWinThread CDocument CWnd CBrush CPaintDC

CClientDC
CObject

CFrameWnd CView CDialog

CMDIFrameWnd CScrollView

CMDIChildWnd CFormView

8
Amine BOUFAIED
9
Amine BOUFAIED
1.3 AppWizard, ClassWizard et MFC
Dans le développement de vos programmes Windows, vous serez amené à vous servir de deux outils.
- AppWizard, pour construire le code élémentaire, squelette de votre application Windows au moyen de la
bibliothèque MFC. Il s’agit d’un assistant à la programmation Windows extrêmement performant, car, pour
créer votre application, il vous suffit de personnaliser un programme tout prêt. Il contient même des
explications sur l’endroit où vous devez insérer le code spécifique à l’application.
- ClassWizard, facilite l’extension des classes générées par AppWizard comme éléments de base de votre
programme Windows. Il permet d’ajouter des classes reposant sur des classes des MFC, pour la prise en
charge des fonctionnalités à intégrer dans votre programme. Il convient de noter que ClassWizard ne
reconnaît pas les classes ne dérivant pas des classes MFC.

L’étendu des services que peuvent fournir ces outils sont conséquent, dans ce cours, nous n’en présenterons qu’une
partie

Les notions abordées :

- Boite de dialogue : La plupart des programmes Windows font appel à des boite de dialogue pour gérer certaines de
leurs entrées de données : cliquez sur une commande de menu et une boîte de dialogue s’affiche, contenant divers
contrôles vous permettant de saisir des informations. Pratiquement tous les éléments de la boîte de dialogue sont des
contrôles. Pour être plus précis, une boîte de dialogue est une fenêtre, et chacun de ses contrôles une fenêtres
spéciales.

- Les 3 différents contrôles abordés :


- Contrôle statique : il contient des informations statiques, telles que titres ou instructions, ou simplement
des éléments d’illustration ;

- Bouton commande : comme OK ou ANNULER, permettent généralement de refermer une boite de


dialogue, ou de confirmer un choix ;

- Contrôle d’édition : réduit à sa simple expression, il permet de saisir et de modifier une ligne de texte.

- à savoir pour la gestion des classes avec ClassWizard :


Comme nous l’avons vu plus haut, Windows communique avec notre programme en lui envoyant des
messages ; de même, les MFC vous permettent de définir des fonctions destinées à gérer les seuls messages
qui vous intéressent, sans vous préoccuper des autres.
Ces fonctions sont appelées gestionnaires de messages, ou simplement gestionnaires. Comme votre
application est un programme MFC, les gestionnaires de messages sont dans tous les cas des fonctions
membres de l’une des classes de votre application.

Une table de correspondance des messages établit la relation entre un message donnée et la fonction qu’il est
censé prendre en charge à l’intérieur de votre programme, sachant que chaque classe du programme
habilitée à gérer les messages Windows en possède une. La table de correspondance des messages de la
classe se présente sous la forme d’un tableau de fonctions membres prenant en charge les messages de
Windows. Toutes ses entrées associent un message spécifique à une fonction ; de sorte que l’arrivée de
chaque message déclenche l’appel de la fonction correspondante.

AppWizard et ClassWizard créent automatiquement une table de correspondance de messages lorsque vous
ajouter une classe pouvant gérer des messages. Dans cette table c’est principalement ClassWizard qui se
charge des ajouts et des suppressions, même si dans certain cas vous êtes amené à modifier la table vous-
même.

Avec Visual C++, trois approches sont proposées pour développer des applications Windo ws :
1. Les fonctions de l’API (Application Program Interface) : cette méthode est très lourde. Elle oblige à
développer de nombreuses lignes de code avant d’aboutir à un résultat concret.
2. Les MFC (Microsoft Foundation Classes) : ces classes interfacent Windows d’une manière bien plus
simple que les fonctions de l’API. Le travail de programmation en est simplifié d’autant. Avec quelques
lignes de code, il est possible de constituer une interface incluant les objets standard de Windows : barres

10
Amine BOUFAIED
de défilement, barre d’outils, menus, boutons, etc...
3. Les MFC et les AppWizards (assistants). Cette dernière méthode est de loin la plus souple : il suffit de
préciser le type de traitement à effectuer, et les assistants écrivent une grande partie du code. Lorsque la
trame du programme a été générée, il ne reste plus qu’à "remplir les trous" laissés vides par les assistants
pour réaliser des tâches plus spécifiques.

2 Boîte de dialogue, boutons et zones de saisie


AppWizard est un assistant à la programmation Windows, il définit automatiquement les classes nécessaires
pour une application MFC qui sont : la classe d’application et la classe de fenêtre, ainsi il contient des
indications sur l’endroit où on doit insérer le code spécifique à l’application.
On appelle l’assistant AppWizard dès la création de l’espace de travail, ainsi il donne la possibilité de
choisir le type d’application SDI, MDI, ou à base de boites de dialogue.

Parmi les éléments qu’on trouve dans presque toutes applications Windows on trouve : les boutons, les cases
à activer, les zones de texte, les listes déroulantes… ces éléments sont connus sous le nom de contrôles, et la
plupart d’entre eux sont intégrés au système d’exploitation Windows.

On peut classer ces contrôles selon leurs types comme le montre le tableau suivant :

Type Aspect Utilisé pour…

Contrôle statique * afficher des étiquettes ou des intitulés


Texte statique

Champs de saisie * permet à l’utilisateur d’entrer ou de modifier


Champs de saisie
un texte
Les boutons  L’utilisateur peut cliquer pour déclencher
Bouton de commande
une action
 C’est un contrôle que l’utilisateur peut
Case à cocher activer ou désactiver
 Il est utilisé dans un groupe de deux ou
Bouton radio plus, et un seul bouton peut être activé à la
fois

Zone de liste déroulante * Elle se compose d’un champ de saisie auquel


se rattache une liste de valeur
Zone de liste * Elle affiche une liste d’éléments prédéfinis
qu’on peut sélectionner

Création d’une application basée dialogue

Three classes have been created for you for the application called FirstMDI:

 CAboutDlg, a dialog class for the About dialog box


 CFirstDialogApp, a CWinApp class for the entire application
 CFirstDialogDlg, a dialog class for the entire application

La programmation d’une boite de dialogue comporte l’affichage et le traitement des contrôles utilisés. Pour
le traitement des contrôles utilisés dans la boite de dialogue, on peut utiliser l’assistant ClassWizard qui permet
de construire la table de messages Windows que l’application pourrait recevoir, y compris les fonctions
auxquelles ils devraient être passés.

11
Amine BOUFAIED
D’une façon générale, la programmation d’une boite de dialogue peut se résumer par les étapes suivantes :
 Conception de l’interface et mise en forme de l’application : lorsqu’on ajoute un contrôle, on doit
configurer ces propriétés,

Exemple :
Objet Propriété Valeur
Bouton de commande ID IDC_FERME
Caption FERME

 Association de variables aux contrôles : avant de commencer l’écriture du code de l’application, il faut
assigner des variables à chacun des contrôles auxquels sera associée une valeur.
 Ajout de fonctionnalités aux contrôles : personnalisation de code de l’application.

Dans la plupart des applications, l’utilisateur est sollicité pour fournir des informations de configuration, à
savoir par exemple si on veut enregistrer les données avant de quitter, et dans la majorité des cas l’application
ouvre une nouvelle fenêtre (fenêtre de dialogue) pour formuler de tels demandes.

Windows fournit un certain nombre de fenêtres de dialogue intégrées :

1) les fenêtres de message : qui présentent un message à l’utilisateur contenant un ou plusieurs boutons pour
récupérer l’entrée de l’utilisateur selon son besoin.
Pour utiliser ce genre de fenêtre, il suffit d’appeler la fonction MessageBox(), à laquelle on passe le texte
d’un message comme argument, ainsi que d’autres paramètres qui indiquent les boutons et l’icône à afficher
dans cette fenêtre.

Identifiants de combinaisons de boutons pour la fonction MessageBox()

MB_ABORTRETRYIGNORE
MB_OK
MB_OKCANCEL
MB_RETRYCANCEL
MB_YESNO
MB_YESNOCANCEL
Identifiants d’icônes pour la fonction MessageBox()
MB_ICONINFORMATION
MB_ICONQUESTION
MB_ICONSTOP
MB_ICONEXCLAMATION

Syntaxe de la fonction MessageBox() :


Int MessageBox(« message à afficher », « titre de la fenêtre de message », MB_ | MB_ ) ;

Pour le bouton Pour l’icône

2) Fenêtres de dialogue standards : sont utilisées dans la plupart des applications Windows pour ouvrir ou
enregistrer un fichier, configurer les options d’impression, etc.

12
Amine BOUFAIED
Les MFC fournissent plusieurs classes pour les fenêtres standards, citées dans le tableau suivant :

Classe standards de type dialogue


CFileDialog Sélection de fichier
CFontDialog Sélection de police
CColorDialog Sélection de couleur
CPgeSetupDialog Mise en forme de pages pour l’impression
CPrintDialog Impression
CFindReplaceDialog Recherche et remplacement

Ouvrez Visual C++ et ensuite Menu File puis New, ensuite suivez les étapes comme cela est illustré ci-
dessous.
AppWizard, Marche à suivre

13
Amine BOUFAIED
Un projet a été créé, et le squelette de l’application également. Il est déjà possible de compiler et d’exécuter
le projet.

Manipulation 1

Compilez, buildez (correspond au linkage dans d’autres langages de programmation) et exé-


cutez le programme. Pour ceci utilisez le menu Build ou les raccourcis claviers, respective-
ment CTRL-F7, F7 puis CTRL-F5.

Vous avez créé une application basée sur une boîte de dialogue, vous apprendrez plus loin à créer une
application dans une "vraie" fenêtre (le choix se fait au niveau de l’étape 1- Step 1 - dans la marche à suivre
ci-dessus).
Vous allez maintenant éditer le contenu de cette boîte de dialogue; pour ceci visualisez les ressources à
l’aide de l’onglet Workspace de la fenêtre View (par défaut elle occupe la partie gauche de Visual Studio).

Il est maintenant possible d’ajouter ou de supprimer des boutons, des zones de texte, des zones de saisie,
etc...Les modifications qui vont suivre permettent de réaliser une application permettant d’additionner deux
valeurs.

Manipulation 2

Supprimez tout d’abord la zone de texte existante dans la boîte de dialogue, ensuite ajoutez
trois zones de saisie (Edit Box, 4ème icone dans la barre Controls) et un bouton (6ème icone).
Changez le texte écrit sur le bouton en choisissant l’option Properties (cliquez avec le bouton
droit de la souris sur le bouton) et en changeant le champ Caption.

Il faut maintenant déclarer des variables correspondantes aux valeurs contenues dans ces trois masques de
saisies. Ceci se fait à l’aide de l’assistant ClassWizard (accessible dans le menu View ou directement à l’aide
de CTRL-W). Allez sur l’onglet Member Variables, et attribuez un type (int) et un nom de variable
(m_operande1, m_operande2 et m_resultat) aux trois zones de saisies (normalement identifié par
IDC_EDIT1, 2 et 3).

14
Amine BOUFAIED
ClassWizard, marche à suivre (suite)

Une fenêtre de ce type pour chacune des trois zones


IDC_EDIT

Il faut également associer une action (un événement) lors de l’appui sur le bouton additionner (le bouton
qui a été rajouté).
Dans le MFC, le routage des messages est centralisé à l’aide de cartes de messages (Message Maps). Chaque
composant d’un programme MFC disposant d’une queue de messages peut avoir une carte de message. Cela signifie
que les cartes de messages sont associées à des classes dérivées de MFC.
Les cartes de messages sont normalement instaurées par l’AppWizard à l’aide de macros.

La syntaxe de ces macros :


DECLARE_MESSAGE_MAP // placé dans la déclaration d’une classe dérivée de MFC (header file)

BEGIN_MESSAGE_MAP (Projet1, CDialog )


{ Placé dans la définition
d’une classe dérivée de
ON_BN_CLICKED(ID_ACTION, OnAction)
MFC (source file)
}
END_MESSAGE_MAP

Il existe un nombre élevé de macros pour la gestion des événements, pour cette raison on utilise le ClassWizard qui
présente les événements possibles des éléments graphiques d’un objet de programmation.

15
Amine BOUFAIED
Dans ClassWizard, choisissez l’onglet Message Maps (le 1er) et sélectionner IDC_BUTTON1 et
BN_CLICKED puis appuyez sur Add Function , acceptez le nom qui vous est proposé et une ligne de plus
apparaît sous member functions. Cliquez enfin sur Edit Code pour écrire le code à exécuter lors de l’appui sur
le bouton.

Le code qui suit permet de lire les valeurs dans les deux premières zones de saisies puis de les additionner
et d’afficher le résultat dans la troisième zone.

void CBoutonDlg::OnButton1()
{
// TODO: Add your control notification handler code here

// UpdateData permet de lire (TRUE) ou d'écrire (FALSE) dans les zones


// de saisies en mettant à jour les variables correspondantes
UpdateData(TRUE);
m_resultat = m_operande1 + m_operande2;
UpdateData(FALSE);

Après avoir recompilé et fait l’édition des liens du programme, exécutez le. Il suffit maintenant d’entrer des
valeurs dans les deux premiers champs et d’appuyer sur additionner pour obtenir le résultat.

3 Gestion des menus, des données et de la souris


Dans la partie précédente, vous avez appris à créer des applications simples basées sur des boîtes de dialo-
gues ("Dialog based"). Vous avez pu remarquer que dans le cas d’une application "Dialog based" (comme la
précédente), il n’a été créé que deux classes par AppWizard : CBoutonApp et CBoutonDlg. Il est expliqué
plus bas (dans le cas d’une explication plus générale) l’utilité de ces classes.
Pour pouvoir exploiter des fonctions plus avancées comme les menus, la souris, le dessin ou la sauvegarde
des don- nées, vous allez maintenant apprendre à créer des applications SDI (Single Document Interface).

La fenêtre d’une application SDI peut-être une boîte de dialogue (à ne pas confondre avec une application
"Dialog based" - comme précédemment - dans ce cas c’est la fenêtre qui est "Dialog based") ou un document.
Dans le premier cas, la fenêtre est comparable à celle d’une application "Dialog based", si ce n’est qu’elle est
munie d’un système de menus, et éventuellement d’une barre d’outils et/ou d’une barre d’état. Dans le second
cas, la fenêtre comporte une zone qui permet de recevoir du texte, des éléments dessinés, des bitmaps, des
AVI, etc... Le choix à effectuer dépend donc du type d’application à réaliser. Il faut néanmoins garder à
16
Amine BOUFAIED
l’esprit que ces différences ne sont la conséquence que d’un héritage (propriété du c++) différent, et qu’il est
tout à fait possible, par exemple, de dessiner dans une SDI du type boîte de dialogue en utilisant des fonctions
des classes de bases (en amont des classes héritées).
Les exemples qui vont suivre sont tous des applications SDI dont la fenêtre d’affichage est "Dialog based"
(permettant ainsi d’utiliser l’éditeur de boîte de dialogue pour y ajouter des boutons ou des zones de textes).

Manipulation 4

Créez un nouveau projet MFC AppWizard, que vous appellerez didact, de type SDI dont la
fenêtre d’affichage est "Dialog Based" en vous aidant des copies d’écrans qui suivent.

17
Amine BOUFAIED
Table 3: AppWizard SDI, marche à suivre

C’est ici que l’on choisit SDI

La classe CDidactView hérite de CFormView

18
Amine BOUFAIED
Vous pouvez constater que l’assistant a créé un certain nombre de classe (plus que pour l’exercice bouton) ,
dont CDidactDoc (classe document) qui sert à l’archivage et CDidactView (classe view) qui représente ce que
l’on voit à l’écran (donc également ce que l’on va y dessiner). Vous trouverez ci-dessous une explication non
exhaustive de ces différentes classes communes à tous les projets MFC de type SDI (à l’exception du nom du
projet inclus dans le nom de chaque classe : pour un projet nommé "truc", la classe document sera appelée
CTrucDoc et la classe view CTrucView, etc...)

Five classes have been created for you. For the application FirstSDI, they are as follows:

 CAboutDlg, a dialog class for the About dialog box


 CFirstSDIApp, a CWinApp class for the entire application
 CFirstSDIDoc, a document class
 CFirstSDIView, a view class
 CMainFrame, a frame class

3.1 CAboutDlg
Cette classe gère la boîte de dialogue qui contient le nom ainsi que le numéro de version du programme et
qui apparaît lors de la sélection dans le menu ? de la fonction A propos.
Déclarée et définie dans les fichiers didact.h et didact.cpp, cette classe dérive de CDialog .

3.2 CDidactApp
Cette classe gère le "comportement" des classes nécessaire à l'application, en particuliers les classes RUN-
TIME (temps réel) View, Doc et MainFrame. Déclarée et définie dans les fichiers didact.h et didact.cpp, cette
classe dérive de CWinApp.

3.3 CMainFrame
Cette classe s'occupe de la gestion de la fenêtre principale. C'est-à-dire dimensionner la taille de la fenêtre
au démarrage ainsi que la gestion (et l'affichage) de la barre des menus et de la barre des outils (toolbar).
Déclarée et définie dans les fichiers MainFrm.h et MainFrm.cpp, cette classe dérive de CFrameWnd.
3.4 CDidactDoc (classe Document)

Cette classe gère le document (objet de la classe Document). Un document représente la partie des données
que l'utilisateur ouvre avec la commande File Open et sauve avec la commande File Save. Cette classe permet
des opérations standard tels que création d'un nouveau document, son chargement, et son archivage. Le pro-
gramme manipulera les données en utilisant l'interface (au sens large) définie dans cette classe. Ces données
sont bien évidemment accessibles aux autres classes de l’application, et en particulier à la classe View. Utili-
sé en interaction avec la classe View, un document peur avoir de multiple views qui lui sont associées. Quand
l'utilisateur ouvre un document le programme principal crée une "view" et l'attache au document. Déclarée et
définie dans les fichiers didactDoc.h et didactDoc.cpp, cette classe dérive de CDocument.
3.5 CDidactView (classe CView)

Cette classe gère l'affichage (ou plus exactement des views, objets de la classe CView). Une view est attachée
à un document (objet de la classe Document) et fait office d'intermédiaire entre le document et l'utilisateur : une
view traduit l'image d'un document sur l'écran ou l'imprimante et interprète les entrées de l'utilisateur comme des
opérations sur le document. Une view est une enfant de la fenêtre principale. Plusieurs vues peuvent se partager
la fenêtre principale, comme dans le cas de fenêtre divisée (par exemple ouverture de deux documents Word et
affichage des deux en même temps). Une view est responsable de l'affichage et de la modification des
données du document mais pas de leurs sauvegarde. Le document fournit à la view les détails concernant
les données qu'il gère. Il est possible de laisser la liberté à la view d'accéder directement aux données du
document (pas très propre) ou d'y accéder à travers des fonctions définies dans la classe CDocument (préférable).
Déclarée et définie dans les fichiers didactView.h et didactView.cpp, cette classe dérive de CView.

19
Amine BOUFAIED
A chaque classe correspond un fichier “.h” (définition des membres de la classe et des prototypes des méthodes)
et un fichier “.cpp” (corps des méthodes)

Manipulation 5

Compilez, linkez et exécutez l’application Didact. (Rem: n’oubliez pas de fermer l’application
après cela, sinon lors du prochain linkage vous aurez une erreur d’accès au fichier en cours
d’utilisation).

Vous constaterez qu’il y a quatre menus : Fichier, Edition, affichage et ?.

Exercice 6

Supprimez également le menu Edition qui ne servira pas pour la suite (hint: utilisez l’éditeur
de ressources et éditez IDR_MAINFRAME, ensuite sélectionnez le menu Edition et la touche
Delete !).

Vous allez maintenant apprendre à créer une application qui permet de dessiner à main levée sur l’écran et
de choisir la couleur RGB du trait, ainsi que de sauver les paramètres de la couleur dans un fichier.

Manipulation 7

Ajoutez trois champs de texte Edit Box (qui serviront à déterminer la valeur de chaque compo-
santes RGB) à l’aide de l’éditeur de ressource. Ajoutez également trois champs de texte stati-
que Red, Green, Blue (ceci uniquement pour l’aspect visuel afin d’avoir une description des
trois champs d’édition). Ensuite à l’aide de ClassWizard (CTRL-W) et de l’onglet Member
Variables faites correspondre aux trois Edit Box trois variables int : m_red, m_green, m_blue
et limitez leur variation de 0 à 255 (Minimum et Maximum Value dans ClassWizard).

20
Amine BOUFAIED
Vous pouvez constater que ces trois variables ont été définies dans la classe CDidactView (fichiers
didactView.cpp et didactView.h). Ces trois variables sont donc propres à cette classe. Pour pouvoir les
archiver, vous allez créer trois autres variables propres à la classe CDidactDoc ainsi que des fonctions pour
pouvoir y accéder depuis d’autres classes (à l’aide d’un pointeur sur la classe CDidactDoc).
Vous pouvez accéder aux différents fichiers composant l’application à l’aide de l’onglet FileView du
Workspace (à gauche de l’écran).

Déclarez les trois variables private (red, green, blue) et les six fonctions public (SetRed, GetRed, SetGreen,
GetGreen, SetBlue et GetBlue) dans le fichier didactDoc.h :

// didactDoc.h : interface of the CDidactDoc class


//
/////////////////////////////////////////////////////////////////////////////
...
class CDidactDoc : public CDocument
...
// Attributes

private:
int Red;
int Green;
int Blue;

public:
void SetRed(int valeur_rouge);
void SetGreen(int valeur_vert);
void SetBlue(int valeur_bleu);
int GetRed();
int GetGreen();
int GetBlue();

...
#endif // !defined(AFX_DIDACTDOC_H__BE53CD6B_9FF6_11D2_B496_000001356673__INCLUDED_ )
21
Amine BOUFAIED
Définissez maintenant les six fonctions ainsi que les valeurs par défaut des trois variables dans le fichier
didactDoc.cpp :
...
CDidactDoc::CDidactDoc() //Constructeur
{
// TODO: add one-time construction code here
Red = 0;
Green = 0;
Blue = 0;
}

CDidactDoc::~CDidactDoc() //Destructeur
{
}

void CDidactDoc::SetRed(int valeur_rouge)


{
Red = valeur_rouge;
}
void CDidactDoc::SetGreen(int valeur_vert)
{
Green = valeur_vert;
}
void CDidactDoc::SetBlue(int valeur_bleu)
{
Blue = valeur_bleu;
}
int CDidactDoc::GetRed()
{
return Red;
}
int CDidactDoc::GetGreen()
{
return Green;
}
int CDidactDoc::GetBlue()
{
return Blue;
}

BOOL CDidactDoc::OnNewDocument()
{
...

Remarque : On aurait pu déclarer et définir les six fonctions dans le fichier en-tête (didactDoc.h), cela
aurait été plus rapide mais moins "propre".

Il existe deux méthodes pour la lecture et l’écriture de données sur disque : la sérialisation des données, qui
utilise classiquement les commandes du menu Fichier, et l’accès direct, qui fait appel aux fonctions de la
classe CFile. La première méthode utilise la fonction Serialize(), prédéfinie par l’assistant AppWizard lors de
la définition du squelette de l’application. La seconde repose sur les fonctions de la classe CFile : Open,
Close, Read, Write, etc...
On utilisera dans ce cours uniquement la sérialisation des données, qui est très simple à implémenter et qui
permet d’utiliser directement les fonctions du menu Fichier.
Ajoutez ces lignes nécessaires à l’archivage des trois variables Red, Green, Blue dans le fichier didac-
tDoc.cpp :

22
Amine BOUFAIED
...
/////////////////////////////////////////////////////////////////////////////
// CDidactDoc serialization

void CDidactDoc::Serialize(CArchive& ar)


{
if (ar.IsStoring())
{
// TODO: add storing code here
ar << Red;
ar << Green;
ar << Blue;
}
else
{
// TODO: add loading code here
ar >> Red;
ar >> Green;
ar >> Blue;
}
}
...

Les instructions situées sous le if sont exécutées dans le cas d’un enregistrement de données (fonction Enre-
gistrer ou Enregistrer sous dans le menu Fichier). Celles sous le else dans le cas d’une lecture de données
(fonction Ouvrir dans le menu Fichier). La variable ar représente l’archive, c’est-à-dire le fichier que vous
allez lire ou dans lequel vous allez écrire. Les opérateurs surchargés << et >> indiquent le sens dans lequel
transitent les données.

Manipulation 8

Les trois champs de saisie ainsi que leurs variables associées (m_Red, m_Green et m_Blue) sont
propres à la classe CD id ac t View et ne sont donc, pour le moment, pas du tout reliées aux
variables de la classe document. Vous allez donc commencez par ajoutez un bouton (à l’aide de
l’éditeur de ressource) qui servira à valider les données dans les trois champs de saisie, puis éditez
le code correspondant à un clic sur ce bouton (comme dans le premier exemple d’addition à l’aide de
ClassWizard CTRL W).

23
Amine BOUFAIED
Maintenant vous allez créez le code associé à l’appui sur le bouton. L’appui sur le bouton devra mettre à
jour les variables Red, Green et Blue (par l’intermédiaire des fonctions SetRed, SetGreen et SetBlue car les
variables susmentionnées ont été déclarées en private et il n’y donc pas possible d’y accéder directement
depuis d’autre classe que la classe document). Il faut pour ceci déclarer un pointeur sur la classe document
dans la classe CDidactView. Donc, après l’appui sur Edit Code de la figure ci-dessus, vous vous
retrouverez dans le fichier didactView.cpp et éditerez la fonction OnButton1 comme ceci :
...
/////////////////////////////////////////////////////////////////////// //////
// CDidactView message handlers

void CDidactView::OnButton1()
{
// TODO: Add your control notification handler code here

// UpdateData(TRUE) met à jour m_red, m_green et m_blue avec les valeurs


// contenues dans les trois masques de saisie

UpdateData(TRUE);
CDidactDoc *pDoc = GetDocument(); // pDoc = pointeur sur la classe document
pDoc->SetRed(m_red);
pDoc->SetGreen(m_green);
pDoc->SetBlue(m_blue);

Afin de pouvoir retrouver les valeurs qui auront été sauvées, il faut les récupérer (c-à-d. prendre les valeurs
contenues dans la classe document et les "coller" dans les masques de saisie de la classe CDidactView) lors
de l’affichage de la fenêtre (l’idéal serait dans le constructeur de la classe CDidactView, mais à ce moment,
le pointeur sur la classe document ne peut pas être utilisé).

Manipulation 9

Vous allez donc ajouter la fonction OnDraw() dans la classe C D i d a c t V iew, à l’aide de
ClassWizard (CTRL W). Pour ceci, sélectionnez l’onglet Message Map dans ClassWizard, puis
sélectionnez CDidactView sous Object IDs et OnDraw sous Messages et finalement cliquez sur Add
Function.

24
Amine BOUFAIED
Ensuite cliquez sur Edit Code, et éditez OnDraw de la façon suivante:
...
void CDidactView::OnDraw(CDC* pDC)
{
// TODO: Add your specialized code here and/or call the base class

CDidactDoc *pDoc = GetDocument();


m_red = pDoc->GetRed();
m_green = pDoc->GetGreen();
m_blue = pDoc->GetBlue();
UpdateData(FALSE); //écrit les valeurs dans les masques de saisies

Manipulation 10

Afin de vérifier si tout marche correctement, exécutez le programme, entrez trois valeurs dans
les masques de saisie (10, 20, 30 par exemple) puis validez à l’aide du bouton. Enregistrez
(menu Fichier) sous essai1 et fermez le programme. Exécutez à nouveau le programme et ouvrez
le fichier essai1...

Understanding a Multiple Document Interface Application


A multiple document interface application also has menus, and it enables the user to have more than one
document open at once. This section presents the code that is generated when you choose an MDI application
with no database or compound document support, but instead with a toolbar, a status bar, Help, 3D controls,
source file comments, and the MFC library as a shared DLL. As with the SDI application, these are the defaults
after Step 1. The focus here is on what differs from the SDI application in the previous section.

Five classes have been created for you. For the application FirstMDI, they are

 CAboutDlg, a dialog class for the About dialog box


 CFirstMDIApp, a CWinApp class for the entire application
 CFirstMDIDoc, a document class
 CFirstMDIView, a view class
 CMainFrame, a frame class

25
Amine BOUFAIED
3.6. Les événements de la souris
Selon le type de l’application, on peut avoir besoin de connaître les actions que l’utilisateur
réalise au moyen de la souris : il nous faut savoir quand et où l’utilisateur a cliqué, quel bouton de la
souris a été activé et quant a été relâché.
En ce qui concerne les événements de la souris on remarque que ceux qui sont disponible le plus
souvent sont : le clic et le double clic, mais si on observe la souris on se dit qu’il existe d’autres
événements qui sont répertoriés dans le tableau suivant :

Messages d’événements de la souris


WM_LBUTTONDOWN Le bouton gauche a été activé
WM_LBUTTONUP Le bouton gauche a été relâché
WM_LBUTTONDBCLK On double-cliqué sur le bouton gauche
WM_RBUTTONDOWN Le bouton droit a été activé
WM_RBUTTONUP Le bouton droit a été relâché
WM_RBUTTONDBCLK On a double-cliqué sur le bouton droit
WM_MOUSEMOVE La souris est déplacée à travers la fenêtre
WM_MOUSEWHEEL La molette de la souris est actionnée

3.7. Les événements du clavier


La capture des événements du clavier est semblable à celle de la souris, mais il existe moins de
messages d’événements. En effet, on trouve des messages pour l’activation d’une touche et pour le
relâchement, ç savoir :

Messages d’événements du clavier


WM_KEYDOWN Une touche est appuyée
WM_KEYUP Une touche est relâchée

3.8. Création de dessins avec la souris


Parmi les actions qu’on peut réaliser avec la souris, la création des dessins. Pour pouvoir
programmer le dessin de formes, on doit connaître plusieurs éléments sur l’état de la souris, en particulier :
 à quel moment le bouton de la souris est enfoncé puisque c’est l’indication du début de l’opération
de dessin
 la position du curseur lorsqu’on appuie sur le bouton
 à quel moment la souris se déplace et la position correspondante du curseur
 à quel moment le bouton de la souris est relâché et quelle est la position du curseur

Parmi les fonctions qui peuvent être développées, on trouve :


 la fonction OnMouseMove (UINT nFlags, CPoint point) pour le message WM_MOUSEMOVE
 la fonction OnLboutonDown (UINT nFlags, CPoint point) pour le message
WM_LBOUTONDOWN

Ces deux fonctions peuvent recevoir les deux paramètres :


 UINT nflags : c’est un ensemble d’indicateurs (drapeaux) qui sont utilisés pour déterminer si le
bouton de la souris est activé (et lequel)
 CPoint point : il renseigne sur la position de la souris (coordonnées actuelles)

26
Amine BOUFAIED
Dessin de la souris

3.9. Incorporations de graphiques, de dessins et de bitmaps

Le système d’exploitation Windows offre plusieurs niveaux d’abstraction pour la création et


l’utilisation de graphiques dans l’application. En effet, Microsoft a facilité cette tâche en fournissant un
dispositif graphique virtuel pour toutes les applications Windows, et permettant ainsi de créer toutes sortes
de graphiques dans une application.
Avant de créer des graphiques, on doit tout d’abord créer le device context (contexte de
périphérique) ou le DC. Le DC contient des informations sur le système, sur l’application et sur la fenêtre
dans laquelle on va dessiner. Le DC est utilisé par le système d’exploitation pour connaître dans quel
contexte un graphique est crée, quelle est la surface visible, et quel est l’emplacement courant sur l’écran.
Le DC utilise deux ressources pour exécuter la plupart des ses fonctions graphiques : le crayon
(pen), le pinceau (brush) et l’image (bitmap). Pour pouvoir expliter ces fonctionnalités, on doit définir les
classes appropriées pour ces ressoures, à savoir :
 la classe CDC : elle offre de nombreuses fonctions permettant de dessiner différentes formes
graphiques.
 La classe CPen : cette classe est la ressource d’outil principale pour dessiner toutes sortes de
lignes à l’écran, on peut créer une instance de cette classe et spécifier le type, l’épaisseur et la
couleur de la ligne
Exemple : CPen lpen(PS_SOLID, 1, RGB(0, 0, 0)) ;
 La classe CBrush : cette classe permet de créer des pinceaux qui définissent le type de
remplissage d’une surface
Exemple : CBrush lsolid( RGB(0 , 0, 255)) ;
 La classe CBitmap : si on ajoute une image bitmap comme ressource, on peut créer une instance
de cette classe et spécifier l’identifiant de ressource bitmap comme image à charger à partir d’un
fichier
Exemple : CBitmap lbitmap ;
Lbitmap.LoadBitmap(IDB_MYBITMAP) ;

Vous allez maintenant apprendre à gérer les messages de la souris pour dessiner à main levée dans
l’application. Pour cela vous aurez besoin de deux messages de la souris : un lors de l’appui sur le bouton
gauche de la souris et l’autre à chaque mouvement de la souris.

Manipulation 11

Ajoutez deux messages dans la classe CDidactView, à l’aide de ClassWizard (CTRL W). Pour
ceci, sélectionnez l’onglet Message Map dans ClassWizard, puis sélectionnez CDidactView sous
Object IDs et WM_LBUTTONDOWN sous Messages et finalement cliquez sur Add Function.
Répétez l’opération pour ajoutez également WM_MOUSEMOVE.

27
Amine BOUFAIED
Visualisez le code généré d’une de ceux fonctions (utilisez le bouton Edit Code dans AppWizard ou
allez manuellement à la fin du fichier didactView.cpp, cela produit le même résultat...). Vous constaterez
que ces deux fonctions reçoivent deux paramètres : nFlags et point. Lors de l’occurrence de l’un de ces
deux événe- ment, le noyau temps réel se chargera de remplir ces deux paramètres correctement : NFlags
contiendra l’état des bouton de la souris (enfoncé ou non enfoncé) et point la position de la souris lors de
l’occurrence du mes- sage.
Pour comprendre comment cela fonctionne, imaginez que vous voulez dessiner à l’écran:
1. Vous commencez par appuyer sur le bouton gauche de la souris à une certaine coordonnée de l’écran,
il faut sauver cette première coordonnée dans une variable pnt_précédent.
2. Lors du premier mouvement de la souris (le plus petit perceptible par votre ordinateur), vous devez
tracer un trait entre le pnt_précédent et le point courant (à condition que le bouton de gauche soit
toujours pressé, d’où l’utilité des nFlags). Ensuite le point courant devient le nouveau pnt_précédent.
3. Lors du deuxième mouvement de la souris, vous tracez un trait entre le pnt_précédent et le point
courant. Ensuite le point courant devient le nouveau pnt_précédent.
4. Etc..., jusqu’à ce que le test des flags indique que le bouton de gauche n’est plus pressé. Dans ce cas, il
ne faut plus tracer de trait à l’écran
Remarque: OnLButtonDown n’est appelée qu’au moment de l’appui sur le bouton gauche alors que
OnMouseMove l’est à chaque déplacement de la souris (même si le bouton n’est pas pressé)

Créez les deux variables pnt_précédent (une pour l’abscisse l’autre pour l’ordonnée) ainsi qu’un crayon
qui sera utile plus loin dans le fichier didactView.h. :
...
protected: // create from serialization
only CDidactView();
DECLARE_DYNCREATE(CDidactView)

private:

int XPrec; //Abscisse précédente


int YPrec; //Ordonnée précédente
CPen *Crayon; //Crayon

public:
...

//{{AFX_DATA(CDidactView)

28
Amine BOUFAIED
Avant d’écrire le code correspondant aux deux fonctions OnLButtonDown et OnMouseMove, il est encore
nécessaire de comprendre comment dessiner un trait entre deux points :
1. Définir un pointeur sur la fenêtre active (appelé Device Context).
2. Définir un crayon possédant certaines propriétés dont la couleur.
3. Déplacer le crayon à une certaine position (le crayon ne dessine pas).
4. Tracer une ligne jusqu’à un autre point (le crayon dessine).

Maintenant vous savez tout ce qui est nécessaire à l’écriture du code. Editez donc les deux fonctions
OnL- ButtonDown et OnMouseMove (rappel: le squelette a déjà été créé précédemment) à la fin du
fichier didac- tView.cpp de la façon suivante :

void CDidactView::OnLButtonDown(UINT nFlags, CPoint point)


{
// TODO: Add your message handler code here and/or call default

// Initialisation du point de départ


XPrec =
point.x;
YPrec =
point.y;

//Aller chercher la couleur du crayon dans le


document int pen_red, pen_green, pen_blue;
CDidactDoc *pDoc =
GetDocument(); pen_red = pDoc-
>GetRed(); pen_green = pDoc-
>GetGreen(); pen_blue = pDoc-
>GetBlue();

//Définir un nouveau crayon de la bonne couleur


Crayon = new CPen(PS_SOLID, 1, RGB(pen_red,pen_green,pen_blue));

CFormView::OnLButtonDown(nFlags, point);
}

void CDidactView::OnMouseMove(UINT nFlags, CPoint point)


{
// TODO: Add your message handler code here and/or call default

// Effectue tout d'abord un test pour savoir si le bouton droit est


pressé if ( (nFlags & MK_LBUTTON) == MK_LBUTTON )
{
//Obtenir tout d'abord un pointeur sur la fenêtre active
CDC* pDC = GetDC();

//Sélectionner le crayon
pDC->SelectObject(Crayon);

//Dessiner le trait allant du point précédent au point courant


pDC->MoveTo(XPrec,YPrec);
pDC->LineTo(point.x,point.y);

//Le point courant devient le point précédent


XPrec = point.x;

29
Amine BOUFAIED
YPrec = point.y;

CFormView::OnMouseMove(nFlags, point);
}

Manipulation 12

Vous avez maintenant terminé l’application. Compilez, linkez, exécutez et amusez -vous avec...

4. – Création des menus et des barres d’outils


Lorsque les 1ers terminaux ont été introduits et que les utilisateurs ont commencé à employer des
applications, les développeurs de logiciels ont constaté le besoin de fournir une sorte de menu des actions qui
peuvent être exécutées par l’ordinateur. Depuis, les menus ont évolué, ils respectent tous les types de conception
standard permettant un emploi et un apprentissage aisé des éléments des menus.
Les premiers styles de menus standardisés sont les menus déroulants ou en cascade. Il s’agit de menus
dont les différentes catégories sont regroupées en barre au sommet de l’application. Si une d’elles est
sélectionnée, un menu est déroulé sous les catégories et présente un certain nombre d’options qui peuvent être
sélectionnées afin de déclencher des actions dans l’application.
Plus tard, un autre style de menu a été développé, appelé le menu contextuel, c à d qui apparaît au
milieu de l’espace de travail de l’application, il est spécifique à l’objet en cours.

Menus standards et conventions :


Bien qu’aucun standard n’ait été défini sur le mode construction, il existe un certain nombre de
conventions à respecter lors de leur conception et de leur fabrication :
 utilisation de catégorie de menu à mot unique
 le menu fichier contient toutes les options relatives aux fichiers
 le menu édition contient toutes les fonctions de modification
 le menu affichage contient les options qui permettent de contrôler et de modifier l’aspect de l’espace de
travail

Création de menu :
Les menus sont définis comme des ressources dans les applications Visual C++. Pour créer un menu, il
suffit de suivre les étapes suivantes :
 créer les applications qui accueilleront les menus
 ajouter une ressource de type menu au projet (à l’aide de l’entête ressource View)
 personnaliser et ajouter les fonctionnalités au menu
 écriture et définition des caractéristiques des ressources de menus

La définition d’un menu dans une ressource permet de modifier l’aspect physique de celui-ci. Lorsque
l’utilisateur sélectionne une commande du menu, un message est généré pour gérer la fonctionnalité de cette
commande.
Comme toute autre ressource d’une application, on doit spécifier les caractéristiques des éléments du menu. Pour
cela on choisit la classe où gérer les messages, et créer les fonctions relatives aux messages de menu

Création de menu contextuel :


La majorité des applications Windows possèdent des menus appelés contextuels qui sont déclenchés par
l’utilisateur lorsqu’il clique le bouton droit de la souris, et qui sont souvent relatifs au contexte dans lequel ils
sont ouverts. Les options qu’il présente dépendent des objets sélectionnés ou de l’élément positionné par la
souris.
Pour inclure un menu contextuel dans une application, on doit prévoir les fonctions suivantes : une fonction sur le
message WM_RBUTTONDOWN et une fonction sur le message WM_ContextMENU. Ce dernier sera placé
dans une liste d’attente une fois le bouton relâché.
30
Amine BOUFAIED
Ajout de raccourci clavier :
Les raccourcis clavier sont de deux types : touche rapide et combinaison de touches (utilisant
généralement les touches Ctrl ou Alt). Ces raccourcis fonctionnent de manière analogue au menu. En, effet, ce
sont des raccourcis définis dans une table dans l’onglet ressource au sein de l’espace de travail, chaque entrée
dans la table se voit attribuer un identifiant d’objets et une combinaison de touches.

4.1. – Ajout d’une commande dans la barre d’un menu

Sélectionner l’onglet « RessourceView », déplier l’option « Menu » et choisir le menu dans lequel
on désire ajouter une commande.
Pour créer une nouvelle commande, faire glisser la zone vide à l’endroit désiré, et taper le nom de la
commande. Le « & » tapé devant une lettre du nom fera office de raccourci clavier.

Faire glisser la zone vide et


saisir le nom de la commande

Cocher cette case rend Si la case n’est pas cochée, l’entrée


le menu grisé et inactif est une commande de menu
simple, dépourvue de sous-menu.

4.2. – Ajout d’une commande dans le menu “Démo”


Cliquer sur la première commande du menu (encore vide) afin de la sélectionner puis remplir les options de la
boite des propriétés (« Menu Item Properties »).

Affiche une coche Entrer l’ID pour identifier la


en regard de la commande du menu
commande

31
Amine BOUFAIED Le texte tapé ici apparaît
dans la barre d’état
4.3. – Prise en charge des messages de menu par ClassWizard

Pour lancer ClassWizard cliquer sur le bouton droit de la souris et choisir ClassWizard.
Sélectionner l’ID et le type du message, cliquer sur Add Function et choisir le nom de la méthode qui
sera appelée à chaque sélection de la commande du menu (message COMMAND) ou à chaque mis à jour de la
commande du menu (message UPDATE_COMMAND_UI).

La sélection d’un type de message


Active le bouton Add function

Sélectionner l’ID du
Message à traiter

32
Amine BOUFAIED
Cliquer sur « Edit Code » génère le code du corps (vide) de la méthode OnElementDemo1()

/////////////////////////////////////////////////////////////////////////
////
// CDemoView message handlers

void CDemoView::OnElementDemo1()
{
// TODO: Add your command handler code here
}

ClassWizard incorpore également automatiquement les nouveaux gestionnaires de messages dans la table
de correspondance des messages de la classe associée au menu (CDemoView).

/////////////////////////////////////////////////////////////////////////
////
// CDemoView

Ajout d’une ligne de code qui ouvre une « message box » quand on sélectionne la commande « Démo1 » du
menu « Demo ».

/////////////////////////////////////////////////////////////////////////
////
// CDemoView message handlers

void CDemoView::OnElementDemo1()
{
// TODO: Add your command handler code here

AfxMessageBox (“Démonstration n°1“) ;

33
Amine BOUFAIED
4.4. – Ajout de boutons à une barre d’outils

Sélectionner l’onglet « RessourceView », déplier l’option « Toolbar » et cliquer deux fois sur
IDR_MAINFRAME. L’éditeur de ressources s’ouvre :

34
Amine BOUFAIED
Cliquer deux fois sur
le bouton ouvre la boite
Dessin du bouton des propriétés

Il est possible de sélectionner


un ID associé à une action
déjà existante ou de créer une
n o uv e ll e a c ti on av e c
ClassWizard (View dans le
menu de la fenêtre principale)

Dans l’exemple ci-dessus, on associe au nouveau bouton l’action de la commande « Démo1 » du menu « Demo
» (ouverture d’une « message box »).

35
Amine BOUFAIED
4.5. – Ajout d’infos-bulles
Il est possible d’ajouter aux boutons de la barre d’outils des zones de texte qui s’affichent
lorsque le curseur de la souris est positionné quelques secondes sur l’un des boutons : ce sont les « infos-
bulles ». Pour cela, sélectionner l’onglet « RessourceView », déplier l’option « String Table », ajouter et
cliquer deux fois sur l’ID du bouton. La fenêtre suivante apparaît :

Pour ajouter une info-bulle il suffit de mettre


« \n » au début de la chaîne de caractères

On obtient :

36
Amine BOUFAIED
37
Amine BOUFAIED 2008
3e partie : Création d'un agenda grâce aux MFC

Manipulation des données membres via UpdateData()

La fonction UpdateData permet au programme de récupérer, et d'initialiser les données membres des
contrôles d'une fenêtre (par exemple, le texte tapé dans un contrôle d'édition). En fournissant l'argument true à
cette fonction le programme récupère l'intégralité des données entrées par l'utilisateur via l'interface graphique, et
les stock dans les variables créées à cet effet.

L'opération inverse est bien évidement possible en passant l'argument false à la fonction UpdateData.
Dans ce cas, la valeur stockée dans la "Member Variable" est envoyée dans le contrôle lui étant rattaché. Ainsi, si
nous stockions dans m_nom la chaîne de caractères "Test", et que nous appelions la fonctions UpdateData(false),
le contrôle IDC_NOM aurait affiché "Test".

MFC + Liste chainée = CList

L'élaboration d'une liste chaînée, ainsi que le groupe de fonctions permettant de la manipuler étant une
opération relativement délicate, Microsoft à inclus dans les MFC la Class CList qui simplifie grandement
l'implémentation d'une liste chaînée dans une application. De plus un nombre impressionnant de méthodes
permettant de manipuler cette liste chaînée est disponible.

La déclaration d'une liste chaînée CList se fait de la manière suivante:

CList <Type_objet,Type_transfert&> Nom_liste;

Type_objet : le type d'élément qui composera la liste chaînée (par exemple CBox),

Type_transfert : représente la façon dont les éléments seront injectés dans la liste chaînée, ici il s'agit d'un
transfert par référence, il peut également se faire par pointeur ou par valeur (une copie donc),

Nom_liste : étant le nom de l'objet désignant notre liste chaînée. Cet objet possède une batterie de méthodes
permettant de manipuler la liste chaînée, en voici quelques une :

Accés de tête ou de fin de liste


GetHead Renvoie le premier élément de la liste
GetTail Renvoie le dernier élément de la liste

Opérations
RemoveHead Supprime le premier élément de la liste
RemoveTail Supprime le dernier élément de la liste
AddHead Insert un élément en tête de liste
AddTail Insert un élément en fin de liste
RemoveAll Supprime tous les éléments de la liste

Iteration
GetHeadPosition Retourne la postion du premier élément de la liste
GetTailPosition Retourne la position du dernier élément de la liste
GetNext Renvoie l'élément suivant
GetPrev Renvoie l'élément précédent

38
Amine BOUFAIED 2008
Récupération et modification
GetAt Renvoie un élément à une position donnée
SetAt Remplace l'élément d'une position par un autre

Insertion
Insert un élément juste avant celui se trouvant à la
InsertBefore
position précisée
Insert un élément juste aprés celui se trouvant à la
InsertAfter
position précisée

Recherche
Renvoie la position d'un élément passé en
Find
paramêtre
Renvoie la position, sur une base d'index de 0,
FindIndex
d'un élément passé en paramêtre

Status
GetCount Renvoie le nombre d'élement de la liste
IsEmpty Test si la liste est vide (aucun élément)

Pour plus d'information sur CList, consultez la MSDN de Visual C++.

Développement de l’Agenda

Notre programme Agenda va être créer afin d’illustrer ces nouvelles fonctionnalités

Nous allons donc développer un agenda qui stockera (en mémoire uniquement) le nom, prénom, adresse et
numéro de téléphone de contacts. Il sera possible d'ajouter, supprimer, modifier et de naviguer dans notre agenda.
Ces contacts seront gérés en mémoire via une liste chaînée de type CList.

Etape 1: Création de l'application MFC Agenda avec AppWizzard

Créer une application basée dialogue nommée Agenda.

Etape 2 : Insérer les contrôles de notre agendas comme nous l'avons fais avec "Hello World"

39
Amine BOUFAIED 2008
On continue, en attribuant à chaque contrôle facilement identifiable

IDs choisis dans notre exemple :

Contrôle d'édition pour le nom IDC_NOM


Contrôle d'édition pour le prénom IDC_PRENOM
Contrôle d'édition pour l’adresse IDC_ADRESSE
Contrôle d'édition pour le numéro de
IDC_PHONE
téléphone
Contrôle bouton suivant IDC_NEXT
Contrôle bouton précédent IDC_PREV
Contrôle bouton ajouter IDC_ADD
Contrôle bouton modifier IDC_MODIFY
Contrôle bouton supprimer IDC_DEL

Etape 3 : Ajouter les variables membres des contrôles avec ClassWizzard (Ctrl+W)

40
Amine BOUFAIED 2008
Etape 4 : Elaboration et ajout de notre class contact dans notre projet Agenda

Nos contacts seront en fait des objets d'une classe CContact ayant 4 variables membres publics de type CString :
nom, prenom, adresse et tel.

En voici la forme:

Class CContact
{
public :
CString nom, prenom, adresse, tel;
};

Pour insérer cette classe à notre projet il suffit de cliquer sur Agenda classes dans l'onglet ClassView:

41
Amine BOUFAIED 2008
Nous choisirons ensuite l'option Generic class comme type de class, car notre classe n'est pas une classe MFC:

Nous entrons le nom de notre classe, puis validons:

Il nous suffit maintenant d'ajouter les 4 membres de cette classe. Pour cela, nous faisons un clic droit sur notre
class CContact, et choisissont l'option Add Member Variable.

42
Amine BOUFAIED 2008
Nous recommençons cette opération pour chaque membre à ajouter dans notre classe contact.

Etape 5 : Déclaration de notre liste chaînée

Maintenant que nous avons notre classe CContact, nous pouvons déclarer notre liste chainée reposant sur ce type
de class (CContact). Pour se faire nous allons ajouter dans la déclaration de la classe AgendaDlg les lignes de
code suivantes :

Nous incluons la bibliothèque « Contact.h » afin de pouvoir manipuler des objets de la classe CContact dans
notre classe de dialogue, ainsi que la bibliothèque <Afxtempl.h> contenant la définition des types CList et
POSITION.

Nous déclarons ainsi un objet current représentant l’objet courant de la liste, un objet CList qui s'appelle
list_contact qui stockera sous forme d'une liste chaînée les différents contacts que nous entrerons, ainsi qu'une
variable current_pos de type POSITION représentant la position courante dans la liste chainée.

Ajout d’un objet tampon nommé current

Etant donné que les données récupérées avec UpdateData(true) ne sont pas retournées sous forme d'objet
CContact, nous devons créer un objet current dans lequel nous stockerons les valeurs récupérées par le
UpdateData.

Etape 6 : Editer la méthode OnAdd

Nous devons maintenant éditer le code de la fonction OnAdd pour que les informations entrées dans l'interface
soient insérées sous forme d'une entité de la liste chaînée:

Etape 7 : Editer la méthode OnModify

43
Amine BOUFAIED 2008
Ici nous allons utiliser la méthode SetAt pour modifier un contact à une position donnée:

void CAgendaDlg :: OnModify()


{
UpdateData(true) ;
current.nom = m_nom ;
current.prenom = m_prenom ;
current.adresse = m_adresse ;
current.tel = m_tel ;
List_contact.SetAt(current_pos, current) ;
m_nom = « « ;
m_prenom = « « ;
m_adresse = « « ;
m_tel = « « ;
UpdateData(false) ;
}

Etape 8 : Editer la méthode OnDel

Pour supprimer un élément de la liste chainée nous allons utiliser la méthode RemoveAt :

Etape 9 : Editer la méthode OnNext

Pour récupérer l'objet suivant dans la liste chaînée list_contact, il suffit d'appeler la méthode
GetNext(position_courante). Cette méthode renvoie l'élément suivant celui se trouvant à la position
position_courante. Il convient également de vérifier lors d'un appel à la fonction GetNext que nous ne "sortons
pas" de la liste chaînée et accédons à des zones mémoires protégées. Le code de la méthode OnNext est donc
celui ci:

Etape 10 : Editer la méthode OnPrev

Comme vous pouvez l'imaginer très peu de choses différencie cette méthode avec la précédente, nous appelons
tous simplement la méthode GetPrev, au lieu de GetNext et nous vérifions si nous ne somme pas au début de la
liste avec GetHeadPosition au lieu de GetTailPosition, le reste du code restant inchangé pour des raisons
évidentes.

44
Amine BOUFAIED 2008
Etape 11 : Compiler le projet et l'exécuter

Après avoir compilé le projet, nous pouvons voir que notre application fonctionne parfaitement bien, et gère
toutes les options que nous voulions !!!

La sérialisation : un puissant système de sauvegarde

Bien que notre programme agenda fonctionne parfaitement bien, il à un handicape majeur : les données sont
stockées en mémoire, résultat en quittant l'application, nous perdons l'intégralité des informations entrées.
Heureusement Microsoft Visual C++ 6.0 propose une solution permettant de gérer l'intégralité des données
manipuler par votre programme. Il s'agit de la sérialisation vue dans la partie précédente. Cette méthode permet
de sauvegarder des objets et de les recharger en mémoire avec un minimum d'effort, toute la partie concernant la
gestion du fichier de sauvegarde est géré par le processus de sérialisation. En fait tous ce qu'il nous reste à faire
c'est d'implémenter cette méthode dans nos classes, et de procéder à une sauvegarde ou à un chargement des
objets du programme en fonction des besoins de l'utilisateur.

Nous nous servirons donc de la sérialisation pour stocker les informations manipulées par notre agenda, c'est à
dire notre liste chaînée contenue dans l'objet list_contact.

Une meilleure solution serait d’utiliser et de gérer des bases de données.

45
Amine BOUFAIED 2008
4ème
partie Connexion aux sources de données

Introduction

La prise en charge des bases de données par les MFC fait appel à SQL pour formuler les requêtes et opérations
exécutées sur les tables de base de données, par l'intermédiaire d'un ensemble de classes spécialisées.

Les requêtes SQL sont transmises sous forme de chaînes. Si le nom d'une table comporte des espaces comme
Product ID, la syntaxe SQL exige qu'il soit placé entre guillemets comme "Product ID".

Ex1: SELECT "Product ID" FROM Products

Or en C++ les guillemets délimitent les chaînes de caractères ce qui prête confusion si nous encadrons le nom des
objets de base de données (lignes ou colonnes) par des guillemets. C'est pourquoi, lorsque nous référençons dans
l'environnement Visual C++ une table de base de données ou un nom de colonne comprenant des espaces, nous
devons remplacer les guillemets par les crochets. En l'occurrence, écrivons [Product ID].

Ex2: SELECT [Product ID] FROM Products

Les MFC abordent les bases de données selon deux approches chacune d'elle utilisant son propre jeu de classes
MFC. Il s'agit de DAO et ODBC. Mais il y en a de plus récentes comme OLE DB et ADO.NET.

La première approche DAO (Data Acess Objects) propose une interface avec le moteur de base de données Jet,
élément logiciel généralisé qui permet de stocker des données dans divers systèmes de gestion de base de
données et de les extraire.

Jet est le moteur utilisé par le SGBD Microsoft Access. Chaque fois que vous manipulez une base de données
sous Access, c'est en réalité Jet qui fournit l'essentiel du travail. Jet est optimisé pour l'accès direct aux fichiers de
base de données Access (.mdb), mais il vous permet également de vous connecter à toute base de données
prenant en charge ODBC. Outre Microsoft Access, Jet vous permet d'accéder à des bases de données comme
Oracle, dBase 5, Btrieve 6.0 et FoxPro 2.6...

La seconde approche est spécifique à ODBC (Open DataBase Connectivity). Vous pouvez manier des bases de
données de tout format pour lesquelles vous possédez le pilote ODBC approprié et même pour les fichiers .mdb
d'Access.

Le standard ODBC (Open DataBase Connectivity)

Le standard ODBC de Microsoft définit aussi bien la syntaxe de SQL qu’une interface de programmation avec
une base de données SQL. Une application écrite dans n’importe quel langage (C, C++, JAVA, etc…) peut
accéder à n’importe quel système de gestion de base de données (SGBD) disposant d’un pilote ODBC. Visual
C++ contient des pilotes ODBC pour les fichiers DBF, les bases de données mbd, les fichiers xsl,… D’autres
fournisseurs de SGBD offrent leurs propres pilotes.

Classes MFC pour ODBC

ODBC fait appel aux cinq classes suivantes:

CDatabase : Un objet de cette classe représente une connexion à votre base de données, que vous devez établir
avant d'effectuer des opérations sur la base de données. Aucune classe d'espace de travail n'est utilisée avec une
base de données ODBC.

CRecordset : Un objet d'une classe dérivée de cette classe représente le résultat d'une opération SQL SELECT, Il
s'agit du concept mentionné lors de la description de la classe CDaoRecordset

CRecordView : Un objet d'une classe dérivée de cette classe permet d'afficher les informations en cours d'un jeu

46
Amine BOUFAIED 2008
de lignes associé. Il s'agit du concept mentionné lors de la description de la classe CDaoRecordView

CFieldExchange : Cette classe permet l'échange de données entre la base de données et un jeu de lignes, comme
pour les bases de données DAO.

CDBException : Les objets de cette classe constituent des exceptions survenant dans les opérations de base de
données ODBC.

Les fonctions membres de CRecordset

Fonctions Description
Open Ouvre le Recordset
AddNew Prépare l’ajout d’un nouvel enregistrement à la table
Update Complète une opération AddNew ou Edit en enregistrant les modifications
Delete Supprime l’enregistrement courant du Recordset
Edit Prépare la modification de l’enregistrement courant
IsBOF Teste si le curseur se trouve au début du Recordset
IsOEF Teste si le curseur se trouve à la fin du Recordset
MoveNext Se déplace vers l’enregistrement suivant
MoveFirst Se déplace vers le premier enregistrement
MoveLast Se déplace vers le dernier enregistrement
MovePrev Se déplace vers l’enregistrement précédent
GetDefaultConnect Obtient la chaîne de connexion par défaut de la source de données sur laquelle
s’appuie le RecordSet
GetDefaultSQL Obtient la chaîne SQL par défaut
DoFieldExchange Échange des données entre les variables associées au recordset et l’état
d’achèvement du comptage
GetRecordCount Obtient l’indice maximal rencontré par l’utilisateur au cours de ses déplacements
dans le recordset
GetODBCFieldCount Lit le nombre de champs du recordset
GetODBCFieldInfo Lit des informations sur les champs du recordset

Premier exemple

Commencer par créer la structure de la base de données sous par exemple MsAccess que vous avez vu en cours
de Bases de Données. Créer les clés et les relations entre les tables.

Ensuite configurer ODBC :

1. Sélectionner le pilote
2. Attribuer un nom à la source de données
3. Finalement, associer une base de données à la source

47
Amine BOUFAIED 2008
Créer l’application qui va utiliser la base de données
 Choisir comme projet MFC AppWizard
 Choisir SDI
 Dans la boite de dialogue sur les bases de données choisir Database view without file support
 Choisir la source de données
 Choisir les tables sur lesquelles vous voulez travailler
 Continuer les étapes restantes avec les options par défaut

Gestion de la base de données :

Dans la fenêtre de dialogue, créer votre interface qui doit contenir les champs de votre table. L’edit box de votre
clé primaire doit être « read only ». Puis, associer des variables membres de la classe View à chacun des edit
boxes. Ces variables membres sont de la forme m-pSet->…, où les trois points sont les variables membres de la
classe Set.

Ajout et suppression d’enregistrements :

Les classes CRecordSet et CRecordView permettent de réaliser toutes les tâches à réaliser sur une base de
données.
Dans un premier, rajouter les menus de suppression et d’ajout correspondant dans le menu « enregistrement »,
ainsi que leurs boutons dans la barre d’outils. N’oubliez pas de connecter les boutons aux menus.

48
Amine BOUFAIED 2008
Ajout et suppression d’un enregistrement à une table :

Ouvrir le fichier View.h file. Dans la section des attributs de la déclaration de la classe, rajouter les lignes
suivantes :

protected:
BOOL m_bAdding;

Double-cliquer sur le constructeur de la classe View et rajouter la ligne suivante à sa fin :

m_bAdding = FALSE;

Dans la fonction membre à la classe View associée à la commande d’ajout ajouter les lignes de code suivant :

void CBaseView::OnRecordAdd()
{
// TODO: Add your command handler code here
m_pSet->AddNew();
m_bAdding = TRUE;
CEdit* pCtrl = (CEdit*)GetDlgItem(IDC_EMPLOYEE_ID);
int result = pCtrl->SetReadOnly(FALSE);
UpdateData(FALSE);
}

OnRecordAdd() débute par l’appel à la function member AddNew() de CEmployeeSet, la classe dérivée de CRecordSet. Ceci crée un enregistrement
vide à remplir par l’utilisateur.

Après que l’utilisateur crée un nouvel enregistrement, la base de données doit être mise à jour. Pour cela, m_bAdding est mis à TRUE pour finaliser
l’opération d’ajout.

Maintenant, comme l’utilisateur veut entrer un nouvel enregistrement, il devait être possible de changer le contenu du champ Employee ID, qui est
pour le moment mis à read-only. Afin de changer l’état read-only du contrôle, le programme obtient en premier lieu un pointeur sur le contrôle avec
GetDlgItem() et après appelle la fonction membre du contrôle SetReadOnly() afin de mettre l’attribut read-only à FALSE.

Finalement, l’appel à UpdateData() affiche le nouvel enregistrement vide.

Ensuite, choisir pour votre classe View “Add Virtual Function” et sélectionner OnMove. Cliquer sur “Add and
Edit ». Enfin insérer le code suivant :

BOOL C…View::OnMove(UINT nIDMoveCommand)


{
if (m_bAdding)
{
m_bAdding = FALSE;
UpdateData(TRUE);
if (m_pSet->CanUpdate())
m_pSet->Update();
m_pSet->Requery();
UpdateData(FALSE);
CEdit* pCtrl = (CEdit*)GetDlgItem(IDC_EMPLOYEE_ID);
pCtrl->SetReadOnly(TRUE);
return TRUE;
}
else
return CRecordView::OnMove(nIDMoveCommand);
}

49
Amine BOUFAIED 2008
Maintenant que l’utilisateur a un enregistrement vide sur l’écran, il est simple de remplir les edit controls avec les données nécessaires. Afin
d’ajouter le nouvel enregistrement à la base de données, l’utilisateur doit se déplacer vers un nouvel enregistrement, une action qui force un appel à
la fonction membre OnMove() de la classe View.

Quand OnMove() est appelée, la première chose que le programme fait est de vérifier la variable booléenne m_bAdding afin de voir si l’utilisateur
est entrain d’ajouter un nouvel enregistrement ou non. Si m_bAdding est à FALSE, la clause du else est exécutée. Dans la clause du else, le
programme appelle la version de la classe de base (CRecordView) de OnMove(), qui simplement déplace vers le prochain enregistrement.

Si m_bAdding est à TRUE, le corps du if est exécuté. Alors, le programme initialise le drapeau m_bAdding et appelle ensuite UpdateData() afin de
transférer les données des contrôles de la fenêtre view à la classe du recordset. Un appel à la méthode CanUpdate() du recordset determine s’il est
possible ou pas de mettre à jour le data source, après quoi un appel à la fonction membre Update() du recordset rajoute le nouvel enregistrement au
data source.

Afin de reconstruire le recordset, le programme doit appeler la fonction membre Requery() du recordset, et après un appel à la fonction membre
UpdateData() de la fenêtre view transfère les nouvelles données aux contrôles de la fenêtre. Finallement, le programme remet le champ Employee ID
à read-only, avec un autre appel à GetDlgItem() et SetReadOnly().

Afin de pouvoir supprimer un élément de la table, rajouter le code suivant à la fonction membre de suppression :

void C…View::OnRecordDelete()
{
m_pSet->Delete();
m_pSet->MoveNext();
if (m_pSet->IsEOF())
m_pSet->MoveLast();
if (m_pSet->IsBOF())
m_pSet->SetFieldNull(NULL);
UpdateData(FALSE);
}

OnRecordDelete() appelle seulement la fonction Delete() du recordset. Quand un enregistrement est efface, un appel à MoveNext() du recordset
prépare l’enregistrement suivant pour être affiché.

Un problème peut apparaître quand l’enregistrement effacé était à la dernière position ou quand l’enregistrement efface est le seul enregistrement du
recordset. Un appel à la fonction IsEOF() du recordset déterminera si oui ou non le recordset est à sa fin. Si l’appel à IsEOF() retourne TRUE, le
recordset nécessite d’être repositionné sur le dernier enregistrement. La fonction MoveLast() du recordse s’occupe de cette tâche.

Quand tous les enregistrements ont été supprimés du recordset, le pointeur d’enregistrement sera au début de l’ensemble. Le programme peut tester
sur cette situation en appelant la fonction IsBOF() du recordset. Si cette fonction retourne TRUE, le programme écrit NULL dans les champs de
l’enregistrement courant.

Finalement, l’appel à UpdateData() affiche met à jour l’affichage dans la fenêtre view.

50
Amine BOUFAIED 2008

Vous aimerez peut-être aussi