• Aucun résultat trouvé

Les fichiers

N/A
N/A
Protected

Academic year: 2022

Partager "Les fichiers"

Copied!
14
0
0

Texte intégral

(1)

1

• La gestion des fichiers

• Architecture non Document/Vue

• Boîte de dialogue non modale Stockage des documents

Boîtes de dialogue

2

Les fichiers

„

La majorité des fonctions de bas niveau (API) de manipulations des fichiers sont encapsulées dans les MFC dans la classe CFile.

„

CFile propose les méthodes classiques d'ouverture, fermeture, écriture et lecture dans des fichiers.

„

Cependant les MFC proposent aussi une autre classe CArchive pour la gestion des fichiers largement employée dans les applications.

„

Ces deux classes sont liées à différents niveaux.

3

Les fichiers – La classe CFile

„ La classe CFile encapsule les fonctionnalités de l'API Win32 dédiées à la gestion des entrées/sorties (fichiers).

„ Elle comporte plus de 25 méthodes pour manipuler les fichiers :

„ ouverture, fermeture,

„ écriture, lecture

„ création, renommage, recherche d'informations,

„ autres …

„ La classe CFile possède

„ un attribut (protégé) : m_StrFileName qui contient le nom du fichier

„ un attribut (public) : m_hFile qui contient le numéro de handle associé au fichier.

„ Certaines fonctions comme :

„ GetFilePath, GetFileName, GetFileTitle

„ permettent de connaître le nom du complet du fichier

(z:\users\ihm\cours.doc) ou simplement le nom du fichier avec son extension (cours.doc) ou sans son extension (cours).

4

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„ Ouverture

„ Un fichier peut être ouvert

„ soit par appel explicite de la méthode Open.

„ soit de façon implicite par le constructeur de la classe.

„ 1 ère méthode : déclaration d'un objet de type CFile et utilisation de la méthode Open.

// déclaration d'un objet de type CFile CFile fich;

// ouverture du fichier

fich.Open("exemple.dat", CFile :: modeReadWrite);

„ La méthode Open retourne un booléen (BOOL) qui indique si l'opération d'ouverture s'est bien déroulée.

// ouverture avec test du résultat if (fich.Open("exemple.dat", CFile :: modeReadWrite)) { // tout est correct

………

} else

{// une erreur s'est produite

……..

}

5

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„

Ouverture

„

Lorsqu'une erreur se produit, une exception de type CFileException est déclenchée. Un objet de ce type peut être donné en 3 ème paramètre à la méthode Open.

CFileException e;

