You are on page 1of 8

1.

I) Cration du Squelette
2.
3. Crer un projet MFC SimpleDocument (SDI) de nom "serialisation"
4. l'tape 4, lui donner une extension de fichier (.PTS)
5. gnrer le squelette d'application
6.
7.
8. II) Dessin simple
9.
10. Faire en sorte qu' chaque clic de souris, un nouveau point soit dessin l'cran la
position du clic
11. on pourra reprsenter le point par ses coordonnes sous la forme [x, y]
12.
13. Pour le dbutant, voici la dmarche pas pas :
14. il suffit de faire un clic droit dans l'onglet ClassView sur la classe
CSerialisationView
15. et de demander la gnration d'un gestionnaire de message pour windows "Windows
Message Handler"
16. On choisira le WM_LBUTTONDOWN (clic gauche) et add&edit
17. on rajoutera le code suivant dans le gestionnaire :
18.
19. void CSerialisationView::OnLButtonDown(UINT nFlags, CPoint point)
20. {
21.
// TODO: Add your message handler code here and/or
call default
22.
CString s;
23.
s.Format("[%d,%d]", point.x, point.y);
24.
CClientDC dc(this);
25.
dc.TextOut(point.x, point.y,s);
26.
CView::OnLButtonDown(nFlags, point);
27. }
28. fin de la dmarche pas pas :
29.
30. Tester l'application en faisant quelques clics sur le fond de la fentre
31. Et vrifier le mauvais comportement de l'application lors des redimensionnements de
la fentre
32. ou de minimisation-restauration.
33.
34. III) Dessin et Mmorisation
35.
36. On notera que si les points sont simplement dessins et non archivs dans la classe
CDocument
37. tout rafrachissement de la fentre (un redimensionnement par exemple) fait
disparatre tous les points
38.
39. A) On a donc besoin chaque clic de souris d'ajouter le point une collection du
document
40. et de le dessiner
41. ATTENTION ! la classe CPoint n'est pas drive de CObject

42. Le but de cet article tant de traiter la srialisation ( la MFC) et le PREMIER


