DEVELOPPEMENT ORIENTE OBJET VISUAL C++ - MFC et AppWizards - ELABORE PAR : Dr. Amine BOUFAIED www.functionx.com
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
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
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 > 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 > 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
Vous pouvez aussi lire