if (fich.Open("exemple.dat", CFile :: modeReadWrite, &e) { // tout est correct

}………

else{// une erreur s'est produite e.ReportError();

}

„

La classe CFileException dispose d'un attribut m_cause (public) qui décrit la cause de l'erreur. La méthode ReportError affiche le message d'erreur correspondant.

6

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„

2 ème méthode d'ouverture d'un fichier : par le constructeur

„

CFile fich("exemple.dat",CFile::modeReadWrite);

„

Si une erreur se produit, une exception de type CFileException est déclenchée.

„

C'est au programmeur de prévoir un gestionnaire approprié pour récupérer cette exception.

„

Aussi la partie de programme qui effectue l'ouverture d'un fichier doit être

„

contrôlée (par try)

„

et suivie de la définition du gestionnaire pour les

exceptions CFileException.

(2)

7

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers void sauvegarde(void)

{ try {

CFile fich("exemple.dat",CFile::modeReadWrite);

….

}

catch (CFileException *e) { e->ReportError();

e->Delete ();

} }

„

L'exception générée doit être « désallouée » par le gestionnaire.

8

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„

Les modes d'ouverture

„

CFile::modeCreate

„ création d'un nouveau fichier avec écrasement si fichier existant.

„

CFile::modeNoTruncate

„mode à combiner avec la valeur modeCreate.

„Si le fichier existe déjà, il n'est pas écrasé. Le fichier est donc soit créé s'il n'existe pas soit ouvert seulement s'il existe déjà.

„

CFile f("exemple.dat", CFile::modeReadWrite

|CFile::modeCreate | CFile :: modeNoTruncate).

„

création du fichier si inexistant, sinon ouverture sans écrasement.

9

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„

Les modes d'accès :

„

CFile::modeRead

„

accès en lecture seulement

„

CFile::modeReadWrite

„

accès en lecture/écriture

„

CFile::modeWrite

„

accès en écriture seulement

10

Les fichiers – La classe CFile

Ouvrir, fermer et créer des fichiers

„

Fermeture

„

La fermeture s'effectue simplement par la méthode Close.

„

fich.Close();

„

Cette fermeture peut aussi être faite par le destructeur.

„

Le destructeur de la classe CFile appelle Close si le fichier est encore ouvert.

11

Les fichiers – La classe CFile

Lecture, Ecriture

„ Lecture

„ La lecture se fait par la méthode Read.

„ virtual UINT Read( void*lpBuf, UINTnCount);

throw( CFileException );

„où lpBuf donne est un pointeur du buffer destiné à récupérer les données lues et nCount est le nombre (maximum) d'octets à lire.

„ exemple : void lire_fich();

{ CFile fich("exemple.dat", CFile::modeRead);

char texte[50];

// lecture de 10 caractères à stocker dans texte fich.Read(texte,10);

}…

„ La méthode GetLength permet de connaître la taille du fichier :

„ taille = fich.GetLength();

„ La méthode Read retourne le nombre d'octets effectivement lus. 12

Les fichiers – La classe CFile

Lecture, Ecriture

„

Lecture

„

Si une erreur se produit durant la lecture,

„

une exception de type CFileException est déclenchée.

„

La gestion de ces exceptions doit être faite

„

en contrôlant la zone d'appel de Read (par un bloc Try)

„

et en définissant un gestionnaire de traitement.

„

De nouveau

„

la variable (public) de CFile, m_cause est affectée au code d'erreur

„

et la méthode ReportError peut être utilisée dans le

gestionnaire pour connaître l'erreur.

(3)

13

Les fichiers – La classe CFile

Lecture, Ecriture

„ Ecriture

„ L'écriture dans un fichier est réalisée par ma méthode Write.

„ virtual void Write( const void*lpBuf, UINTnCount);

throw( CFileException );

„ Son utilisation est similaire à Read mais permet l'écriture.

„ Elle retourne le nombre d'octets effectivement écrits et déclenche une exception CFileException si problème.

„ Le pointeur donné en paramètre indique l'adresse de la zone contenant les données à écrire.

void ecrire_fich();

{ CFile fich("exemple.dat", CFile::modeWrite |CFile::modeCreate);

char texte[50]="Je suis le texte à sauvegarder";

// écriture des 10 premiers caractères fich.Write(texte,10);

}

14

Les fichiers – La classe CFile

Se positionner

„

Positionnement

„

Le positionnement direct dans le fichier peut être fait par la méthode Seek.

„ virtual LONG Seek( LONGlOff, UINTnFrom);

throw( CFileException );

„

lOff indique le nombre d'octets de déplacement du pointeur de fichier.

„

nFrom indique le mode de mouvement, il doit être l'une des trois valeurs suivantes :

„ CFile::begin bouge le pointeur de nOff octets à partir du début du fichier.

„ CFile::current bouge le pointeur de nOff octets à partir de la position courant du pointeur du fichier.

„ CFile::end bouge le pointeur de nOff octets à partir de la fin fichier (la valeur de déplacement doit dans ce cas être négative).

15

Les fichiers – La classe CFile

Se positionner

„

La méthode GetPosition peut être utilisée pour connaître la position courante.

„

virtual DWORD GetPosition( ) const;

throw( CFileException );

„

On peut aussi fixer la position courante du pointeur de fichier par les méthodes suivantes :

„

soit au début :

„void SeekToBegin( ); throw( CFileException );

„

soit à la fin :

„DWORD SeekToEnd( ); throw( CFileException );

„

On peut aussi changer la taille d'un fichier par :

„

virtual void SetLength( DWORD dwNewLen );

throw( CFileException );

16

Les fichiers – La classe CFile

Renommer, Supprimer

„

Renommage

„

CFile comporte une méthode Rename qui permet de renommer un fichier.

„

static void PASCAL Rename( LPCTSTR lpszOldName , LPCTSTR lpszNewName ); throw(

CFileException );

„

où pszOldName indique l'ancien nom

„

lpszNewName indique le nouveau nom

„

Cette méthode renomme le fichier spécifié, les répertoires ne peuvent pas être modifiés.

„

Cette méthode est équivalente à la commande REN.

17

Les fichiers – La classe CFile

Renommer, Supprimer

„ Renommage : exemple

„ pOldName et pNewName sont de type char *

„ L'appel de la méthode Rename est contrôlé car il peut produire une exception.

„ Un exemple de gestionnaire est décrit après le bloc Try,

„ il affiche en utilisant m_cause, les raisons du déclenchement de l'erreur.

try

{ CFile::Rename( pOldName, pNewName );

}

catch( CFileException, e ) { #ifdef _DEBUG

//afxDump envoi un message vers la fenêtre de Debug de Visual afxDump << "File " << pOldName << " not found, cause = "

<< e->m_cause << "\n";

#endif }

18

Les fichiers – La classe CFile

Renommer, Supprimer

„

Suppression

„

static void PASCAL Remove( LPCTSTR lpszFileName ); throw( CFileException );

„

où lpszFileName indique le nom du fichier à supprimer

„

La méthode Remove déclenche une exception si le fichier ne peut pas être détruit (ou est ouvert).

„

Cette méthode est équivalente à la commande DEL.

(4)

19

Les fichiers – La classe CFile

Renommer, Supprimer

„

Suppression : exemple

char* pFileName = "test.dat";

try {

CFile::Remove( pFileName );

}

catch ( CFileException e ) {

#ifdef _DEBUG

afxDump << "File " << pFileName << " cannot be removed\n";

#endif }

20

Les fichiers – La classe CArchive

„

Bien que la classe CFile fournissent toutes les méthodes nécessaires à la gestion des fichiers,

„

la majorité des applications MFC

„ n'utilisent pas directement la cette classe

„ mais réalisent les opérations d'écriture et de lecture dans les fichiers

„ à l'aide de la classe CArchive.

„

CArchive utilise les méthodes de la classe CFile mais MFC assure la surcharge des opérateurs de flots << et >> avec CArchive.

„

Dans les architectures de type Document/Vues des MFC,

„ des méthodes de gestion des archives sont proposées dans la classe Document

„ pour permettre une sauvegarde simple des données.

21

Les fichiers – La classe CArchive

„

Exemple de sauvegarde d'entiers à l'aide de CArchive.

CFile fich("exemple.dat",CFile :: modeWrite|CFile ::modeCreate);

int a=5,b=6;

„

L'écriture :

fich.Write(&a, sizeof((a));

fich.Write

(&b, sizeof((b));

„

peut être faite de façon équivalente à l'aide de la classe CArchive par

CArchive ar(&fich, CArchive::store);

ar << a << b;

22

Les fichiers – La classe CArchive

„

Exemple de Lecture d'entiers à l'aide de CArchive.

CFile fich("exemple.dat",CFile :: modeRead);

int a,b;

„

La lecture :

fich.Read(&a, sizeof((a));

fich.Read(&b, sizeof((b));

„

peut être faite de façon équivalente à l'aide de la classe CArchive par

CArchive ar(&fich, CArchive::load);

ar >> a >> b;

„

MFC permet la "sérialisation" d'un grand nombre de types y compris les classes CString, CTime, CTimeSpan, …, CSize, CPoint, CRect.

23

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

L'aspect le plus puissant du mécanisme de sérialisation proposé par les MFC est

„

le fait que l'on puisse créer des classes "sérialisables"

qui travaillent avec les opérateurs d'écriture et de lecture de la classe CArchive

„

sans avoir à surcharger les opérateurs de flots << et

>>.

„

Pour cela, il faut que la classe définie

„

soit une classe descendante directement ou indirectement de la classe CObject

„

car dans ce cas les MFC surchargent les opérateurs de flots pour les pointeurs vers des instances de classes dérivées de CObject.

24

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Si une erreur se produit lors de la sérialisation une exception est générée.

„

Le type de l'exception produite dépend de la nature de l'erreur.

„

CMemoryException indique un problème d'allocation mémoire,

„

CFileException indique une erreur d'entrée/sortie,

„

CArchiveException dans les autres cas.

(5)

25

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

La définition d'une classe « sérialisable » peut être faite en 5 étapes :

„

Etape 1 : Dériver la classe à construire de CObject (ou d'une héritière de CObject).

class CLine : public CObject { protected :

CPoint m_Start;

CPoint m_End;

public :

…….

}

26

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Etape 2 : Inclure la déclaration de la macro instruction DECLARE_SERIAL dans la classe.

class CLine : public CObject { protected :

CPoint m_Start;

CPoint m_End;

public :

…….

DECLARE_SERIAL(CLine) }

27

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Etape 3 : Surcharger la fonction « Serialize » de la classe de base et sérialiser les membres données de la classe dérivée.

class CLine : public CObject { protected :

CPoint m_Start;

CPoint m_End;

public :

void Serialize(CArchive& ar);

…….

}

void CLine :: Serialize(CArchive& ar) { CObject :: Serialize();

if (ar.storing ()) ar << m_Start << m_End;

else

ar >> m_Start >> m_End;

}

28

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Etape 4 : Définition d'un constructeur par défaut

„ Si la classe dérivée ne possède pas de constructeur par défaut, il est nécessaire d'en définir un.

„ Cette étape est nécessaire car lorsqu'un objet est lu à partir d'une archive,

„ MFC crée un nouvel objet et l'initialise avec les valeurs lues.

„ Le constructeur par défaut est utilisé à lors de cette étape.

class CLine : public CObject { protected :

CPoint m_Start;

CPoint m_End;

public :

CLine() { }; //nécessaire

CLine (CPoint p1, Cpoint p2) {m_Start=p1; m_End=p2;}

void Serialize(CArchive& ar);

…….

}

29

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Etape 5 : Inclure la macro IMPLEMENT_SERIAL dans l'implémentation de la classe

„

La macro instruction IMPLEMENT_SERIAL admet trois paramètres :

„ le nom de la classe,

„ le nom de la classe ancêtre,

„ un numéro relatif à la version (pour gérer différent formats de sauvegarde).

„

dans Line.cpp

„ IMPLEMENT_SERIAL (CLine, CObject, 1)

„ dans une version ultérieure, on pourrait avoir :

„ IMPLEMENT_SERIAL(CLine, CObject, 2|VERSIONABLE_SCHEMA)

30

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Stockage des documents dans l'application IHM

„

Dans le cas de l'application IHM

„ les documents à sauvegarder sont les objets de type CElement (via les classes dérivées CLine, CCercle, CRectangle).

„

Pour qu'une classe soit sérialisable,

„ il faut que toutes les classes utilisées dans ses données membres soient aussi sérialisables.

„

Les gestionnaires définis dans la classe CIHMDoc associés aux commandes :

„ Fichier | Ouvrir,

„ Fichier | Enregistrer,

„ Fichier | Enregistrer Sous

„

comportent du code pour la sérialisation des documents.

(6)

31

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Stockage des documents dans l'application IHM

„ CIHMDoc dérive de CDocument qui dérive elle-même de CObject.

„ La classe CIHMDoc comporte un constructeur par défaut, utilise la macro instruction DECLARE_DYNCREATE et surcharge la méthode Serialize.

class CIHMDoc : public CDocument {

protected: // create from serialization only CIHMDoc();

DECLARE_DYNCREATE(CIHMDoc)

………

// Operations public:

………

// Overrides

// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CIHMDoc)

public:

virtual BOOL OnNewDocument();

virtual void Serialize(CArchive& ar);

//}}AFX_VIRTUAL

………

} 32

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Stockage des documents dans l'application IHM

„

Trois niveaux de fonctionnalités sont disponibles dans les classes dérivées de CObject.

„

DECLARE_DYNAMIC(nom_classe) qui assure la prise en charge des informations de classe à l'exécution.

„

DECLARE_DYNCREATE(nom_classe) qui assure la création dynamique des objets et des informations de classe à l'exécution.

„

DECLARE_SERIAL(nom_classe) qui assure la prise en charge de la sérialisation des objets, de leur création dynamique et des informations de classe à l'exécution.

33

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Stockage des documents dans l'application IHM

„

Chaque niveau exige l'insertion de la macro correspondante dans le fichier contenant l'implémentation de la classe.

„ IMPLEMENT_DYNAMIC(nom_classe, nom_classe_ancêtre)

„ IMPLEMENT_DYNCREATE(nom_classe, nom_classe_ancêtre)

„ IMPLEMENT_SERIAL(nom_classe, nom_classe_ancêtre, numero)

„

La classe CIHMDoc n'a pas besoin de sérialisation mais les données membres doivent être sérialisables.

„

La macro IMPLEMENT_SERIAL a comme dernier argument un numéro qui est une numéro de version (appelé aussi numéro de schéma).

34

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

La classe CIHMDoc contient le code suivant :

IMPLEMENT_DYNCREATE(CIHMDoc, CDocument) void CIHMDoc :: Serialize (CArchive& ar) { if (ar.IsStoring())

{ // TODO : add storing code here } else { // TODO : add loading code here }

„

La méthode IsStroring() retourne

„ vraie si l'archive a été déclarée (par le constructeur) en mode stockage/écriture des données

„ et faux sinon.

„

De façon similaire, il existe une méthode IsLoading() de la classe CArchive qui teste si une archive est créée en mode chargement/lecture ou non.

35

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Donc la méthode « Serialize » permet soit la sauvegarde soit la restauration des données.

„

La classe CArchive surcharge les opérateurs de flots << et

>> sur les types :

„ float, double, BYTE, int, LONG, WORD, DWORD,

„ CObject *,

„ CString,

„ SIZE et CSize,

„ POINT et CPoint, RECT et CRect,

„ CTime et CTimeSpan (contient un intervalle en secondes).

„

On peut noter en particulier la surcharge sur CObjet * qui assure la surcharge sur les objets de CObjet * mais aussi de toutes ses classes dérivées.

36

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Sérialisation de la classe CElement

„

Définition dans CElement.h de la déclaration de la macro :

„

DECLARE_SERIAL(CElement)

„ Ne pas mettre cette macro dans une zone gérée par AppWizard.

„ Il est préférable de la mettre en 1 ère ligne pour éviter de l'oublier.

„

Définition de la macro dans CElement.cpp

„

IMPLEMENT_SERIAL(CElement, CObject,

VERSION_NUMBER)

(7)

37

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Définition de la méthode Serialize dans CElement.h

„ virtual void Serialize(CArchive& ar);

„ Implémentation de la fonction Serialize dans CElement.cpp void CElement::Serialize(CArchive& ar)

{ // Appel de la méthode Serialize de la classe de base CObject CObject::Serialize(ar);

if (ar.IsStoring())

{ /* Sauvegarde de la couleuret de l'épaisseur du crayon */

ar << m_Color << m_Pen;

}else

{ /* Restauration de la couleur et de l'épaisseur du crayon */

ar >> m_Color >>m_Pen;

}}

38

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Mise en œuvre de la sérialisation dans les classes CLine, CRectangle, CCercle.

„ Dans les constantes du programmes : // Numéro de version pour la sérialisation const UINT VERSION_NUMBER 1

„ Dans les déclarations des respectives des classes (.h) DECLARE_SERIAL (CLine)

virtual void Serialize(CArchive& ar);

DECLARE_SERIAL (CRectangle) virtual void Serialize(CArchive& ar);

DECLARE_SERIAL (CCercle) virtual void Serialize(CArchive& ar);

„ Dans les implémentations respectives des classes : IMPLEMENT_SERIAL(CLine, CElement, VERSION_NUMBER) IMPLEMENT_SERIAL(CRectangle, CElement, VERSION_NUMBER) IMPLEMENT_SERIAL(CCercle, CElement, VERSION_NUMBER)

39

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Implémentations des méthodes Serialize dans les classes respectives

void CLine::Serialize(CArchive& ar) {

// Appel de la méthode de la classe mère CElement::Serialize(ar);

//

Sauvegarde ou restaure les coordonnées des points extrémités

if (ar.IsStoring())

{ ar << m_Start << m_End; } else

{ ar >> m_Start >> m_End; } }

40

Les fichiers

La "sérialisation" des classes définies par le programmeur

void CRectangle::Serialize(CArchive& ar) {

// Appel de la méthode de la classe mère

CElement::Serialize(ar);

if (ar.IsStoring())

{ ar << m_TopLeft << m_BottomDown; } else

{ ar >> m_TopLeft >> m_BottomDown; } }

„

Il en est de même pour la classe CCercle avec les attributs m_center et m_r.

41

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Sérialisation de la classe CIHMDoc

„

Pour gérer la sauvegarde et la restauration des données,

„ il est nécessaire de savoir si des modifications ont été apportées au document ou non.

„

On va utiliser la fonction SetModifiedFlag héritée de la classe CDocument

„

void CDocument :: SetModifiedFlag( BOOL bModified = TRUE );

„

Cette méthode permet d'affecter un indicateur de modification du document en fonction de la valeur du paramètre (True ou False)

42

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Dans la classe CIHMDoc, l'ajout d'un élément et donc la modification du document est fait dans la méthode :

void CIHMDoc :: AddElement(CElement *pElement);

„

Nous allons donc insérer dans cette méthode un appel à la méthode SetModifiedFlag.

void CIHMDoc :: AddElement(CElement* pElement) {

m_ElementList.AddTail(pElement);

SetModifiedFlag();

}

(8)

43

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ On peut maintenant terminer la mise en place de la sérialisation dans la classe CIHMDoc en implémentant la méthode virtuelle Serialize

void CIHMDoc::Serialize(CArchive& ar) {

// Appel de la méthode Serialize sur la liste d'élement // CTypedPtrList<CObList, CElement*> m_ElementList;

m_ElementList.Serialize(ar); // Serialize the element list

// Sauvegarde ou restauration de la couleur courante, de l'élément courant, de l'épaisseur de la plume courante et de la taille du document.

if (ar.IsStoring()) {

ar << m_Color << m_Element << m_Pen << m_DocSize;

} else {

ar >> m_Color >> m_Element >> m_Pen >> m_DocSize;

}

} 44

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Les gestionnaires OnNewDocument, OnOpenDocument, On CloseDocument, OnSaveDocument

„ Ces gestionnaires ne sont pas surchargés dans CIHMDoc, ce sont les gestionnaires par défaut de la classe CDocument qui sont utilisés.

„ Le gestionnaire OnNewDocument.

„ Si l'on souhaite surcharger ce gestionnaire, on peut écrire : BOOL CIHMDoc ::OnNewDocument()

{ if (!CDocument::OnNewDocument()) return FALSE;

// TODO : Ajouter les initialisations souhaitées return TRUE;

}

45

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Le gestionnaire OnOpenDocument.

„ virtual BOOL OnOpenDocument( LPCTSTRlpszPathName);

„ Cette méthode retourne une valeur non nulle si l'opération s'est bien déroulée ou 0 sinon.

„ Le paramètre lpszPathName est le nom du document à ouvrir.

„ L'implémentation par défaut de ce gestionnaire :

„ ouvre le fichier spécifié,

„ appelle la méthode DeleteContents de la classe CDocument pour s'assurer que le document est bien 'vide',

„ appelle la méthode CObject::Serialize pour lire le document

„ et marque le document comme non modifié.

„ On peut surcharger ce gestionnaire si on souhaite mettre en œuvre un autre mécanisme que le principe de sérialisation proposé

46

Les fichiers

La "sérialisation" des classes définies par le programmeur

„

Le gestionnaire OnCloseDocument

„

virtual CDocument :: void OnCloseDocument( );

„

Appelé lors du choix Fichier -> Fermer.

„

L'implémentation par défaut :

„

détruit toutes les structures utilisées pour visualiser le document,

„

ferme les vues associées au document,

„

réinitialise le contenu du document,

„

appelle la méthode DeleteContent pour détruire les données du document.

47

Les fichiers

La "sérialisation" des classes définies par le programmeur

„ Le gestionnaire OnSave Document

„ virtual BOOL OnSaveDocument( LPCTSTRlpszPathName);

„ retourne une valeur non nulle si la sauvegarde s'est bien passée et 0 sinon.

„ Le paramètre lpszPathName désigne le nom du ficher de sauvegarde.

„ Appelé comme partie du traitement des commandes

„ Fichier -> Enregistrer

„ Fichier -> Enregistrer Sous

„ L'implémentation par défaut :

„ ouvre le fichier spécifié,

„ appelle la fonction CObject:: Serialize pour écrire le document dans le fichier,

„ marque le document comme non modifié.

„ On peut surcharger cette méthode pour réaliser des traitements spécifiques lors des opérations de sauvegarde.

48

Les fichiers

„

Conclusion

„

MFC fournit des nombreuses fonctionnalités pour la gestion des fichiers à travers les classes

„

CFile qui encapsule les méthodes de lecture et d’écriture bas niveaux, sur des fichiers

„

CArchive qui propose des mécanismes de sauvegarde

et restauration d’objets haut niveaux (sérialization)

(9)

49

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

On construit une application à l’aide de AppWizard,

„ Simple Document Interface,

„ sans utiliser l’architecture Document/Vue,

„ appelée DlgExemple

„

Le menu principal comporte par défaut :

„ Fichier -> Quitter

„ Edition -> Annuler, Couper, Copier, Coller

„ Affichage -> Barre d’outils, Barre d’état

„ ? -> A propos de ...

„

Le squelette généré comporte

„ 4 classes :

„CMainFrame // objet fenêtre cadre

„CDlgExempleApp // objet application

„CChildView // objet vue

„CAboutDlg // boîte de dialogue gérée par // ? A propos de …

50

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

L'application comporte en plus du squelette généré, un sous-menu : Fichier -> Options

„

Le choix du sous-menu Options fait apparaître la fenêtre de dialogue

„

Le programme affiche simplement un rectangle dans le coin haut droit de la fenêtre en respect des

spécifications données dans le menu Options.

„

Par défaut, la largeur et la longueur sont de 2 pouces.

51

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

La boîte de dialogue Options permet

„

de paramétrer la taille du rectangle

„

et d'appliquer ces modifications directement sans fermer la boîte de dialogue par le choix Appliquer.

„

Les options

„Fermer ferme la boîte de dialogue et

„Défaut réinitialise les paramètres à leurs valeurs initiales.

„

La boîte de dialogue ouverte est non modale i.e.

„

on peut effectuer d'autres opérations en conservant la boîte de dialogue ouverte.

52

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 1 : Création du projet à l'aide AppWizard

„

Les classes créées sont :

„

CAboutDlg, CChildView, CMainFrame et CDlgExempleApp.

„

La classe CChildView comporte une surcharge de la méthode OnPaint

void CChildView::OnPaint()

{ CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here }

53

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 2 : Ajout de nouveaux attributs dans la classe CChildView.

„

Trois options de dessin sont gérées dans le programme :

„ la largeur et la longueur du rectangle et l'unité de mesure.

„

On ajoute donc les trois variables :

„ m_Largeur, m_Longueur et m_Unite

„

Ces attributs sont initialisés dans le constructeur de la classe CChildView.

CChildView::CChildView() {

m_Largeur = 2;

m_Longueur =2;

m_Unite =0; // l’unité est le pouce }

54

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Etape 3 : Surcharge de la méthode OnPaint de la classe CChildView.

„ La méthode OnPaint affiche le rectangle dans la vue en fonction de l'unité choisie.

void CChildView::OnPaint() {CPaintDC dc(this);

CBrush brush (RGB (255, 0, 255));

dc.SelectObject (&brush);

switch (m_Unite) {

case 0: // Pouces

dc.SetMapMode (MM_LOENGLISH);

dc.Rectangle (0, 0, m_Largeur * 100, -m_Longueur * 100); break;

case 1: // Centimètres dc.SetMapMode (MM_LOMETRIC);

dc.Rectangle (0, 0, m_Largeur * 100, -m_Longueur * 100); break;

case 2: // Pixels dc.SetMapMode (MM_TEXT);

dc.Rectangle (0, 0, m_Largeur, m_Longueur); break;

} }

(10)

55

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Etape 4 : Ecrire un gestionnaire de message (OnCreate) pour le message WM_CREATE.

„ Dans cette architecture, la création de la fenêtre vue peut être faite par le gestionnaire OnCreate dans la classe CMainFrame.

„ La création est faite en utilisant la méthode Create de la classe CWnd.

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) return -1;

return 0;

}(cf Documentation CWnd :: Create) – Cette création est générée dans le

squelette de l’application 56

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Etape 5 : Création de la ressource boîte de dialogue

„ La boîte de dialogue est créée à l'aide de l'éditeur de ressources de AppWizard

„ La boîte de dialogue comporte :

„ 2 contrôles STATIC pour les messages Largeur, Longueur.

„ 2 contrôles EDIT pour la saisie de ces valeurs.

„ 3 contrôles BUTTON pour Appliquer, Fermer et Défaut.

„ 3 boutons radio groupés : Pouces, Centimètres et Pixels dans un contrôle STATIC (Unités).

57

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ L'option WS_GROUP permet de grouper certains contrôles.

„ Les contrôles groupés sont ceux compris entre deux WS_GROUP. Ici, les trois boutons radio.

Ceci permet d'avoir automatiquement un seul choix possible parmi les boutons groupés.

„ Le bouton OK est celui défini par défaut lorsque l'utilisateur utilise la touche entrée.

„ On peut aussi définir l'ordre de parcours de contrôles avec la touche tab en utilisant le menu Format -> Ordre de

tabulation. 58

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

On peut vérifier que des contrôles sont groupés en utilisant le menu

„

Format -> Tester la boîte de dialogue

„

Cliquer sur le premier contrôle et à l'aide des flèches haut, bas on peut se déplacer en boucle sur les contrôles groupés.

59

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 6 : Création de la classe COptionsDialog

„

On définit dans la classe COptionsDialog

„

3 attributs pour gérer les options :

„ m_Largeur, m_Longueur et m_Unite.

„

Lors de la création de la classe COptionsDialog par ClassWizard sur la boîte dialogue

IDD_OPTIONS,

„

Le constructeur et la méthode DoDataExchange sont automatiquement générés.

„

On ajoute ensuite les variables.

60

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Ces attributs/variables sont associés aux 3 contrôles de la boîte de dialogue:

„

Pour la longueur (IDC_LONGUEUR)

„

Pour la largueur (IDC_LARGEUR)

„

Pour les 3 boutons radio groupés (1er bouton)

(IDC_POUCES)

(11)

61

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 7 : Mise à jour du menu principal et création du gestionnaire

„ pour le menu Fichier -> Options

„ La boîte de dialogue est gérée en mode non modal.

„ Le gestionnaire OnFichierOptions va donc prendre en charge :

„ l'allocation d’un pointeur sur un objet de type COptionsDialog, pour gérer la boîte de dialogue

„ l'initialisation des champs,

„ la création de la boîte (lien avec la ressource IDD_OPTIONS) et l'affichage de cette boîte.

„ Un pointeur sur cette boîte est défini dans la classe CChildView.

62

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

void CChildView::OnFichierOptions()

„

{ // Si la boîte existe, on l'affiche.

if (m_pDlg != NULL) m_pDlg->SetFocus ();

// Si la boîte n'existe pas, on la crée.

else {

m_pDlg = new COptionsDialog;

m_pDlg->m_Largeur = m_Largeur;

m_pDlg->m_Longueur = m_Longueur;

m_pDlg->m_Unite = m_Unite;

m_pDlg->Create (IDD_OPTIONS);

m_pDlg->ShowWindow (SW_SHOW);

} }

63

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 8 : Création des gestionnaires pour les contrôles : Appliquer et Fermer.

„

Une différence fondamentale entre la gestion des boîtes modales et non modales est la manière dont les gestionnaires OnOk et OnCancel sont définis.

„

Pour les boîtes modales,

„ La méthode OnCancel est rarement redéfinie car son implémentation dans la classe CDialog appelle EndDilaog pour fermer la boîte et retourne IDCANCEL.

„ De même, la méthode OnOK de CDialog appelle OnUpdateData pour mettre à jour les attributs de la boîte de dialogue avant de fermer la boîte.

„ Si les contrôles de la boîte et les attributs sont liés par les mécanismes DDX et DDV, l'action par défaut CDialog::OnOk est en général suffisante.

64

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Pour les boîtes non modales,

„

Les méthodes OnOK et OnCancel doivent presque toujours être surchargées.

„

Il faut donc éviter que les méthodes :

„

CDialog::OnOK et CDialog::OnCancel soient appelées.

„

Les boîtes de dialogue non modales doivent être fermées par DestroyWindow.

„

Dans l'exemple, les deux boutons

„

Appliquer (IDOK) et Fermer (IDCANCEL) génèrent des appels à OnOK et OnCancel,

„

il faut donc surcharger ces méthodes.

65

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Principe de gestion des messages pour les boutons Appliquer et Fermer

„ Les méthodes OnOK et OnCancel sont surchargées dans la classe COptionsDialog.

„ Ces méthodes émettent un message vers la fenêtre principale qui le traite et le retransmet vers la vue qui termine le traitement.

COptionsDialog OnOK, OnCancel

CMainFrame OnAppliquer, OnDialogDestroyed WM_USER_APPLY

WM_USER_DIALOG _DESTROYED

CChildView OnAppliquer, OnDialogDestroyed

WM_USER_APPLY

WM_USER_DIALOG_D ESTROYED

66

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Définitions des gestionnaires dans la classe COptionsDialog.

void COptionsDialog::OnOK () {

UpdateData (TRUE);

RECTPROP rp;

rp.Largeur = m_Largeur;

rp.Longueur = m_Longueur;

rp.Unite = m_Unite;

AfxGetMainWnd ()->SendMessage (WM_USER_APPLY_, 0, (LPARAM)

&rp);

}

„ UpdateData(TRUE) permet la mise à jour des données de la boîte de dialogue.

„ Ces valeurs sont stockées dans une structure RECTPROP pour être transmises en paramètres vers la fenêtre principale à l'aide d'un message utilisateur WM_USER_APPLY (correspondant au choix de l'option Appliquer).

(12)

67

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ La définition de la structure RECTPROP est définie de la façon suivante:

typedef struct tagRECTPROP { int Largeur;

int Longueur;

int Unite;

} RECTPROP;

Elle peut être incluse dans le fichier stdafx.h

„ WM_USER_ sont des messages utilisateur définis sous la forme suivante dans stdafx.h.

#define WM_USER_APPLY WM_USER+0x100

#define WM_USER_DIALOG_DESTROYED WM_USER+0x101 WM_USER qui est défini à l'adresse 0x400 dans le fichier Winuser.h

spécifie la borne inférieure des adresses utilisables pour des messages utilisateurs sans provoquer de conflits avec les messages standard de Windows.

WM_USER_APPLY est arbitrairement défini à cette adresse + 0x100.

68

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Le gestionnaire OnCancel détruit la fenêtre en utilisant la méthode DestroyWindow de CDialog.

void COptionsDialog::OnCancel () {

DestroyWindow ();

}

„

La méthode OnOK émet un message

WM_USER_APPLY vers la fenêtre principale. Ce message doit donc être géré par cette classe.

69

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Gestion des messages dans la classe CMainFrame

„

Déclaration du gestionnaire dans la table des messages de CMainFrame :

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame)

ON_WM_SETFOCUS() ON_WM_CREATE()

ON_MESSAGE(WM_USER_APPLY,OnAppliquer) //}}AFX_MSG_MAP

END_MESSAGE_MAP()

70

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Définition du gestionnaire :

LRESULT CMainFrame::OnAppliquer (WPARAM wParam, LPARAM lParam) { // m_wndView désigne la vue de type CChildView

m_wndView.SendMessage (WM_USER_APPLY, wParam, lParam);

return 0;

}

„

La méthode OnAppliquer de la fenêtre principale envoie un message vers la vue.

„

On doit donc définir un gestionnaire pour ce message (WM_USER_APPLY) dans la classe CChildView.

71

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Gestionnaires de la classe CChildView

„

Déclaration du gestionnaire dans la table des messages de CChildView :

BEGIN_MESSAGE_MAP(CChildView,CWnd ) //{{AFX_MSG_MAP(CChildView) ON_WM_PAINT()

ON_COMMAND(ID_FICHIER_OPTIONS, OnFichierOptions) ON_MESSAGE(WM_USER_APPLY, OnAppliquer);

//}}AFX_MSG_MAP END_MESSAGE_MAP()

72

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Définition du gestionnaire :

LRESULT CChildView::OnAppliquer (WPARAM wParam, LPARAM lParam) {

RECTPROP* prp = (RECTPROP*) lParam;

m_Largeur = prp->Largeur;

m_Longueur = prp->Longueur;

m_Unite = prp->Unite;

Invalidate ();

return 0;

}

„

Le gestionnaire récupère en paramètre les valeurs des

attributs à appliquer et les affecte aux attributs de la vue,

qui est invalidée pour être repeinte par OnPaint.

(13)

73

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Gestionnaire OnCancel dans la classe COptionsDialog,

„ OnCancel appelle la méthode DestroyWindow.

„ Cette fonction appelle pour terminer la méthode COptionsDialog::PostNcDestroy qui doit donc être définie.

void COptionsDialog::PostNcDestroy () { CDialog::PostNcDestroy ();

AfxGetMainWnd()->

SendMessage(WM_USER_DIALOG_DESTROYED, 0, 0);

delete this;

}

„ Cette méthode envoie un message à la fenêtre principale pour signaler la terminaison de la boîte de dialogue.

„ Ce message doit donc être récupéré par la fenêtre principale qui pourra ainsi transmettre ce message à la vue et la vue réinitialisera l'attribut m_pDlg à NULL.

74

Application SDI – Non Document/Vue Boîte de dialogue non modale

„ Dans la classe CMainFrame :

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_SETFOCUS() ON_WM_CREATE()

ON_MESSAGE(WM_USER_APPLY,OnAppliquer)

ON_MESSAGE(WM_USER_DIALOG_DESTROYED,OnDialogDestroyed) //}}AFX_MSG_MAP

END_MESSAGE_MAP()

„ Définition du gestionnaire :

LRESULT CMainFrame::OnDialogDestroyed (WPARAM wParam, LPARAM lParam) {

m_wndView.SendMessage (WM_USER_DIALOG_DESTROYED, wParam, lParam);

return 0;

}

75

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Dans la classe CChildView :

BEGIN_MESSAGE_MAP(CChildView,CWnd ) //{{AFX_MSG_MAP(CChildView) ON_WM_PAINT()

ON_COMMAND(ID_FICHIER_OPTIONS, OnFichierOptions) ON_MESSAGE(WM_USER_APPLY, OnAppliquer);

ON_MESSAGE(WM_USER_DIALOG_DESTROYED, OnDialogDestroyed) //}}AFX_MSG_MAP

END_MESSAGE_MAP()

„

Définition du gestionnaire :

LRESULT CChildView::OnDialogDestroyed (WPARAM wParam, LPARAM lParam)

{

m_pDlg = NULL;

return 0;

}

76

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Etape 9 : Définition du gestionnaire pour le bouton Défaut

„

Le bouton Défaut provoque la réinitialisation des valeurs de largeur, longueur et unité aux valeurs initiales.

„

Le gestionnaire est défini dans la classe COptionsDialog.

„ Il affecte les valeurs aux attributs et demande une mise à jour des informations.

BEGIN_MESSAGE_MAP(COptionsDialog, CDialog) //{{AFX_MSG_MAP(COptionsDialog) ON_BN_CLICKED(IDC_DEFAUT, OnDefaut) //}}AFX_MSG_MAP

END_MESSAGE_MAP()

„ Le message géré est de type ON_BN_CLICKED , message lié à un clic sur un bouton.

77

Application SDI – Non Document/Vue Boîte de dialogue non modale

void COptionsDialog::OnDefaut() {

m_Largeur = 4;

m_Longueur = 2;

m_Unite = 0;

UpdateData (FALSE);

}

„

La méthode UpdateData(FALSE) demande le transfert des variables de la classe (m_Largeur,

…) vers les contrôles de la boîte de dialogue.

78

Application SDI – Non Document/Vue

Boîte de dialogue non modale

(14)

79

Application SDI – Non Document/Vue Boîte de dialogue non modale

„

Conclusion

„

L’environnement intégré de Visual Studio 2005 permet la création de différents squelettes d’applications C++

„

Document/vue (SDI ou MDI)

„

SDI sans Document/Vue

„

Basés sur des boîte de dialogues

„

Etc.

selon le type d’application envisagé.

Références

Documents relatifs

On pourrait croire naïvement qu’une sorte de graphe séparateur jouerait le rôle de la médiatrice (comme dans le cas précédent) : ce graphe séparerait le plan en trois régions,

La partie se termine lorsque qu’il n’est plus possible de jouer c’est à dire lorsque les combinaisons ne permettent plus de baisser les clapets ou lorsque l’un des

Résumé - La méthode zonale à coefficients d'absorption multiples (MACZM) pour la modélisation des facteurs de transferts radiatifs dans les milieux transparents et

Deux améliorations pourraient être envisagées pour réduire le temps de calcul de ce type de schéma (qui, comme on s'en rend compte, peut difficilement être inséré dans le

Résumé — Dans le cadre des développements asymptotiques raccordés, on propose une méthode ef- ficace et robuste pour modéliser le comportement élastique linéaire d’une

The micro reading task consisted in extracting GO terms from a single MEDLINE abstract, as in the Trieschnigg et al’s work; the macro reading task consisted in extracting GO terms

Pour chaque combinaison on simule 50 jeux de données de 130 individus avec 8 variables comme fichier originel, 100 individus comme fichier donneur et 30 individus

Dans l’architecture et comme dans tous les domaines le choix des couleurs doit être avoir une relation avec la nature de bâtiment et leurs fonctions, notre bâtiment a des