PRINCIPE respecter
43. pour tre une classe srialisable tant de driver de CObject :
44. => Il faut donc crer notre propre classe de Point, on pourra la nommer CObjectPoint
et lui donner
45. un constructeur acceptant un CPoint et une donne membre de type CPoint
(rutilisation par composition)
46. Prendre bien soin de conserver le constructeur par dfaut car il est exig en vertu du
DEUXIEME PRINCIPE
47. de la srialisation.
48. B) De plus, dans l'vnement WM_PAINT de la vue, il faut redessiner tous les points.
49. Il faut donc tre capable d'itrer sur la collection prive et nous fournirons en prenant
exemple
50. sur la conception (le Design) de la classe CObArray les mthodes GetSize et GetAt.
51.
52. Pour le dbutant, voici la dmarche pas pas :
53. Crer une nouvelle classe CObjectPoint
54. Clic droit dans ClassView sur le projet (serialisation classes) puis new class
55. On doit prendre une classe gnrique (non MFC) car la classe CObject n'est pas vue
de l'assistant
56. nommer la classe CObjectPoint (les fichiers "objectPoint.h et .cpp" sont
automatiquement crs)
57. On modifiera le constructeur
58.
59. Modification du document :
60. Comme on utilisera le type CObjectPoint, ajouter la ligne suivante en tte de
"serialisationDoc.h"
61. #include "objectPoint.h"
62. Doter la classe drive de CDocument (CSerialisationDoc) d'un attribut priv de type
CObArray (tableau dynamique d'objets)
63. Modifier le code du gestionnaire OnLButtonDown pour ajouter un point dans la
collection chaque clic.
64. private:
65.
CObArray m_points;
66. Parce que notre collection est prive, on doit fournir une mthode d'encapsulation
Add(CPoint* pPoint)
67. Elle sera donc publique et son contenu :
68. void CSerialisationDoc::Add(CObjectPoint *pPoint)
69. {
70.
m_points.Add(pPoint);
71.
72. }
73. Modifier le gestionnaire OnLButtonDown en lui rajoutant la ligne suivante
74. GetDocument()->Add(new CObjectPoint(point));
75. Si vous vous demandez pourquoi faire un new (alloc dynamique)... rflchissez!
76.
77. Ajout de GetSize et GetAt (ne pas oublier les dclarations dans le .h)
78. int CSerialisationDoc::GetSize()
79. {
80.
return m_points.GetSize();

81. }
82.
83. CObjectPoint* CSerialisationDoc::GetAt(int index)
84. {
85.
return (CObjectPoint*)m_points.GetAt(index);
86. }
87.
88.
89. Grer le rafrachissement de la vue en traitant le WM_PAINT
90. Pour cela, il faut parcourir la collection de points et dessiner chacun d'eux.
91. Il est prfrable de demander chaque point de se dessiner lui-mme et nous crons
une mthode
92. Draw(CDC*) pour notre classe CObjectPoint (elle recevra le Device Context de
dessin):
93. void CObjectPoint::Draw(CDC* pDC)
94. {
95.
CString s;
96.
s.Format("[%d,%d]", m_point.x, m_point.y);
97.
pDC->TextOut(m_point.x, m_point.y,s);
98. }
99.
100.
Modification de la mthode OnDraw de la vue (c'est elle qui est appele lors
des WM_PAINT)
101.
void CSerialisationView::OnDraw(CDC* pDC)
102.
{
103.
CSerialisationDoc* pDoc = GetDocument();
104.
ASSERT_VALID(pDoc);
105.
// TODO: add draw code for native data here
106.
for (int i=0; i<pDoc->GetSize(); i++)
107.
pDoc->GetAt(i)->Draw(pDC);
108.
}
109.
110.
fin de la dmarche pas pas
111.
112.
On peut alors test l'application : elle fonctionne correctement mme lors des
redimensionnements...
113.
ou presque ... Avez vous essay le menu Fichier/Nouveau !
114.
115.
Les points ne disparaissent jamais et d'ailleurs ils ne sont jamais dtruits (pas
de delete => fuite mmoire)
116.
La bonne mthode (officielle MFC) est de redfinir la mthode virtuelle
DeleteContent
117.
Clic droit sur CSerialisationDoc / Add Virtual fonction / DeleteContents / Add
& Edit
118.
void CSerialisationDoc::DeleteContents()
119.
{
120.
// TODO: Add your specialized code here and/or
call the base class
121.
for (int i=0; i<m_points.GetSize(); i++)

122.
delete m_points[i]; //destruction des CObjectPoint
(libration du tas)
123.
m_points.RemoveAll(); //libration du conteneur
124.
CDocument::DeleteContents();
125.
}
126.
127.
Encore un point ncessaire !
128.
Dmarrer l'application, cliquer pour gnrer quelques points, puis fermer
l'application.
129.
Rien d'anormal ?
130.
Elle a oubli de nous proposer de sauvegarder notre document...
131.
Pour cela, nous devons passer l'tape suivante de srialisation mais on peut
tout de mme
132.
la prparer en appelant SetModifiedFlag() chaque fois que nous ajoutons un
point au document
133.
Donc dans la mthode Add.
134.
135.
136.
137.
IV) Srialisation de base
138.
139.
Si l'on referme l'application, les points tant simplement mis en mmoire vive,
ils sont perdus:
140.
Il faut donc les archiver sur disque, le plus simple tant d'utiliser le mcanisme
141.
de srialisation du framework
142.
Le TROISIEME PRINCIPE de la srialisation est de possder une mthode
Serialize
143.
Nous pouvons vrifier que notre classe document le vrifie dj ... mais pas
notre CObjectPoint
144.
On doit donc l'ajouter la classe :
145.
Clic droit sur CObjectPoint dans ClassView => ajouter une mthode...
146.
void CObjectPoint::Serialize(CArchive &ar)
147.
{
148.
if (ar.IsStoring())
149.
{
150.
// TODO: add storing code here
151.
ar << m_point;
152.
}
153.
else
154.
{
155.
// TODO: add loading code here
156.
ar >> m_point;
157.
}
158.
}
159.
160.
Quand et Comment cette mthode est elle appele ?
161.
Lorsque le document a besoin de se sauvegarder... par l'appui sur
fichier/Enregistrer par exemple.
162.
C'est donc via le document que l'appel a lieu
163.
On doit modifier le contenu de la mthode Serialize du document ainsi :

164.
void CSerialisationDoc::Serialize(CArchive& ar)
165.
{
166.
m_points.Serialize(ar);
167.
}
168.
169.
C'est presque fini pour le code ... on teste
170.
- d'abord l'enregistrement d'un document vide ... aucun clic => aucun point =>
OK
171.
on peut vrifier qu'un fichier l'extension .PTS a bien t cr
172.
- ensuite l'enreristrement d'un ducument non vide ! et un message d'erreur
apparat
173.
Il nous faut respecter le QUATRIEME PRINCIPE de la srialisation : utiliser
les MACROS
174.
DECLARE_SERIAL et IMPLEMENT_SERIAL
175.
rajouter la fin de la dfinition de la classe CObjectPoint (fichier
"objectPoint.h")
176.
DECLARE_SERIAL();
177.
178.
et au dbut du fichier objectPoint.cpp (mais aprs les includes)
179.
IMPLEMENT_SERIAL(CObjectPoint, CObject, 1)
180.
181.
Retester ...
182.
183.
184.
V) Srialisation avec gestion de version
185.
186.
On voit bien l'intrt de la srialisation ... conserver de faon persistante
(archive) les informations
187.
qui resteraient volatiles sinon.
188.
Le problme est que les logiciels voluent ... ils changent de version
189.
Que se passe t-il par exemple lorsque l'on veut traiter des points colors dans
une version 2 ?
190.
Gnralement, on ne change pas l'extension de fichier pour autant.
191.
La srialisation d'un document en version 1 suivi de la dsrialisation en
version 2 devrait bien se passer !
192.
193.
Pour cette raison, lors de la srialisation, un numro de version est archiv avec
le contenu
194.
et il peut tre rcupr lors de la dsrialisation pour savoir si l'on ne lit que des
CObjectPoint
195.
ou bien des CObjectPointCouleur !
196.
197.
Voyons ce que nous offre le framework MFC pour traiter la question :
198.
199.
La MACRO IMPLEMENT_SERIAL(CObjectPoint, CObject, 1) contient en
troisime paramtre le numro de version
200.
pour faire voluer le logiciel, il faut donc le modifier dans la version 2.
201.
202.
203.
Pour le dbutant, voici la dmarche pas pas :

204.
Partie traitant les points en couleur
205.
Parsque cet article se focalise sur la srialisation et non sur les bonnes pratiques
d'interfaces utilisateur,
206.
on grera la couleur courante dans la vue et un clic droit pour passer de rouge
bleu et rciproquement
207.
un menu droulant/menu contextuel/barre d'outil/boite de dialogue serait plus
adapt mais plus long dcrire
208.
209.
Ajouter une donne membre prive de type COLORREF appele m_couleur
la classe Vue (CSerialisationView)
210.
private:
211.
COLORREF m_couleur;
212.
Initialiser le "bleu" dans le constructeur
213.
m_couleur = RGB(0,0,255);
214.
215.
Grer le clic droit qui change la couleur courante:
216.
void CSerialisationView::OnRButtonDown(UINT nFlags, CPoint point)
217.
{
218.
// TODO: Add your message handler code here
and/or call default
219.
if (m_couleur==RGB(0,0,255))
220.
m_couleur=RGB(255,0,0);
221.
else
222.
m_couleur=RGB(0,0,255);
223.
224.
CView::OnRButtonDown(nFlags, point);
225.
}
226.
227.
Modifier la classe CObjectPoint pour suppporter la couleur
228.
ajouter une donne membre m_couleur, ajouter un Constructeur capturant la
couleur et initialiser.
229.
Modifier la mthode Draw du point pour tenir compte de la couleur
230.
pDC->SetTextColor(m_couleur);
231.
Modifier la mthode Serialize du CObjectPoint
232.
if (ar.IsStoring())
233.
{ ar << m_point << m_couleur; }
234.
else
235.
{ ar >> m_point << m_couleur; }
236.
237.
Modifier la cration des points dans la mthode OnLButtonDown
238.
void CSerialisationView::OnLButtonDown(UINT nFlags, CPoint point)
239.
{
240.
// TODO: Add your message handler code here
and/or call default
241.
CString s;
242.
s.Format("[%d,%d]", point.x, point.y);
243.
CClientDC dc(this);
244.
dc.SetTextColor(m_couleur);
245.
dc.TextOut(point.x, point.y,s);
246.

247.
GetDocument()->Add(new CObjectPoint(point, m_couleur));
248.
249.
CView::OnLButtonDown(nFlags, point);
250.
}
251.
252.
Vrifier qu'il existe alors un problme lors de la relecture des fichiers
sauvegards en Version 1
253.
254.
255.
On utilise pour rgler cela la technique suivante :
256.
modifier la macro pour lui passer un numro de version gal 2
257.
IMPLEMENT_SERIAL(CObjectPoint, CObject,
VERSIONABLE_SCHEMA|2)
258.
Modifier la srialisation du point ainsi :
259.
void CObjectPoint::Serialize(CArchive &ar)
260.
{
261.
if (ar.IsStoring())
262.
{
263.
ar << m_point << m_couleur;//on dcide de toujours restocker en version 2
264.
}
265.
else
266.
{
267.
int nVersion = ar.GetObjectSchema();
268.
269.
switch(nVersion)
270.
{
271.
case 1: // lire en version 1 (sans la couleur)
272.
ar >> m_point ;
273.
break;
274.
case 2: // lire en version courante (2)
275.
ar >> m_point >> m_couleur;
276.
break;
277.
default:
278.
// version inconnue
279.
break;
280.
}
281.
}
282.
}
283.
284.
On pourra tester en ouvrant un fichier sauvegard en version 1 (les points sont
noirs)
285.
Modifier ensuite en rajoutant des points rouges et bleus puis sauvegarder.
286.
Ouvrir ensuite le fichier rsultat.
287.
Notez que la compatibilit ascendante est contrle en particulier car le
constructeur des
288.
CObjectPoint prend une valeur par dfaut 0 pour la couleur (Noire)
correspondant la couleur de la version 1
289.

You might also like