Documente Academic
Documente Profesional
Documente Cultură
Lab CPP
Lab CPP
ndrumtor de laborator
Disciplina:
Programare orientat pe obiecte
Autor: Lect. univ. Horea Oros
1
Laborator C++
Cuprins
INTRODUCERE .......................................................................................................... 4
LABORATOR 15 ...................................................................................................... 71
LABORATOR 16 ...................................................................................................... 84
LABORATOR 17 ...................................................................................................... 94
LABORATOR 18 ...................................................................................................... 97
2
Laborator C++
3
Laborator C++
Introducere
4
Laborator C++
Laborator 1 - limbajul C
Cum limbajul C++ este bazat pe limbajul C, pentru a programa n C++ este absolut necesar
cunoaterea sintaxei limbajului C. Nu este obligatorie ns nvarea limbajului C nainte de
C++ (fapt confirmat chiar i de creatorul limbajului C++, Bjarne Stroustrup i de muli ali
programatori profesioniti) dar avnd n vedere c aceste note de laborator se adreseaz
studenilor din anul III profilul matematic-informatic, studeni ce au studiat anterior
limbajul C, considerm c acetia pot rezolva urmtoarele probleme C cu uurin.
5
Laborator C++
strcpy(s, hello);
free(s);
8) Scriei un program C care tiprete argumentele din linia de comand cu care a fost apelat.
9) Definii o funcie care returneaz suma parametrilor de tip int cu care a fost apelat.
Declarai un pointer la o astfel de funcie i apelai funcia utiliznd pointerul.
10) Explicai urmtoarele declaraii complexe
a) void *(*(*fp1)(int))[10];
b) float (*(*fp2)(int, int, int))(int);
c) typedef double (*(*(*fp3)())[10])(); fp3 a;
d) int (*(*fp4())[10])();
Rezolvare:
1) Calculul factorialului:
#include <stdio.h>
main()
{
int n, i, f;
printf(n=);
scanf(%d, &n);
f=1;
for(i=1; i<=n; i++)
f = f * i;
printf(n! = %d, f);
return 0;
}
randomize();
for(i=0; i<SIZE; i++)
a[i] = random(MAX+1);
6
Laborator C++
7
Laborator C++
8) Linia de comand
#include <stdio.h>
main(int argc, char *argv[])
{
int i;
for(i=1; i<argc; i++) // primul argument este numele
//programului
printf("%s\n", argv[i]);
return 0;
}
9) Pointer la funcie
#include <stdio.h>
int f(int, int);
main()
{
int (*fp)(int, int);
fp = f;
printf("%d", fp(1, 2));
return 0;
}
int f(int a, int b)
{
return a+b;
}
10) Declaraiile complexe se citesc din interior spre exterior. Pentru interpretarea declaraiilor
complexe exist programul cdecl.
a) fp1 este pointer la funcie care are un singur argument de tip int i returneaz pointer
la tablou de 10 pointeri la void
b) fp2 este pointer la funcie (cu trei argumente) care returneaz pointer la funcie cu un
singur argument de tip int i care returneaz o valoare de tip float
c) a este ponter la funcie fr argumente care returneaz pointer la tablou de 10 pointeri
la funcii fr argumente care returneaz o valoare de tip double
d) fp4 este funcie fr argumente ce returneaz pointer la tablou de 10 pointeri la funcii
fr argumente care returneaz o valoare de tip int.
8
Laborator C++
9
Laborator C++
{
cout << dec << setw(5) << 255 << endl;
cout << oct << setw(5) << 255 << endl;
cout << hex << setw(5) << 255 << endl;
cout << setprecision(2) << 1.234 << endl;
return 0;
}
Manipulatorul dec convertete valoarea ce se afieaz n baza 10, oct n baza 8 i hex n baza
16, setw stabilete dimensiunea minim a spaiului pe care vor fi afiate datele alinierea
implicit fiind la dreapta, setprecision permite stabilirea numrului de zecimale cu care va fi
afiat un numr n virgul mobil.
Problem: Scriei un program C++ ce afieaz la consol coninutul unui tablou de caractere
n format hexa. Coninutul tabloului va fi generat aleator, folosind funcia din biblioteca
standard C random(). Datele vor fi afiate la consol sub forma:
76 72 53 8B 69 AB BB 9B 98 8D 6D D 6E B6 28 30 vrS.i.....m.n.(0
5A 97 4A 5C 4A 1E B0 A2 DB 4C 73 BF C5 28 63 24 Z.J\J....Ls..(c$
95 FA 98 2F 6D 60 F1 66 B5 E D5 D9 82 E4 F 70 .../m`.f.......p
A4 23 21 4F 11 54 E5 19 AC CE D2 41 1E 5F B8 1B .#!O.T.....A._..
B5 F7 55 F1 0 F3 98 CD 2E D7 E8 34 CD F 44 7C ..U........4..D|
B 9B 97 17 F3 2D 20 5B EB A0 37 2C E3 55 52 20 .....- [..7,.UR
5E 54 9B 6B ^T.k
Sursa de octei nu e foarte important. Problema o vom relua cnd vom trata lucrul cu fiiere.
Pentru fiiere vom putea crea un viewer sau chiar un editor hexa.
n partea stng apar valorile hexa ale caracterelor din partea dreapt. n partea dreapt am
nlocuit cu punct caracterele ce au codul ASCII n afara intervalului 32..127.
Programul ce rezolv problema de mai sus:
#include <iostream.h>
#include <stdlib.h>
#include <iomanip.h>
#include <ctype.h>
main()
{
const int MAX=100;
unsigned char s[MAX+1];
int i;
// initializarea generatorului de numere aleatoare
randomize();
for(i=0; i<MAX; i++)
s[i]=(unsigned char)random(255);
s[MAX]='\0';
i=0;
int j;
do{
for(j=0; j<16 && i<MAX; j++, i++)
cout << setiosflags(ios::uppercase) << setw(3)
<< hex << (unsigned)s[i];
10
Laborator C++
if(i==MAX)
for(int t=0; t<16-j; t++)
cout << setw(3) << " ";
i-=j;
cout << '\t';
for(j=0; j<16 && i<MAX; j++, i++)
if (isprint(s[i]))
cout << s[i];
else
cout << '.';
cout << endl;
}while(i<MAX);
return 0;
}
Intrarea de la consol se realizeaz prin obiectul cin (console input). cin este un obiect asociat
cu stream-ul standard de intrare (n mod implicit este tastatura dar poate fi redirectat).
#include <iostream.h>
main()
{
char c, tab[10];
int n;
float f;
cin >> c >> tab >> n >> f;
cout << "c=" << c << endl;
cout << "tab=" << tab << endl;
cout << "n=" << n << endl;
cout << "f=" << f << endl;
return 0;
}
Dac introducem de la tastaur irul x abc 123 1.234 programul va afia:
c=x
tab=abc
n=123
f=1.234
Datele trebuie s fie separate prin spaii albe (spaiu, tab sau linie nou). Pentru a citi un ir de
caractere ce conine spaii albe sau ali delimitatori, trebuie folosite metodele get sau getline.
Pentru a citi un singur caracter folosim metoda getc iar pentru a afia un singur caracter putc.
Pentru a inspecta urmtorul caracter din intrare se poate folosi metoda peek (caracterul nu
este scos din intrare), iar pentru a repune n intrare un caracter ce a fost scos se folosete
putback.
Exerciiu: Studiai modul de utilizare al metodelor descrise mai sus.
Intrarea standard se redirecteaz utiliznd sintaxa: nume program executabil > fisier.
Ieirea standard se redirecteaz utiliznd sintaxa: nume programului executabil < fisier.
Pentru a fi siguri c rezultatele vor ajunge pe ecran i nu ntr-un fiier, chiar dac utilizm
redirectarea putem trimite datele la obiectul cerr (console error).
11
Laborator C++
Problem:
1. Scriei un program C++ care elimin comentariile dintr-un fiier surs C++. Se va folosi
redirectarea intrrii pentru a da programului numele fiierului surs ce trebuie procesat i
redirectarea ieirii pentru a da numele fiierului rezultat (cel ce nu conine comentarii).
12
Laborator C++
13
Laborator C++
i.open(argv[1]);
if(i.fail()){
cerr << "Nu pot deschide fisierul " << argv[1] << endl ;
exit(1);
}
o.open(argv[2]);
if(o.fail()){
cerr << "Nu pot deschide fisierul " << argv[2] << endl ;
exit(1);
}
const int MAXLINE=1000;
char buf[MAXLINE];
while (!i.eof()){
i.getline(buf, MAXLINE, '\n');
o << buf << endl;
}
i.close();
o.close();
return 0;
}
2) Copiere de fiiere binare
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>
#include <stdlib.h>
main(int argc, char *argv[])
{
ifstream i;
ofstream o;
if(argc!=3){
cerr << "Utilizare " << argv[0]
<< " <sursa> <destinatie>" << endl;
exit(1);
}
i.open(argv[1], ios::binary);
if(i.fail()){
cerr << "Nu pot deschide fisierul "
<< argv[1] << endl ;
exit(1);
}
o.open(argv[2], ios::binary);
if(o.fail()){
cerr << "Nu pot deschide fisierul "
<< argv[2] << endl ;
exit(1);
14
Laborator C++
}
unsigned char c[1];
while (!i.eof()){
i.read(c, 1); // citesc cate un caracter
if(!i.eof()) // testul este necesar pentru ca
// eof va fi setat doar dupa ce se citeste un
// caracter dincolo de sfarsitul fiserului
// fara acest test dimensiunea fiserului destinatie
// va fi cu un octet mai mare decat a fiserului sursa
o.write(c, 1);
}
i.close();
o.close();
return 0;
}
Intrarea-ieirea se poate face i pe iruri din memorie, ntr-un mod echivalent cu cel al
funciilor din biblioteca Standard C sscanf i sprintf. Pentru a putea folosi aceste faciliti
trebuie s includem n program fiierul header strstream.h i s declarm obiecte de tip
ostrstream pentru ieire, respectiv isrtstream pentru intrare.
#include <iostream.h>
#include <strstream.h>
main()
{
char s[100];
ostrstream o(s, 100);
o << "pi=" << 3.14 << ends;
cout << s;
return 0;
}
Programul de mai sus afieaz pi=3.14. Manipulatorul ends adaug terminatorul de ir
(caracterul NUL).
Dac exist un ir de caractere i vrem s citim din el putem folosi un stream de intrare pe
iruri ca ma jos.
#include <iostream.h>
#include <strstream.h>
#include <string.h>
main()
{
char *s = "3.14 12 abc";
istrstream i(s, strlen(s));
float f;
int n;
char t[100];
15
Laborator C++
16
Laborator C++
17
Laborator C++
*
**
***
****
*****
3) Descoperii modul de creare a unui proiect n mediul pentru dezvoltare de aplicaii pe care
l folosii i creai un proiect pentru problema de mai sus. Se vor crea trei fiiere: un fiier
header ce conine declaraia clasei cu numele stars.h , un fiier ce conine implementarea
clasei (definiia clasei) cu numele stars.cpp i un fiier cu numele driver.cpp ce conine
funcia main.
Rezolvare:
// stars.h
#ifndef STARS_H // aceste directive pentru preprocesor
#define STARS_H // ne garanteaza faptul ca declaratia
//clasei nu va fi inclusa de doua ori
// intr-un fisier sursa C++, ceea ce constituie
// eroare
class Star
{
public:
Star(int);
private:
int _i;
};
#endif
// stars.cpp
#include stars.h
#include <iostream.h>
Star::Star(int i): _i(i)
{
for(int j=0; j<i; j++)
cout << '*';
cout << endl;
}
// driver.cpp
#include <stars.h>
main()
{
for(int i=1; i<=5; i++)
Star s(i);
return 0;
}
18
Laborator C++
Probleme:
1) Definii o clas HorzBar al crei constructor tiprete la consol +-------+. Numrul
de semne minus se d argument constructorului.
2) Definii o clas VertBar al crei constructor tiprete:
|
|
|
Numrul de semne | se d ca argument constructorului.
3) Definii o clas Frame care conine dou obiecte de tip HorzBar i ntre ele unul de tip
VertBar
+-------+
|
|
|
+-------+
4) Definii o clas Ladder ce conine dou obiecte de tip Frame i ntre ele un obiect de tip
VertBar.
+-------+
|
|
|
+-------+
|
|
|
+-------+
|
|
|
+-------+
Rezolvare:
#include <iostream.h>
class HorzBar
{
public:
HorzBar(int h): _h(h)
{
cout << '+';
for(int i=0; i<h; i++)
cout << '-';
cout << '+' << endl;
}
private:
int _h;
};
19
Laborator C++
class VertBar
{
public:
VertBar(int v): _v(v)
{
for(int i=0; i<v; i++)
cout << '|' << endl;
}
private:
int _v;
};
class Frame
{
public:
Frame(int h, int v): h1(h), vert(v), h2(h)
{
//Acesta este un exemplu care ilustreaza foarte bine
//rolul listei de initializatori a constructorului.
//Obiectele declarate intr-o clasa pot fi initializate doar
//prin intermediul acestei liste.
//Ordinea in care apar variabilele in lista nu este importanta
//ele vor fi initializate in ordinea in care sunt declarate
//in clasa. Lista de initializatori a constructorului este de
//asemenea importanta in cazul mostenirii, prin itermediul ei
//se initializeaza clasele de baza.
}
private:
HorzBar h1;
VertBar vert;
HorzBar h2;
};
class Ladder
{
public:
Ladder(int h, int v): f1(h, v), vert(v), f2(h, v)
{
}
private:
Frame f1;
VertBar vert;
Frame f2;
};
main()
{
Ladder l(3, 4);
20
Laborator C++
return 0;
}
Problem: Creai un proiect pentru programul de mai sus. Pentru fiecare clas creai un fiier
header ce va conine declaraia clasei i un fiier cu implementarea clasei (definiia
metodelor). Funcia main va fi pus ntr-un fiier separat cu numele driver.cpp.
21
Laborator C++
void tiparire();
// Operatori aritmetici
Complex adun(Complex &);
Complex scad(Complex &);
Complex inmult(Complex &);
double modul();
// Operatori relationali
bool esteEgalCu(Complex &);
bool esteDiferitDe(Complex &);
private:
double _re, _im;
};
#endif
//complex.cpp
#include "complex.h"
#include <iostream.h>
#include <math.h> // pentru sqrt
// C-tor implicit
22
Laborator C++
double Complex::getIm()
{
return _im;
}
23
Laborator C++
24
Laborator C++
Dup cum se vede din programul test.cpp de mai sus utilizarea clasei Complex este foarte
simpl, dac cineva (creatorul de clase) a depus efortul de a o implementa. Tot ceea ce trebuie
s fac programatorul client (cel care utilizeaz clasa) este s includ n fiierul su surs
fiierul header al clasei i s acceseze funciile de interfa. Implementarea clasei de obicei va
fi ntr-o bibliotec de clase de a crei existen trebuie informat compilatorul.
Utiliznd programare orientat pe obiecte putem deveni programatori mult mai eficieni (prin
eficien n programare nelegem c un program care cu alte paradigme ale programrii este
finalizat de o echip de zece programatori n dou luni de zile, programnd pe obiecte, doi
programatori l termin n trei sptmni). Eficiena se realizeaz prin reutilizarea codului.
Programarea orientat pe obiecte ne permite s pictm cu o pensul mai mare, putem
exprima ntr-un mod mai compact i mai clar mult mai multe operaii. Limbajul n care se
exprim soluia problemei este mult mai apropiat de limbajul n care este formulat problema
dect de limbajul mainii pe care se rezolv problema.
Probleme:
1. Adugai la clasa Complex, definit mai sus, operaiile de mprire a dou numere
complexe i ridicare la putere a unui numr complex. Adugai de asemenea i metode
pentru transformarea unui numr complex din forma algebric n forma trigonometric.
2. Studiai modul de creare a unei biblioteci n mediul pentru dezvoltare de aplicaii C++ pe
care l utilizai. Cu clasa definit mai sus creai o bibliotec pe care s o utilizai ntr-un
program.
25
Laborator C++
void tipar();
// Metode accesor
int getNuma(); // Numaratorul
int getNumi(); // Numitorul
private:
int numarator, numitor;
};
#endif
// rational.cpp
#include "rational.h"
#include <iostream.h>
Rational::Rational()
{
numarator = numitor = 0;
}
Rational::Rational(int numarator, int numitor)
{
// Pentru a face distictie intre argumentele
// functiei constructor si numele datelor membre
// folosim operatorul de rezolutie a domeniului
// de valabilitate ::
Rational::numarator = numarator;
Rational::numitor = numitor;
}
26
Laborator C++
// Metode operator
Rational Rational::Adun(Rational &r2)
{
Rational temp;
temp.numarator = getNuma()*r2.getNumi() + getNumi()*r2.getNuma();
temp.numitor = getNumi() * r2.getNumi();
return temp;
}
void Rational::tipar()
{
cout << getNuma() << '/' << getNumi();
}
// Metode accesor
int Rational::getNuma()
{
return numarator;
}
int Rational::getNumi()
{
return numitor;
}
void Rational::invers()
{
int temp;
temp = numarator;
numarator = numitor;
numitor = temp;
27
Laborator C++
if(r1.egalCu(r2))
cout << "Egale" << endl;
else
cout << "Nu sunt egale" << endl;
return 0;
}
Probleme:
1. Adugai programului de mai sus operaia de aducere la forma ireductibli a unui numr
raional.
2. Creai metode pentru compararea a dou numere raionale. (inei cont i de numerele
negative).
3. Modificai metodele de adunare i scdere a dou numere raionale, determinnd cel mai
mic multiplu comun al numitorilor i amplificnd fiecare fracie cu valoarea
corespunztoare (Procednd astfel putem evita n unele cazuri depirile).
4. Adugai cod pentru tratarea erorilor: numitori nuli, depiri.
28
Laborator C++
Creai un tip de date definit de utilizator care s simuleze o stiv de numere ntregi. ntr-o
stiv datele se introduc i se extrag la un singur capt dup principiul ultimul intrat-primul
ieit (Last In First Out - LIFO). Implementarea se va face utiliznd un tablou.
// stack.h
#if !defined(STACK_H)
#define STACK_H
#define SIZE 100 // Stiva este limitata la 100 de elemente
enum bool {false, true};
// Numele clasei este decorat cu int pentru
// a scoate in evidenta faptul ca aceasta clasa
// reprezinta o stiva de intregi. Pentru a crea
// o stiva de alt tip trebuie sa copiem tot
// codul si sa facem modificarile de rigoare
// decorand noul nume de tip cu altceva.
// Stiva este un concept general, care nu depinde
// de tipul datelor ce le contine.
// C++ ofera facilitati pentru crearea de tipuri
// parametrizate prin asa numitele "sabloane"
// (template) ce vor fi studiate mai tarziu.
// Sabloanele permit programarea generica.
class Stack_int
{
public:
// Constructor implicit
Stack_int();
// Metode ce constituie interfata stivei
// Introducerea unui element in stiva
void push(int);
// Extragerea unui element din stiva
void pop();
// Obtinerea elementului din varfului
// fara a fi extras
int top();
// Pentru obtinerea numarului de elemente din stiva
unsigned size();
bool empty();
private:
int tab[SIZE];
unsigned _top; // indica prima pozitie libera din stiva
};
#endif
29
Laborator C++
// stack.cpp
#include "stack.h"
#include <iostream.h>
Stack_int::Stack_int()
{
_top = 0;
}
void Stack_int::push(int x)
{
if(_top < SIZE - 1)
tab[_top++] = x;
else
cerr << "Stiva plina";
}
void Stack_int::pop()
{
if(!empty())
_top--;
}
int Stack_int::top()
{
if(!empty())
return tab[_top-1];
else
cerr << "Stiva goala" << endl;
// C++ ofera facilitati pentru tratarea erorilor.
// Acestea vor fi studiate
// ulterior astfel incat situatii cum sunt
// cele din aceasta functie si din functia
// push, de mai sus, se vor trata mai elegant.
}
unsigned Stack_int::size()
{
return _top;
}
bool Stack_int::empty()
{
if (_top == 0)
return true;
else
return false;
30
Laborator C++
// stack_drv.cpp
#include "stack.h"
#include <iostream.h>
main()
{
Stack_int s;
s.push(1);
s.push(2);
s.push(3);
cout << "Elementul din varful stivei: "
<< s.top() << endl;
s.pop();
cout << "Numarul de elemente din stiva: "
<< s.size() << endl;
s.pop();
if (s.empty())
cout << "Stiva goala" << endl;
else
cout << "Stiva nu este goala. Elementul "
"din varful stivei: " << s.top() << endl;
return 0;
}
Probleme:
1. Scriei un program C++ n care s folosii o stiv de numere raionale. (Utilizai clasa
Rational)
2. Modificai implementarea clasei Stack_int astfel nct datele s fie pstrate ntr-o
structur dinamic ce se poate redimensiona dup necesiti i nu ntr-un tablou alocat n
mod static. Mesajul de eroare Stiva plina va disprea i va fi nlocuit cu mesajul
Memorie insuficienta. Cnd stiva se umple se face o nou alocare de memorie pentru
mai multe elemente, se copiaz datele n noua zon de memorie i se elibereaz vechea
zon de memorie.
31
Laborator C++
32
Laborator C++
// str_impl.cpp
#include "str.h"
#include <string.h>
#include <iostream.h>
#include <stdlib.h>
// C-tor implicit = c-tor care poate fi apelat fara argumente.
// Asadar un constructor implicit poate avea argumente dar toate
// trebuie sa aiba valori implicite.
Str::Str()
{
p = new char[1];
p[0] ='\0';
_size = 0;
}
// C-tor de copiere
Str::Str(const Str &s2)
{
p = new char[s2.size() + 1];
strcpy(p, s2.p);
_size = s2._size;
}
Str::Str(char *s)
{
p = new char[strlen(s) + 1];
strcpy(p, s);
_size = strlen(s);
}
Str::Str(const Str &s2, int poz, int lng)
{
33
Laborator C++
// Exercitiu:
// Copiaza lng caractere incepand de la pozitia poz.
// Verificati daca se pot copia caracterele.
}
Str::Str(const Str &s2, int poz)
{
if(poz+1<=s2.size())
{
p = new char[s2.size() - poz +1];
strncpy(p, s2.p+poz, s2.size() - poz + 1);
_size = s2.size() - poz;
}
else
cerr << "Nu pot crea sirul cu parametrul dat";
}
Str::Str(char *s2, int poz, int lng)
{
// Exercitiu:
// Copiaza lng caractere incepand de la pozitia poz.
// Verificati daca se pot copia caracterele.
}
Str::Str(char *s2, int poz)
{
if(poz+1<=strlen(s2))
{
p = new char[strlen(s2) - poz +1];
strncpy(p, s2+poz, strlen(s2) - poz + 1);
}
else
// Daca executia programului ajunge in acest loc
// obiectul va fi nedefinit. Trebuie gasita a alta
// modalitate de tratare a acestui tip de exceptie,
// nu doar afisarea unui mesaj de avertizare.
// De ex. crearea unui obiect gol, la fel ca si
// constructorul implicit.
cerr << "Nu pot crea sirul cu parametrul dat";
}
Str::Str(char ch, int n)
{
p = new char[n+1];
for(int i=0; i<n; i++)
p[i] = ch;
p[n] = '\0';
}
Str::~Str()
34
Laborator C++
{
delete []p;
p = 0;
}
void Str::operator=(const Str &s2)
{
// Pentru a preveni auto-asignarea folosim
// testul de mai jos.
// this este pointer constant la obiectul pentru
// care a fost apelata functia
if(this!=&s2)
{
delete []p;
p = new char[s2.size() + 1];
strcpy(p, s2.p);
_size = s2.size();
}
}
Str operator+(const Str& s1, const Str &s2)
{
char *s = new char[s1.size() + s2.size() + 1];
strcpy(s, s1.p);
strcat(s, s2.p);
return Str(s);
}
bool operator<(const Str& s1, const Str &s2)
{
if(strcmp(s1.p, s2.p)<0)
return true;
else
return false;
}
bool operator<=(const Str &s1, const Str &s2)
{
// Exercitiu
}
bool operator>(const Str &s1, const Str &s2)
{
// Exercitiu
}
bool operator>=(const Str &s1, const Str &s2)
{
// Exercitiu
}
bool operator==(const Str &s1, const Str &s2)
{
35
Laborator C++
// Exercitiu
}
bool operator!=(const Str &s1, const Str &s2)
{
// Exercitiu
}
char &Str::operator[](long i)
{
if(i<_size)
return p[i];
else
{
cerr << "Incercare de accesare a unui caracter dincolo"
" de sfarsitul sirului";
exit(1);
};
}
long Str::size() const
{
return _size;
}
//driver.cpp
#include "str.h"
#include <iostream.h>
#include <conio.h>
main()
{
clrscr();
Str s1("abcdefg"); // Se utilizeaza c-torul Str(char*);
Str s2(s1); // Se utilizeaza constructorul de copiere
Str s3(s1, 2); // Se utilizeaza c-torul Str(Str&,int);
Str s4 = s3; // Se utilizeaza constructorul de copiere.
// Obiectul s4 este creat ceea ce determina
// apelul unui constructor. Analog cu Str s4(s3);
Str s5; // Se utilizeaza constructorul implicit
s5 = s1; // Se utilizeaza operatorul de atribuire supraincarcat
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
36
Laborator C++
return 0;
}
Exerciii:
1. Completai toate metodele crora le lipsete implementarea i testai aceste metode.
2. Adugai o metod, cu numele swap care s permit interschimbarea coninutului a dou
obiecte de tip Str, folosind sintaxa: s1.swap(s2).
3. Adugai o metod cu numele empty care s returneze true dac un ir nu conine nici un
caracter i false n caz contrar.
4. Adugai una sau mai multe metode erase suprancrcate, care s permit tergerea unei
poriuni dintr-un ir.
5. Adugai una sau mai multe metode insert suprancrcate care s permit inserarea ntr-
un obiect de tip Str a unui ir sau subir de caractere.
6. Adugai una sau mai multe metode replace care s permit nlocuirea unei poriuni dintr-
un ir cu un alt ir de caractere sau cu un subir al unui ir de caractere.
7. Adugai una sau mai multe metode find care s permit cutarea ntr-un ir a unui subir.
8. Adugai metodele upper i lower care transform toate literele dintr-un ir n litere mari
respectiv mici.
9. Adugai o metod reverse care inverseaz caracterele dintr-un ir (caracterul de pe prima
poziie se interschimb cu cel de pe ultima, al doilea cu cel de pe penultima .a.m.d.)
37
Laborator C++
Laborator 9 - ora
Creai un tip de date definit de utilizator (Time) pentru reprezentarea timpului sub forma
(ora:minutul:secunda.sutimea). Pentru acest tip de date implemetai operaia de adunare a doi
timpi. Se vor utiliza dou modaliti de iniializare a unui obiect de tip Time:
Time t1(2, 34, 05, 89);
Time t2(2:34:05.89);
Rezolvare:
//main.cpp
#include <mtime.h>
int main()
{
MTime t1(2, 30, 59,10);
MTime t2("2.30:59.11");
MTime t3;
t3 = t1 + t2;
cout << endl << t1 << '+' << endl << t2 << '='
<< endl << t3 << endl;
if(t1==t2)
cout << "t1 == t2" << endl;
else
cout << "t1!=t2" << endl;
return 0;
}
//mtime.h
#ifndef MTIME_H
#define MTIME_H
#include <iostream.h>
enum bool {false, true};
class MTime
{
public:
MTime();
MTime(unsigned, unsigned, unsigned, unsigned);
MTime(char *);
bool operator==(const MTime &);
bool operator!=(const MTime &);
bool operator<(const MTime &);
bool operator>(const MTime &);
bool operator<=(const MTime &);
bool operator>=(const MTime &);
MTime operator+(const MTime &);
friend ostream & operator<<(ostream &, const MTime &);
private:
38
Laborator C++
unsigned ora;
unsigned minut;
unsigned secunda;
unsigned sutime;
};
#endif
//mtime.cpp
#include "mtime.h"
#include <iostream.h>
#include <strstream.h>
#include <iomanip.h>
MTime::MTime(): ora( 0 ), minut( 0 ), secunda( 0 ), sutime( 0 )
{
}
MTime::MTime(char *str )
{
istrstream t(str);
t >> ora;
t.ignore();
if (t.peek()=='0')
t.ignore();
t >> minut;
t.ignore();
if (t.peek()=='0')
t.ignore();
t >> secunda;
t.ignore();
if (t.peek()=='0')
t.ignore();
t >> sutime;
}
39
Laborator C++
40
Laborator C++
else
if(secunda < t.secunda)
return true;
else
if(secunda > t.secunda)
return false;
else
if(sutime < t.sutime)
return true;
else
return false;
}
bool MTime::operator>(const MTime &t )
{
if( (*this!=t ) && !(*this < t) )
return true;
else
return false;
}
bool MTime::operator<=(const MTime &t )
{
if( !(*this > t) )
return true;
else
return false;
}
bool MTime::operator>=(const MTime &t )
{
if( !(*this < t) )
return true;
else
return false;
}
Probleme:
1. Suprancrcai operatorul pentru clasa MTime pentru a calcula diferena dintre doi
timpi. Operatorul va returna prin valoare un obiect de tip MTime.
2. Implementai o metod care s determine timpul scurs de la o anumit ora pn la ora
curent. Ora curent este cea dat de ceasul intern al calculatorului.
41
Laborator C++
Laborator 10 - data
Creai un tip de date definit de utilizator (Date)pentru reprezentarea datei sub forma
(zi.luna.an). Pentru acest tip de date implementai o operaie pentru determinarea numrului
de zile dintre dou date. Se vor utiliza dou modaliti de iniializare a unui obiect de tip
Date:
Date d1(3, 4, 1940);
Date d2(17.11.1997);
//main.cpp
#include "date.h"
int main()
{
Date d1(12, 12, 2030);
Date d2("13.12.2040");
cout << endl << d1 << endl <<d2 << endl;
cout << "d1-d2 = " << d1-d2 << endl;
cout << "d1-d2 = " << d2-d1 << endl;
if( (d1-d2) == (d2-d1) )
cout << "OK!";
return 0;
}
//date.h
#if !defined(DATE_H)
#define DATE_H
#include <iostream.h>
enum bool {false, true};
class Date
{
public:
Date();
Date(unsigned, unsigned, unsigned);
Date(char *);
42
Laborator C++
};
#endif
//date.cpp
#include "date.h"
#include <strstream.h>
#include <iomanip.h>
Date::Date(): zi(0), luna(0), an(0)
{
}
Date::Date(char *s)
{
istrstream is(s);
is >> zi;
is.ignore();
if(is.peek() =='0')
is.ignore();
is >> luna;
is.ignore();
is >> an;
}
43
Laborator C++
d1.zi--;
else
switch(d1.luna){
case 1:
d1.zi = 31;
d1.luna = 12;
d1.an--;
break;
case 2: case 4: case 6: case 8: case 9: case 11:
d1.zi = 31;
d1.luna--;
break;
case 5: case 7: case 10: case 12:
d1.zi = 30;
d1.luna--;
break;
case 3:
d1.luna--;
if(d1.an%400 == 0 || (d1.an%100!=0 && d1.an%4==0))
d1.zi = 29;
else
d1.zi = 28;
}
}
return nr;
}
44
Laborator C++
return true;
else
if(an > d.an)
return false;
else
if(luna < d.luna)
return true;
else
if(luna > d.luna)
return false;
else
if(zi< d.zi)
return true;
else
return false;
}
45
Laborator C++
Probleme:
1. Pentru clasa Date de mai sus implementai o metod care s determine vrsta unei
persoane n an, luni i zile. Data curent va fi cea dat de ceasul intern al calculatorului.
2. Pentru clasa Date de mai sus implementai o metod care s determine n ce zi a
sptmnii cade o anumit dat.
46
Laborator C++
Laborator 11 - matrice
Creai un tip de date definit de utilizator pentru reprezentarea matricilor de numere reale. Vor
fi implementate operaiile de adunare, scdere i nmulire a dou matrici. Se va testa dac
operaiile se pot executa. Operaia de accesare a unui element al matriciii va fi realizat
suprancrcnd operatorul apel de funcie cu doi parametri (folosind sintaxa m(1, 2) vom
accesa elementul de pe linia 2 coloana 3). Acest operator trebuie s returneze referin la
double pentru a putea fi folosit i ca l-valoare i ca r-valoare. Dac s-ar returna doar double
atunci expresia m(1, 2) poate fi folosit doar ca r-valoare (n partea dreapt a semnului egal).
// main.cpp
#include "matrice.h"
#include <iostream.h>
#include <stdlib.h>
#define MAX 4
int main()
{
randomize();
Matrice m1(2, 2), m2(2, 2);
unsigned i, j;
// Elementele celor doua matricile generam aleator
for(i=0; i<2; i++)
for(j=0; j<2; j++)
m1(i, j) = random(MAX);
cout << "m1" << endl << m1;
// In expresiile de mai jos obiectul m exista deja (a fost creat si initializat mai sus) prin
// urmare va fi apelata functia operator= supraincarcata pentru clasa Matrice
m = m1 - m2;
cout << "m1-m2" << endl << m;
m = m1 * m2;
cout << "m1*m2" << endl << m;
return 0;
}
47
Laborator C++
// matrice.h
#ifndef MATRICE_H
#define MATRICE_H
#include <iostream.h>
class Matrice
{
public:
Matrice();
Matrice(unsigned);
Matrice(unsigned, unsigned);
Matrice(const Matrice &);
~Matrice();
// matrice.cpp
#include "matrice.h"
#include <iostream.h>
// Constructor impicit
Matrice::Matrice()
{
l = c = 0;
48
Laborator C++
p = 0;
}
Matrice::Matrice(unsigned n)
{
l = c = n;
p = new double[ n * n ];
}
Matrice::Matrice(unsigned l, unsigned c)
{
Matrice::l = l;
Matrice::c = c;
p = new double[ l * c ];
}
// Constructor de copiere
Matrice::Matrice(const Matrice &m)
{
// Aloc memorie pentru noul obiect
p = new double[ m.l * m.c ];
// initializez numarul de linii si coloane
l = m.l; c = m.c;
// si copiez valorile matricii in noua matrice.
unsigned i, j;
for(i=0; i<l; i++)
for(j=0; j<c; j++)
p[ i*c + j ] = m.p[ i*c + j ];
}
// Destructor
Matrice::~Matrice()
{
delete []p;
}
49
Laborator C++
{
temp.p = new double[l*c];
temp.l = l;
temp.c = c;
unsigned i, j;
for(i=0; i<l; i++)
for(j=0; j<c; j++)
temp.p[ i*c + j ] = p[ i*c + j ] + m.p[ i*c + j ];
}
return temp;
}
unsigned i, j;
for(i=0; i<l; i++)
for(j=0; j<c; j++)
temp.p[ i*c + j ] = p[ i*c + j ] - m.p[ i*c + j ];
}
return temp;
}
50
Laborator C++
// Operatorul de atribuire modifica operandul din partea stanga a semnului egal asa ca
// aici putem returna o referinta la obiectul care a fost modificat.
//Aceasta functie poate sa nu returneze nimic (void) dar in acest caz expresia ce contine
// operatorul de atribuire nu va avea nici o valoare. Nu se va putea folosi nici o
// expresie care foloseste rezultatul evaluarii atribuirii.
Matrice& Matrice::operator=(const Matrice &m)
{
if( this == &m )
return *this;
delete []p;
p = new double[ m.l * m.c ];
l = m.l;
c = m.c;
unsigned i, j;
for(i=0; i<l; i++)
for(j=0; j<c; j++)
p[ i*c + j ] = m.p[ i*c + j ];
return *this;
}
Probleme:
1) Adugai clasei Matrice operaia de transpunere a unei matrici.
51
Laborator C++
52
Laborator C++
// pers.h
#ifndef PERS
#define PERS
#include <iostream.h>
class Persoana
{
public:
Persoana(char *, char *, unsigned short);
Persoana();
Persoana(const Persoana&);
Persoana& operator=(const Persoana&);
friend ostream& operator<<(ostream&, const Persoana&);
~Persoana();
private:
char * nume;
char * prenume;
unsigned short varsta;
};
#endif
// pers.cpp
#include "pers.h"
#include <string.h>
#include <iomanip.h>
Persoana::Persoana(char *nume, char *prenume, unsigned short varsta)
{
//daca numele unei date membre a clasei coincide cu numele //unui argument al unei
functii membre atunci pentru a elimina //ambiguitatea se precede numele datei membre de
numele clasei //si operatorul de rezolutie a domeniului de valabilitate //(scope resolution
operator)
Persoana::nume = new char[strlen(nume)+1];
strcpy(Persoana::nume, nume);
53
Laborator C++
strcpy(Persoana::prenume, prenume);
Persoana::varsta = varsta;
}
//Constructor implicit
Persoana::Persoana()
{
nume = prenume = 0;
varsta = 0;
}
//C-tor de copiere. Este folosit cand transmitem un obiect //prin valoare unei functii, cand
returnam un obiect prin //valoare dintr-o functie sau cand initializam un obiect cu un
//altul de acelasi tip
Persoana::Persoana(const Persoana& p)
{
nume = new char[strlen(p.nume) + 1];
strcpy(nume, p.nume);
prenume = new char[strlen(p.prenume) + 1];
strcpy(prenume, p.prenume);
varsta = p.varsta;
}
//Obs. 1 Operatorul de atribuire trebuie scris in asa fel //incat sa previna de auto-asignarea.
//Obs. 2 Daca ar returna void nu am putea folosi o expresie de //genul a=b=c; expresia b=c;
nu ar avea nici o valoare.
Persoana& Persoana::operator=(const Persoana& pers)
{
if(this == &pers)
return *this;
else
54
Laborator C++
{
delete []nume;
delete []prenume;
nume = new char[strlen(pers.nume) + 1];
strcpy(nume, pers.nume);
prenume = new char[strlen(pers.prenume) + 1];
strcpy(prenume, pers.prenume);
varsta = pers.varsta;
}
}
//lst.h
#ifndef LIST_PERS
#define LIST_PERS
#include "pers.h"
//Decoram numele clasei cu DePersoana pentru a scoate in //evidenta foarte clar ce fel
de lista am creat. Dar dupa cum //se vede din modul in care este implementate (mai jos
//lst.cpp), aceasta clasa poate fi modificata foarte usor //pentru a crea liste de orice alt tip.
Programarea generica //(cuv. cheie template) ne va permite sa creem o singura clasa
//parametrizata.
class ListaDePersoane
{
public:
ListaDePersoane();
~ListaDePersoane();
void Add(const Persoana&);
friend ostream& operator<<(ostream&, const ListaDePersoane&);
unsigned Numar() const;
unsigned MaxNumar() const;
private:
unsigned numar;
unsigned maxnumar;
Persoana *p;
};
#endif
// lst.cpp
#include "lst.h"
#include <math.h>
#include <iomanip.h>
#define INCREMENT 3 // numarul cu care creste dimensiunea //listei la o re-alocare
ListaDePersoane::ListaDePersoane()
{
maxnumar = INCREMENT;
numar = 0;
p = new Persoana[maxnumar]; // initial lista poate contine //INCREMENT elemente
55
Laborator C++
ListaDePersoane::~ListaDePersoane()
{
delete []p; // operatorul delete [] va apela destructorul //pentru fiecare obiect de tip
Persoana din lista
numar = maxnumar = 0;
}
56
Laborator C++
{
return maxnumar;
}
//main.cpp
#include "lst.h"
#include "pers.h"
#include <iostream.h>
int main()
{
ListaDePersoane lst;
Persoana p("Georgescu", "Ion", 25);
lst.Add(p);
lst.Add(Persoana("Petrescu", "Gheorghe", 29));
lst.Add(Persoana("Ionescu", "Marin", 26));
lst.Add(Persoana("Popescu", "Petre", 28));
cout << lst;
cout << Numarul de persoane din lista: << lst.Numar();
return 0;
}
Probleme:
1. Adugai clasei ListaDePersoane o metod pentru tergerea ntregii liste.
2. Adugai clasei ListaDePersoane facilitatea de cutare n list a unei persoane creia i
tim numele.
3. Adugai clasei ListaDePersoane o metod de sortare a listei n ordine alfabetic. Aceast
sortare va fi ineficient pentru c vor trebui inversate obiecte de tip Persoana.
4. Pentru ca sortarea s devin eficienta trebuie modificat implementarea clasei
ListaDePersoane ntr-o list nlnuit. Facei aceast modificare.
5. Dac am modificat implementarea, listei ntr-o list nlnuit atunci putem elimina
obiecte din list foarte eficient (fr s facem o re-alocare). Adugai o metod pentru
eliminarea unui obiect din list. Metoda va primi ca argument numele persoanei ce va fi
eliminat.
6. Adugai clasei ListaDePersoane un constructor de copiere.
57
Laborator C++
2 3 4
5 6 7 8 9 10
Pentru a parcurge n adncime un arbore se parcurge prima dat rdcina dup care se parcurg
toi fii, acesta fiind un proces recursiv.
Parcurgerea n adncime a arborelui de mai sus: 1, 2, 5, 6, 3, 7, 4, 8, 9, 10.
Parcurgerea n lime a unui arbore nseamn de fapt parcurgere pe nivele. Pentru aceasta vom
folosi o coad. O coad este o structur liniar de date n care intrrile se fac la un capt iar
ieirile la cellalt capt. Algoritmul pentru parcurgerea n lime a unui arbore poate fi dedus
din listingul de mai jos.
Parcurgerea n lime a arborelui de mai sus: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.
Programul care rezolv problema de mai sus:
// ar.cpp
#include <iostream.h>
#include <stdlib.h>
class nod
{
public:
char inf; // Informatia poate fi orice alta structura de
//date
int dim;
nod *tab[100]; // e indicat a se folosi containerul
//vector din biblioteca standard C++
};
nod * crearb(); // Functia pentru crearea arborelui
void padinc(nod *); // Functia pentru parcurgerea in adincime
void plat(nod *); // Functia pentru parcurgerea in latime
58
Laborator C++
nod * queue::front()
{
if (end>0)
return t[end-1];
else
{
cerr << "queue empty" << endl;
exit(1);
}
}
int queue::empty()
{
if (end == 0)
59
Laborator C++
return 1;
else
return 0;
}
int main()
{
//Creez arborele
nod * root;
root = crearb();
cout << "Parcurgere in adincime:" << endl;
padinc(root);
cout << endl;
cout << "Parcurgere in latime:" << endl;
plat(root);
return 0;
}
nod * crearb()
{
char ch;
int n,i;
nod *p;
cout << "Inf="; cin >> ch;
p = new nod;
p->inf = ch;
cout << "Cati fii are?"; cin >> n;
p->dim = n;
for(i=0; i < n; i++)
p->tab[i] = crearb();
return p;
}
60
Laborator C++
Probleme:
1. Dac, n mediul pentru dezvoltarea de aplicaii pe care l folosii, avei la dispoziie
biblioteca standard C++, modificai programul de mai sus astfel nct s folosii clasa
queue (pentru coad) i clasa vector (pentru fii unui nod) din aceast bibliotec.
61
Laborator C++
// main.cpp
#include "bignum.h"
#include <fstream.h>
int main()
{
// Programul va scrie toate datele in fisierul
// fib.dat
ofstream file("fib.dat");
62
Laborator C++
//node.h
#if !defined(NODE_H)
#define NODE_H
#include <stdlib.h>
struct Node
{
Node(int c): ch(c)
{
next = previous = NULL;
}
int getCh()
{
return ch;
}
int ch;
Node *next, *previous;
};
#endif
//list.h
#if !defined(LIST_H)
#define LIST_H
#include "node.h"
class List
{
public:
List();
List(char *);
~List();
void pushBack(Node *);
63
Laborator C++
// list.cpp
#include "list.h"
#include "node.h"
#include <string.h>
List::List()
{
_size = 0;
front = back = point = NULL;
}
List::List(char *s)
{
_size = strlen(s);
front = back = point = NULL;
if(_size>0)
{
for(int i=0; i<_size; i++)
{
Node *n = new Node(s[i]-'0');
pushBack(n);
}
}
64
Laborator C++
List::~List()
{
Node *p;
while(front!=NULL)
{
p = front->next;
delete front;
front = p;
}
}
65
Laborator C++
void List::moveFront()
{
point = front;
}
void List::moveBack()
{
point = back;
}
Node* List::getBack()
{
return back;
}
Node* List::getFront()
{
return front;
}
Node* List::getPrevious()
{
if(point==NULL)
return NULL;
if(point->previous != NULL)
point = point->previous;
else
point = NULL;
return point;
}
Node* List::getNext()
{
if(point==NULL)
return NULL;
if(point->next != NULL)
point = point->next;
else
point = NULL;
return point;
66
Laborator C++
void List::clear()
{
Node *p;
while(front!=NULL)
{
p = front->next;
delete front;
front = p;
}
front = back = point = NULL;
}
//bignum.h
#if !defined(NUMAR_MARE)
#define NUMAR_MARE
#include "list.h"
#include <iostream.h>
class NumarMare: public List
{
public:
NumarMare();
NumarMare(char *);
~NumarMare();
void operator+=(NumarMare &);
friend ostream& operator<<(ostream &, NumarMare &);
};
#endif
//bignum.cpp
#include "bignum.h"
NumarMare::NumarMare(): List()
{
}
67
Laborator C++
68
Laborator C++
Probleme:
1. Extindei programul de mai sus pentru a putea nmuli un numr mare cu o cifr. Vei
introduce n clasa NumarMare o metod cu prototipul void operator*=(char);
unde caracterul va trebui s reprezinte o cifr.
2. Calculai 1000! Pentru aceasta va trebui introdus o metod pentru nmulirea unui numr
mare cu un ntreg. Prototipul acestei metode va fi void operator*=(long);
Pentru a generaliza problema de mai sus, creai o metod pentru nmulirea a dou numere
mari.
69
Laborator C++
Semestrul II
Programare Win32 folosind biblioteca MFC
70
Laborator C++
Laborator 15
Obiective:
Familiarizare cu AppWizard explicarea tuturor celor 6 opiuni puse la dispoziie de acest Wizard
Prezentarea claselor create de AppWizard pt. o aplicaie de tip SDI.
Funcia OnDraw().
Desenare: linii
Clasa CRect
Funcia GetClientRect()
Pentru a crea un nou proiect trebuie s selectai comanda New a meniului File -astfel se va afia caseta
de dialog New (vezi imaginea de mai jos)- dup care selectai opiunea MFC AppWizard (exe) (care reprezint
tipul proiectului pe care dorii s-l creai), introducei un nume pentru acest nou proiect sub eticheta Project
name:, selectai (doar dac dorii) o alt adres pentru directorul n care s fie creat acest proiect, dup care
apsai pe butonul OK.
71
Laborator C++
reveni la un pas anterior prin apsarea unuia dintre butoanele Next > sau Back <. Vom explica pe rnd rolul
acestor ase casete de dialog.
Caseta de dialog MFC AppWizard Step 1 (vezi imaginea de mai jos) v ofer posibilitatea alegerii
tipului interfeei aplicaiei i a limbii n care s fie scris cod surs. Noi vom alege opiunea Single document n
majoritatea programelor care urmeaz. Mai jos va trebui s decidei dac dorii sau nu suport pentru arhitectura
Document/Reprezentare al claselor MFC. Dac nu dorii acest lucru nu vei putea folosi clasele MFC pentru a
deschide un fiier de pe disc. De asemenea nu vei putea nici s selectai anumite opiuni care vor urma n paii
urmtori. Pentru a trece la pasul urmtor (la afiarea urmtoarei casete de dialog) vom apsa pe butonul Next >.
Caseta de dialog MFC AppWizard Step 2 (vezi imaginea de mai jos) ofer anumite opiuni
referitoare la diferite tipuri de suport pentru bazele de date. Acestea sunt: None, Header file only, Database
view without file support i Database view with file support. n cazul opiunii suportului bazei de date apsai
pe butonul Data Source i alegei o baz de date extern de tipul ODBC, DAO, OLE DB mpreun cu sursa
de date i opiunilor specifice existente fiecrui caz n parte. Pentru a trece la pasul urmtor apsai pe butonul
Next >.
72
Laborator C++
Caseta de dialog MFC AppWizard Step 3 (vezi imaginea de mai jos) ofer opiuni ce privesc
adugarea unor faciliti privind automatizarea OLE (Object Linking and Embedding). n funcie de destinaia
aplicaiei pe care o vei crea avei de ales ntre None, Container, Mini-server, Full-server i Both container
and server.
Pentru a nelege puin fiecare opiune vom porni de la un exemplu. Foile de calcul din Excel pot fi
inserate i editate n Word. n acest exemplu Word va reprezenta aplicaia container OLE iar Excel aplicaia
server OLE. Desigur c unele aplicaii pot fi n acelai i containere OLE i server OLE (chiar n exemplul
nostru, rulnd Excel putei insera documente Word i invers).
Un server complet poate s ruleze att ca aplicaie de sine stttoare ct i ca obiect inserat pe cnd
mini-serverele pot fi lansate doar din cadrul unui program container.
Pentru a trece la pasul apsai pe butonul Next >.
73
Laborator C++
Caseta de dialog MFC AppWizard Step 4 (vezi imaginea de mai jos) ofer posibilitatea alegerii
ctorva opiuni de baz referitoare la interfaa cu utilizatorul i la bara cu instrumente. Dac dorii s schimbai
numele fiierelor i/sau a extensiilor pe care s le foloseasc aplicaia apsai pe butonul Advanced i selectai
opiunile dorite. Pentru a trece la pasul urmtor apsai pe butonul Next >.
74
Laborator C++
Caseta de dialog MFC AppWizard Step 5 (vezi imaginea de mai jos) ofer posibilitatea alegerii
stilului proiectului (Explorer, care afieaz o reprezentare de tip arbore n paretea stng i o reprezentare de tip
list n partea dreapt, sau MFC Standard care ne ofer o singur regiune pentru reprezentarea unui fiier), a
generrii comentariilor n fiierele surs (care v pot ghida atunci cnd scriei codul surs a programului) i
modul n care dorii s utilizai biblioteca MFC. Pentru a trece la pasul apsai pe butonul Next >.
75
Laborator C++
Caseta de dialog MFC AppWizard Step 6 (vezi imaginea de mai jos) permite modificarea numelui
clasei, a clasei de baz, a numelui fiierului antet i a fiierului surs care sunt implicite.
76
Laborator C++
Clasa Descriere
CView Clasa de baz pentru toate reprezentrile.
Clasa de baz pentru CTreeView, CListView, CEditView, i CRichEditView. Aceste
CCtrlView clase permit folosirea arhitecturii document/reprezentare mpreun cu cele mai folosite
controale Windows.
O reprezentare simpl bazat pe controlul de editare Windows. Permite introducerea i
CEditView
editarea textului i poate fi folosit ca punct de pornire pentru un editor de texte simplu.
O reprezentare ce conine un obiect de tipul CRichEditView. Aceast clas este analoag
CRichEditView clasei CEditView, dar spre deosebire de ultima CRichEditView poate utiliza formatarea
textului.
CListView O reprezentare ce conine un obiect de tipul CListView.
O reprezentare ce conine un obiect de tipul CTreeView, util pentru reprezentrile
CTreeView
asemntoare ferestrei Workspace din Visual C++.
Clas de baz pentru CFormView, CRecordView, i CDaoRecordView. Ofer faciliti
CScrollView
pentru derularea coninutului reprezentrii (bara de derulare vertical, etc).
Folosete o machet de dialog ca reprezentare, permind aplicaiei s se prezinte ca un
CFormView
formular de baz de date.
Este o reprezentare de tip browser de Web cu ajutorul creia utilizatorul aplicaiei poate
CHtmlView accesa pagini de pe World Wide Web i de asemenea i directoare din sistemul de fiiere
local sau din reea.
Aceast clas este derivat din clasa CFormView i a fost dezvoltat pentru a face legtura
ntre reprezentare i o mulime de nregistrri dintr-o baz de date. Dac optai pentru
CRecordView
suport ODBC n proiectul creat atunci clasa de baz a clasei reprezentare va fi
CRecordView.
Aceast clas este derivat din clasa CFormView i se folosete la baze de date DAO.
CDaoRecordView Dac optai pentru suport DAO n proiectul creat atunci clasa de baz a clasei reprezentare
va fi CDaoRecordView.
Aceast clas este derivat din clasa CFormView, este nou aprut n versiunea 6.0 a
Microsoft Visual Studio, i este folosit la nregistrri de tipul OLE DB. Dac optai
pentru suport OLE DB n proiectul creat atunci clasa de baz a clasei reprezentare va fi
COleDBRecordView
COleDBRecordView.
Not: COleDBRecordView nu este nc recunoscut de ClassWizard, nici de ctre New
Class i nici de ctre comanda New Form din meniul Insert.
Apsnd butonul Finish va aprea o caset de dialog (vezi imaginea urmtoare) cu un sumar al
opiunilor selectate. Apsai pe butonul OK pentru ca AppWizard s creeze noua aplicaie conform opiunilor
selectate la paii anterior.
77
Laborator C++
Pentru a compila i a rula programul apsai pe butoanele Ctrl+F5 (sau pe bunonul _!_ sau selectai
comanda Execute din meniul Build) i apsai pe butonul OK.
Prin noiunea de resurs vom nelege o component adiional a unui proiect (pe lng codul C++)
care este stocat mpreun cu aplicaia i poate fi utilizat prin cod pentru afiarea de pictograme, meniuri, bara
cu instrumente(toolbar), bitmap-uri, iruri(string-uri) sau casete de dialog. Deci, meniul, bara cu instrumente .a.
sunt resurse pe care AppWizard le-a adugat proiectului atunci cnd l-a creat. Dac selectai pagina
ResourceView, i v uitai printre componentele ce se gsesc acolo, vei observa c exist patru resurse(o
tabel de acceleratori, o pictogram, un meniu i o bar cu instrumente) care au acelai
identificator(IDR_MAINFRAME). Efectund un dublu-clic pe oricare din acestea, vei avea posibilitatea
editrii acestora. Mai exist i o tabel de iruri. Aceasta reprezint un ir de caractere cu un format special; irul
este mprit n apte iruri distincte, delimitate de \n . Fiecare subir descrie un anumit atribut al
documentului aplicaiei(de exemplu primul subir reprezint titlul afiat n fereastra aplicaiei).
Dac v uitai la pagina ClassView a unei aplicaii de tip SDI, vei observa c AppWizard a creat patru
clase care gestioneaz structura aplicaiei(plus nc o clas corespunztoare aplicaiei de tip dialog About).
Aceste sunt: CNumeApp, CNumeDoc, CNumeView, CMainFrame (unde Nume reprezint numele aplicaiei
SDI create). Lanul motenirilor acestor clase este ilustrat n imaginea urmtoare.
78
Laborator C++
a) Clasa CNumeApp, derivat din CWinApp, se ocup de iniializarea aplicaiei, este responsabil pentru
ntreinerea relaiei dintre clasele document (CNumeDoc), reprezentare (CNumeView) i cadru
(CMainFrame). De asemenea, primete mesajele Windows i le expediaz ctre fereastra int corespunztoare.
b) ntr-o aplicaie cu interfa SDI, la un moment dat exist o singur instan a clasei CNumeDoc, derivat din
CDocument. Aceast clas are rolul de container pentru datele aplicaiei. Aceste date pot fi de orice form (de
exemplu pentru o aplicaie de prelucrare a textului datele ar putea conine textul n sine precum i unele detalii
legate de formatarea textului, n timp ce pentru o aplicaie de proiectare grafic datele ar putea conine
coordonate i alte detalii ale fiecrei componente ale unei imagini).
c) Clasa CNumeDoc, se ocup cu reprezentarea datelor documentului i permite acestuia s interacioneze cu
respectivele date. Clasa reprezentare acceseaz datele necesare prin intermediul funciilor membru oferite de
ctre clasa document.
d) Clasa CMainFrame are rolul de a furniza aplicaiei o fereastr. Aceast clas se ocup de asemenea i de
crearea , iniializarea i distrugerea barelor cu instrumente i a barei de stare.
Infrastructura MFC apeleaz funcia membru OnDraw a clasei reprezentare (adic funcia
CNumeView::OnDraw) de fiecare dat cnd reprezentarea trebuie generat pe ecran (de exemplu n cazul
redimensionrii ferestrei cadru). Aceast funcie este apelat i pentru a gestiona operaiile necesare pentru
tiprire i previzualizare. Deci pentu a implementa codul de desenare vom folosi aceast funcie membru
OnDraw().
n aplicaia pe care ai nceput-o mai sus (ora trecut), adugai n cadrul funciei OnDraw()
urmtoarele linii de cod (pentru aceasta efectuai un dublu-clic pe numele funciei i completai cu liniile de mai
jos!). Astfel vom vedea cum putem s desenm linii, dreptunghiuri, elipse etc.
79
Laborator C++
19 //pentru a afisa un mesaj vom folosi functia TextOut() care primeste drept parametri pozitia si
20 //respectiv textul de afisat
21 pDC->TextOut(200,200,"Laboratorul 15 : Visual C++!!!");
22
23 //pentru a obtine o valoare de tipul COLORREF (necesar functiilor ce necesita specificarea unei culori)
24 //vom folosi macro-ul RGB care necesita trei parametri (pentru detalii vezi mai jos,
25 // dupa aceste linii de cod). Pentru a seta o culoare de fundal folosim functia SetBkColor()
26 pDC->SetBkColor(RGB(124,124,124));
27 pDC->TextOut(200,250,"Primul laborator de Visual C++!!!");
28
29 pDC->SetBkMode(TRANSPARENT);
30 pDC->TextOut(200,245,"Primul laborator de Visual C++!!!");
31 pDC->SetBkMode(OPAQUE);
32 pDC->TextOut(200,205,"Primul laborator de Visual C++!!!");
33
34 pDC->SetTextColor(RGB(125,0,0));
35 pDC->TextOut(200,300,"Primul laborator de Visual C++!!!");
36
37 CRect rect;
38 GetClientRect(&rect);
Macro-ul RGB primete trei argumente i anume trei ntregi din intervalul [0, 255], corespunztori respectiv
nuanelor de rou (Red), verde (Green) i albastru (Blue).
Liniile 29-32 arat cum se poate folosi funcia SetBkMode(). Dac funcia primete parametru OPAQUE atunci
textul este afiat numai dup ce culoarea de fundal este desenat. Dac ns va primi parametrul
TRANSPARENT, textul afiat se va afia fr a se mai folosi nici o culoare de umplere pe fundal. Folosind
funcia SetTextColor putem seta culoarea cu care dorim s fie afiat un text. Aceast funcie primete drept
parametru o valoare de tip COLORREF.
De multe ori este necesar s tim dimensiunile ferestrei cu care lucrm. Pentru aceasta avem la dispoziie clasa
CRect i funcia GetClientRect(). Un obiect de tip CRect este determinat de patru numere ntregi (la care ne
putem gndi ca la cele patru coordonate corespunztoare colului stnga-sus i respectiv a colului din dreapta-
80
Laborator C++
jos corespunztoare unui dreptunghi). Pentru a obine dimensiunile ferestrei transmitem o referin la un obiect
de tip CRect funciei GetClienRect(). Liniile de cod 37-38 ncarc n rect dimensiunile ferestrei de lucru.
n VisualC++ pentru lucrul cu iruri putem lucra cu clasa CString. Aceast clas ofer faciliti extinse lucrului
cu iruri. De asemenea avem o clas definit i pentru lucrul cu puncte n coordonate bi-dimensionale: CPoint.
Problem:
Scriei un program MFC de tip SDI care realizeaz urmtorul desen:
Numrul de linii care se traseaz din fiecare col este egal cu 10.
81
Laborator C++
Pasul 4) Apsai un dublu-clic pe prototipul funciei OnDraw(CDC *pDC) (sau apsai clic-dreapta pe
OnDraw(CDC *pDC) i alegei opiunea Go to Definition)
Pasul 5) Adugai listingul urmtor:
82
Laborator C++
22 }
23 for (i = 0; i < n; i++){
24 pDC->MoveTo(0, r.Height());
25 pDC->LineTo(r.Width() / 2 - i * dx, 0);
26 }
27 for (i=0; i < n; i++){
28 pDC->MoveTo(r.Width(), 0);
29 pDC->LineTo(0, r.Height() / 2 - i * dy);
30 }
31 for (i=0; i < n; i++){
32 pDC->MoveTo(r.Width(), 0);
33 pDC->LineTo(r.Width() / 2 + i * dx, r.Height());
34 }
35 for (i=0; i < n; i++){
36 pDC->MoveTo(r.Width(), r.Height());
37 pDC->LineTo(0, r.Height() / 2 + i * dy);
38 }
39 for (i=0; i < n; i++){
40 pDC->MoveTo(r.Width(), r.Height());
41 pDC->LineTo(r.Width() / 2 + i * dx, 0);
42 }
43 }
Observaii:
1) n liniile 6 i 7 declarm un obiect de tip CRect i i transmitem dimensiunile ferestrei client cu ajutorul
funciei GetClientRect (care are urmtorul prototip: void GetClientRect( LPRECT lpRect ) );
2) n liniile 9 respectiv 10 am calculat distanele dintre capete a dou linii consecutive, capete care se afl pe axa
orizontal respectiv vertical;
3) Cu ajutorul funciilor MoveTo i LineTo vom desena apoi (din fiecare col) liniile cerute de enunul
problemei;
83
Laborator C++
Laborator 16
Problema 1.
Scriei un program MFC care aprinde fiecare pixel din zona client a ferestrei care se afl ntr-un punct de
coordonate (x, y) cu proprietatea cmmdc(x, y) = 1. Pentru a aprinde un pixel se folosete funcia SetPixel() a
clasei context de dispozitiv.
Rezolvare:
Se deschide programul Microsoft Visual C++ i se alege opiunea New din meniul File ca n exemplul de mai
jos:
84
Laborator C++
In care dup cte se poate observa se alege opiunea Projects iar din lista aparut se alege MFC
AppWizard(exe). In partea dreapt a ferestrei se va scrie numele proiectului n caseta de editare
corespunzatoare mesajului Project name iar dedesubt se va scrie locaia de pe disc unde va fi creat proiectul,
dup care se va apsa butonul OK.Va aprea urmtoarea fereastra:
85
Laborator C++
n care se va selecta opiunea Single Document , optiunea Document/View architecture support? este activat.
Apsnd Butonul Next > va aprea fereastra urmatoare, n aceast fereastr se va selecta opiunea None i se
apas butonul Next >, iar in fereasta urmtoare opiunea ActiveX Controls i Automation vor fi dezactivate ca
mai jos:
La pasul urmtor se va lsa totul aa cum apare, la fel cum se arat i mai jos:
86
Laborator C++
La fel i la pasul 5 opiunile care vor fi selectate trebuie lsate aa cum sunt.
87
Laborator C++
nainte de a se crea proiectul va fi afiat un mesaj ca mai jos, n care se va apsa butonul OK.
In meniu din dreapta al ferestrei de mai jos se va alege opiunea Class View.
Iar in funcia OnDraw din clasa CPuncteView n linia imediat urmtoare liniei : ,, // TODO: add draw
code for native data here , se va aduga urmtorul cod :
CRect r;
GetClientRect(&r);
int w=r.Width();
int h=r.Height();
for (int i=0; i<w; i++)
for (int j=0; j<h; j++)
if (gcd(i,j)==1)
pDC->SetPixel(i,j,RGB(250,0,0));
88
Laborator C++
Se creaz un obiect de tip CRect, n cazul nostru se numete r. Pentru mai multe amnunte vezi biblioteca
MSDN. Variabila w va lua valoare egal cu numrul de puncte al lungimii zonei client a ferestrei iar variabila h
valoarea egal cu naltimea zonei client. Mai departe se testeaz cu ajutorul funciei gcd (pe care o vom
implementa imediat) dac puctele din zona client sunt prime ntre ele. In cazul n care sunt prime se folosete
contextul de dispozitiv pDC i funcia membru SetPixel() pentru a afia pixelul respectiv ntr-o anumit culoare.
In cazul de fa am ales pentru funcia RGB care seteaz paleta de culori, valorile 255, 0 si 0 ceea ce nseamn
culoarea rosu.
89
Laborator C++
Dar s revenim la implementarea funcei gcd. Se adaug in fiierul puncteview.cpp naintea declaraiei funciei
OnDraw urmtorul cod:
int gcd(int a, int b)
{
if (b==0) return a;
else return gcd(b,a%b);
}
90
Laborator C++
Fiierul puncteview.cpp este corespunztor clasei CPuncteView. Deci pentru a-l deschide vom deschide clasa
CPuncteView.
n continuare vom compila programul i-l vom executa. Va trebui s obinem urmtorul rezultat :
Problema 2.
Desenai triunghiul lui Sierpinski de ordin n. (Se deseneaz un triunghi. Se iau mijloacele celor trei laturi i
elimin triunghiul format de aceste trei puncte. Pentru cele trei triunghiuri rmase se procedeaz la fel.)
Rezolvare:
Se creaz un proiect de tip SDI(Single Document Interface) cu numele Sierpinski.
Implementm o funcie membru clasei View cu numele Vizor de tip void i cu 5 parametri un int, un pointer la
CDC, i trei CPoint astfel:
apasm click dreapta n dreptul clasei CSierpinskiView , selectm Add Member Function i decalarm funcia
astfel:
91
Laborator C++
92
Laborator C++
Observaie:
n funcia OnDraw variabila n se poate modifica, astfel vom obine un alt desen.
93
Laborator C++
Laborator 17
Problema 1
Desenai un poligon regulat cu n laturi n zona client a ferestrei. Numrul de laturi n se modific (incrementeaz
i decrementeaz) prin opiuni de meniu i prin butoane pe bara cu instrumente.
Rezolvare:
Se creaz un proiect de tip SDI cu numele Poligon. La primul pas opiunea Document/View arhitecture
support? va fi inactivat.
n funcia membru OnPaint a clasei CChildView se adaug urmtorul cod:
1 double pi = 3.1415926535;
2 CRect r;
3 GetClientRect(&r);
4 dc.SetViewportOrg(r.CenterPoint());
5 CString s;
6 s.Format("n=%d",n);
7 dc.TextOut(10,10,s);
8 CPoint pcti,pctf;
9 for (int k=0; k<n; k++)
10 {
11 pcti=CPoint(100*cos((2*k*pi)/n), 100*sin((2*k*pi)/n) );
12 pctf=CPoint(100*cos((2*(k+1)*pi)/n),100*sin((2*(k+1)*pi)/n) );
13 dc.MoveTo(pcti);
14 dc.LineTo(pctf);
15 }
n prima linie se declar variabila pi de tip double i se iniializeaz..
Variabila n de tip int va fi declarat n clasa CChildView n seciunea private i va fi iniializat cu valoarea 3
n constructorul clasei CChildView.
n fiierul ChildView vom include biblioteca math.h pentru a se putea folosi funciile sin i cos predefinite n
aceast clas.
#include <math.h>
Vom crea n continuare dou butoane pentru a mri i micora numrul de laturi. Aceste butoane se vom crea
astfel: apsm un clic stnga pe ResourseView, deschidem Poligon resources, Toolbar i
94
Laborator C++
Ultimul pas al rezolvrii problemei va fi crearea unor funcii care trateaz apsarea butoanelor n+ i n- .
Acestea vor fi funcii membre a clasei CChildView i se vor aduga folosind ClassWizard.
Atenie aceste funcii trebuie s fie funcii membre a clasei CChildView pentru aceasta se va selecta aceast
clas la meniul corespunztor mesajului ClassName(la fel ca n imaginea de mai sus) .
Se va apsa butonul Add Function dup ce n prealabil se va selecta ID_POLIGON_MARIRE i
COMMAND i va aprea urmtoarea fereastr:
95
Laborator C++
n care se va scrie numele funciei, n cazul nostru implicit va fi scris numele OnPoligonMarire.
La fel se procedeaz i pentru adugarea funciei de micorare a numrului de laturi.
Dup realizarea acestor dou funcii n ClassWizard se apas butonul Edit Code i se va modifica codul astfel
nct s arate astfel:
void CChildView::OnPoligonMarire()
{
// TODO: Add your command handler code here
n++;
Invalidate();
}
void CChildView::OnPoligonMicsorare()
{
// TODO: Add your command handler code here
n--;
Invalidate();
}
Se observ c se incrementeaz n respectiv se decrementeaz, iar funcia Invalidate() se folosete pentru a
rescrie zona client a ferestrei.
Dup compilare i execuie vom obine urmtorul rezultat:
Problema 2:
Scriei un program MFC care desenarea i apoi rotete un cub.
Se creaza o clasa Cpoint3D pentru reprezentarea unui punct n spaiu i rotirea punctului.
Se creaz o clas pentru cub. (Implementarea funciilor de rotaie n jurul celor 3 axe ca rspuns la apsarea unor
taste. Eventual se va ine cont i de perspectiv).
(Funcie pentru scalarea cubului.)
96
Laborator C++
Laborator 18
Obiective:
Familiarizarea cu:
Casete de dialog. Clasa document.
Funcia AfxMessageBox(). CColorDialog, CFontDialog,
Crearea casetelor de dialog modale. Adugarea resurselor de tip dialog. Funcia DoModal().
Problem:
Scriei un program MFC care cere utilizatorului introducerea unor date despre o persoana printr-o caseta de
dialog (numele, prenumele, varsta i salveaz datele ntr-o colecie din clasa document). Toate datele introduse
se afieaz n zona client a ferestrei. Programul va permite si salvarea datelor aplicaiei ntr-un fiier pe disc i
ncrcarea datelor dintr-un fiier de pe disc (serializare).
Rezolvare:
Se creaz un proiect de tip SDI urmnd pai descrii n laboratorul 16 cu excepia faptului c la pasul 6 clasa de
baz va fi CScrollView pentru a putea afia n zona client a ferestrei pe mai multe linii i pentru a putea fi
vizualizate aceste linii cu ajutorul unei bare de derulare. Pentru exemplu nostru am considerat numele proiectului
Persoane.
Urmtorul pas n rezolvarea problemei va fi inserarea unei casete de dialog astfel: se deschide ResourceView, se
apas un clic dreapta n dreptul directorului Dialog i din lista aprut se alege Insert Dialog iar n noul Dialog
creat se vor aduga trei controale de tip Static Text i n dreptul fiecruia cte un control de tip Edit Box.
Caseta de dialog va avea urmatoarea forma:
Se deschide din nou caseta de dialog creat i din meniul View se deschide ClassWizard, i ne va fi afiat o
fereastr prin care putem crea o clasa corespunztoare noului Dialog.
97
Laborator C++
Se va selecta Create a new class i se va apasa butonul OK, i ne va fi afiat o fereastr n care se va scrie
numele Clasei, n exemplu prezentat am ales numele CPers, iar clasa de baz corespunztoare va fi CDialog, iar
prin butonul Change se poate modifica numele fisierele corepunztoare acestei clase.
Dup ce am stabilit numele clasei, clasa de baza pentru clasa creat i ID-ul clasei se va apsa butonul OK.
La urmtorul pas se apas un dublu clic pe butonul OK pentru a se introduce o funcie care trateaz apasarea
butonului respectiv. n fereastra aparut se va scrie numele funciei, implicit numele funciei va fi OnOK dar
poate fi modificat (ceea ce nu este prea indicat).
98
Laborator C++
Dup stabilirea numelui funciei se apasa butonul OK din acea fereastr i va fi adugat automat aceast funcie
n care automat va fi introdus urmtoarea linie de cod: CDialog::OnOK(); . La fel se adaug i funcia care
trateaz apsarea butonului Cancel.
n fereastra MFC ClassWizard se va alege pagina Member Variables i se va asocia casetelor de editare
corespunztoare Numelui i Prenumelui cte dou variabile fiecruia: una de tip CEdit i una de tip CString cu
nume m_nume i m_v_nume respectiv m_prenume i m_v_prenume, iar casetei de editare corespunztor
vrstei o variabil de tip UINT cu numele m_v_varsta care va lua valori ntre 1 i 80 i o variabil de tip CEdit
cu numele m_v astfel:
se apas butonul AddVariable dup care in fereastra Add Member Variable se va scrie numele variabilei i va
fi ales tipul ei. n cazul variabilelor de tip CString se va alege categoria Value iar n cazul variabilei de tip
CEdit categoria Control.
Vom alege pe urm n proiectul nostru ClassView i vom aduga o nou clas apsnd un clic dreapta pe
Persoane Classes i alegem opiunea New Class. Clasa creat va fi Generic Class i numele CPersoana i care
nu va fi derivat din alt clas, iar n aceast clas se va aduga o funcie membr cu numele Draw care va avea
ca parametri un pointer la CDC (Context de dispozitiv ) i doi ntregi. De asemenea acestei clase i se va aduga
i un constructor cu parametri: doi de tip referin la CString i un unsigned int.
Variabilele se vor introduc apsnd un click dreapta pe numele clasei i se alege Add Member Variable i va fi
afiat urmtoarea fereastr:
Tipul funciei va fi void n cazul funciei Draw iar n cazul constructorului nu se va scrie nimic. La declaraia
funciei se va scrie numele urmat de o parantez n care se va scrie parametri separai de virgul.
Dup ce am introdus aceste funcii codul lor va fi modificat ca s arate astfel:
Vor mai fi introduse tot n aceast clas variabilele nume i prenume de tip CString i variabila vrsta de tip
unsigned, prin opiunea Add Member Variable.
Pentru serializare vom modifica funcia Serialize() a clasei CPersoaneDoc astfel:
99
Laborator C++
}
}
}
De asemenea se va introduce o colecie cu numele persoane care este vector cu persoanele introduse astfel:
se adaug urmtorul cod n fiierul PersoaneDoc.h n seciunea de declaraii private
std::vector<CPersoana> persoane;
De asemenea tot n acest fiier se introduce i urmtorul cod
#include "Persoana.h"
#include <vector>
n seciunea #include.
Funcia OnDraw a clasei CPersoaneView va fi modificat astfel:
n continuare vom deschide pagina ResourceView din directorul Toolbar i n cadrul lui fiierul
IDR_MAINFRAME i vom introduce un buton.
100
Laborator C++
101
Laborator C++
Dup apsarea butonului Add Function se va aduga funcia OnButton32771 (numele acestei funcii se poate
modifica, aici am lsat numele funciei aa cum apare) care va trebui modificat prin apsarea butonului Edit
Code s arate astfel:
void CPersoaView::OnButton32771()
{
CPers dlg;
CPersoaDoc* pDoc = GetDocument();
Astfel dup ce vom compila i executa programul vom putea introduce date, aceste date fiind afiate ulterior n
zona client a meniului astfel:
102
Laborator C++
La final dup introducerea datelor despre persoane dac nu am salvat datele ntr-un fiier i vom dori s
nchidem fereastra programul ne va avertiza n legtur cu salvarea fiierului pe disc.
103
Laborator C++
Dac vom apsa butonul No atunci vom renuna la salvarea pe disc a datelor, dac vom apsa Yes va aprea
fereastra urmtoarea n care vom putea scrie numele i extensia fiierului n care se vor salva datele.
104
Laborator C++
Laborator 19
Scriei un program care cere utilizatorului introducerea datelor despre persoane (numele, prenumele, vrsta) i
afieaz n zona client a ferestrei datele introduse. Programul permite modificarea culorii de afiare (folosind
clasa CColorDialog), modificarea fontului folosit (folosind clasa CFontDialog), modificarea culorii de fundal
precum i cutarea unei persoane n colecie i tergerea ei dac utilizatorul cere aceasta. (clasa de baza a
aplicaiei va fi CScrollView).
Pasul1: Creai o aplicaie SDI (pe care noi am numit-o de exemplu Persoane2)
iar la pasul 6 al lui AppWizard selectai astfel nct clasa de baza s fie CScrollView (vezi imaginea de mai
jos).
105
Laborator C++
Pasul 2: Vom crea o nou clas, CPersoana, care va conine urmtoarele date individuale: nume,
prenume,respectiv varsta. Pentru aceasta dai un clic-dreapta pe foaia ResourceView i selectai opiunea New
Class (vezi imaginea urmtoare).
Acum ar trebui s v apar caseta de dialog New Class, unde vei selecta ca tipul noi clase s fie una generic
iar aceast nou clas am denumit-o CPersoana (vezi imaginea de mai jos). Dup introducerea acestor date
apsai pe butonul OK pentru a nchide aceast caset de dialog.
106
Laborator C++
Efectuai, dup aceea, un clic pe semnul + din stnga numelui Persoane2 classes din pagina ClassView. Vei
vedea acum toate clasele proiectului. Efectuai un dublu-clic pe numele clasei CPersoana i adugai liniile de
cod de mai jos n declaraia acestei clasei:
1) #pragma once
2) #endif // _MSC_VER > 1000
3)
4) class CPersoana
5) {
6) public:
7) CPersoana();
8) CPersoana( CString nume_ , CString prenume_ , int varsta_ );
9) CString GetNume();
10) CString GetPrenume();
11) int GetVarsta();
12) void SetNume( CString nume_ );
13) void SetPrenume( CString prenume_ );
14) void SetVarsta( int varsta_ );
15)
16) virtual ~CPersoana();
17) private:
18) CString Nume, Prenume;
19) int Varsta;
20) };
Astfel am declarat, n liniile 18-19, variabilele membru Nume, Prenume i Varsta ca avnd tipul CString,
CString respectiv int ; n liniile 7-8 se poate observa c vom avea doi constructori ai acestei clase (dintre care
primul este implicit) .
107
Laborator C++
n plus vom avea nc ase funcii, cte dou pentru fiecare variabil membru a acestei clase: una care s ne
returneze valoarea variabilei iar alta pentru stabilirea valorii acestei variabile.
Acum, efectuai din nou un clic pe semnul + din dreptul numelui clasei CPersoana i efectuai un dublu-clic
pe numele ce se afl imediat sub numele acestei clase (adic pe numele constructorului acestei clase:
CPersoana() ) i completai cu liniile de cod de mai jos care reprezinta codul fiecrei funcii-membru n parte.
1) CPersoana::CPersoana()
2) {
3) Nume="";
4) Prenume="";
5) Varsta=0;
6) }
7)
8) CPersoana::CPersoana( CString nume_ , CString prenume_ , int
varsta_ )
9) {
10) Nume=nume_;
11) Prenume=prenume_;
12) Varsta=varsta_;
13) }
14) CPersoana::~CPersoana()
15) {
16)
17) }
18)
19) CString CPersoana::GetNume()
20) {
21) return Nume;
22) }
23)
24) CString CPersoana::GetPrenume()
25) {
26) return Prenume;
27) }
28)
29) int CPersoana::GetVarsta()
30) {
31) return Varsta;
32) }
33)
34) void CPersoana::SetNume(CString nume_ )
35) {
36) Nume=nume_;
37) }
38)
39) void CPersoana::SetPrenume(CString prenume_ )
40) {
41) Prenume=prenume_;
42) }
43)
44) void CPersoana::SetVarsta(int varsta_ )
45) {
46) Varsta=varsta_;
47) }
108
Laborator C++
Pasul 3: Pentru a le ine n memorie i putea opera cu aceste date personale vom utiliza clasa predefinit vector.
Pentru aceasta introducei urmtoarele linii de cod n declaraia clasei document CPersoane2Doc (aveti de
introdus doar liniie 4, 5 i 16)
1) #pragma once
2) #endif // _MSC_VER > 1000
3)
4) #include <vector>
5) #include"Persoana.h"
6)
7)
8) class CPersoane2Doc : public CDocument
9) {
10) protected: // create from serialization only
11) CPersoane2Doc();
12) DECLARE_DYNCREATE(CPersoane2Doc)
13)
14) // Attributes
15) public:
16) std::vector<CPersoana> persoanele;
17)
18)
19) // Operations
20) public:
Absolut analog vom declara n clasa reprezentare (adic n clasa CPersoane2View) urmtoarele variabile
membru: culoare_scris, culoare_fundal (pentru culoarea cu care s se scrie n zona Client, respectiv culoarea
de fundal, ambele de tipul COLORREF), lf (necesar fontului cu care s se afieze textul, de tipul
LOGFONT), i un ntreg, schimbare_font, pe care l vom folosi pentru a ti dac pe parcursul rulrii aplicaiei
am dorit s schimbm fontul caracterelor sau nu (n cazul din urm vom lsa fontul implicit). Pentru aceasta
introducei urmtoarele linii de cod (mai trebuie inserate doar liniile 12-14) n declaraia clasei reprezentare:
Pentru a iniializa aceste variabile-membru adugai n constructorul clasei reprezentare urmtoarele linii de cod:
1) CPersoane2View::CPersoane2View()
2) {
109
Laborator C++
Pasul 4: Pentru ca utilizatorul s poat introduce datele unei persoane vom folosi o resurs de tip dialog. Pentru
aceasta, pe pagina (lista) ResourceView apsai clic-dreapta pe eticheta Dialog i selectai opiunea Insert
Dialog.
Acum adugai pe aceast nou resurs de tip dialog trei etichete statice i trei controale de editare astfel nct s
arate asemntor cu imaginea urmtoare:
.
Pentru aceasta efectuai un clic-dreapta oriunde pe suprafaa liber a acestei casete de dialog i selectai opiunea
Properties. n csua de editare din dreapta etichetei Caption introducei numele pe care dorii sa-l aib caseta
de dialog atunci cnd ea va fi accesat (noi am introdus PERSOANA).
110
Laborator C++
Efectuai apoi pe fiecare etichet static un clic-dreapta i selectai opiunea Properties. n csua de editare din
dreapta etichetei Caption introducei numele pentru fiecare etichet n parte.(noi am introdus Nume:, Prenume:
i respectiv Varsta:). Vezi imaginea urmtoare pentru eventualele neclariti.
Vom asocia, n cele ce urmeaz, fiecare din cele trei casete de editare cte un nume i anume IDC_NUME,
IDC_PRENUME si respectiv IDC_VARSTA astfel: efectuai pe fiecare caseta de editare cte un clic-dreapta
i selectai opiunea Properties. n csua de editare din dreapta etichetei ID introducei numele pentru fiecare
casu de editare n parte.
Vom asocia (n cele ce urmeaz) aceast resurs de dialog cu o nou clas pe care o vom crea. Deschidei
ClassWizard (apsnd direct Ctrl+W sau selectnd opiunea ClassWizard din meniul View). Se va deschide
automat caseta de dialog Adding a Class. Apsai pe butonul OK pentru a crea o nou clas.
111
Laborator C++
Acum se deschide caseta de dialog New Class. Denumii aceast nou clas CDlgPers. n felul acesta, pentru
caseta de dialog pe care am creat-o noi avem asociat o clasa: CPersDlg.
Pentru a putea lucra mai uor cu datele introduse n caseta de dialog, vom asocia celor trei casete de editare (vom
mapa peste ele) cte o variabil (conform cu tabelul de mai jos:)
Control ID Variable Name Category Type
IDC_NUME m_Nume Value CString
IDC_PRENUME m_Prenume Value CString
IDC_VARSTA m_Varsta Value int
Pentru aceasta, dai un clic pe oricare din aceste casete de editare dup care deschidei ClassWizard. Ar trebui
s se deschid o caset de dialog asemntoare cu cea din imaginea de mai jos (daca nu este aa: selectati mai
intai pagina Members Variables i asigurai-v c este selectat (n cmpul Class name:) clasa CPersDlg).
112
Laborator C++
Selectai IDC_NUME i efectuai un clic pe Add Variable (sau apsai direct un dublu-clic pe IDC_NUME).
Ar trebui s v apar caseta de dialog Add Member Variable. Introduceti m_Nume pentru numele noii
variabile membru pe care s o creeze ClassWizard i selectai CString pentru tipul acestei variabile.
Procedai analog i pentru IDC_PRENUME (i dai-i numele m_Prenume, tipul CString) i respectiv
IDC_VARSTA (i dai-i numele m_Varsta, tipul int).
Pasul 5: Acum vom crea o opiune de meniu Adaugare persoana (cu ajutorul careia vom aduga cte o
persoan n lista persoanele de tipul vector de CPersoana) n meniul pe care tot noi l vom crea i l vom
113
Laborator C++
denumi Persoane. Mai intai vom crea aceast meniu Persoane. Pentru aceasta apsai un clic pe semnul + ce
se afl n stnga etichetei Menu din pagina ResourceView. Efectuai acum un dublu-clic pe eticheta
IDR_MAINFRAME. Pe dreptunghiul gol din drepta etichetei Help de sus efectuai un clic dreapta i selectai
opiunea Properties. Se va deschide caseta de dialog Menu Item Properties. n caseta de editare Caption
introducei numele noului meniu: &Persoane.
Semnul & dinaintea literei P va determina ca n numele acestui meniu acea liter s apar subliniat (n cazul
nostru P). Aceasta se folosete pentru aa numitele taste fierbinti. Astfel, n cazul de fa prin simpla apsare
simultan a tastelor Alt+P vom accesa direct meniul Persoane. Dac dorim ca n numele unui meniu sau a unei
opiuni din meniu s apar i caracterul &, acesta trebuie dublat adic vom scrie && peste tot unde vom dori s
apar &. Pentru a schimba poziia meniului Persoane (deoarece poziia sa fireasc ar fi naintea meniului Help)
vom apsa un clic pe dreptunghiul unde su i, innd apsat butonul stng al mouse-ului, l "tragem" nspre
stnga meniului Help. Acum meniul ar trebui s arate ca n imaginea de mai jos:
Acum vom crea opiunea de meniu Adaugare persoana. Pentru aceasta vom urma aceeai pai de mai sus ns
dreptunghiul gol folosit va fi cel care s-a creat automat sub numele Persoane. Schimbai i numele din dreapta
etichetei statice ID: cu numele ADAUGARE_PERSOANA (vezi imaginea de mai jos)
114
Laborator C++
Pasul 6: Pentru ca atunci cnd selectm opiunea Adaugare persoana din meniul Persoane s se efectueze ceva
(de exemplu, n cazul nostru, s se deschid o caset de dialog de tipul CDlgPers) va trebui s apelam din nou la
ClassWizard. Pentu aceasta deschidei ClassWizard. Selectai pagina Message Maps, la numele clasei selectai
CPersoane2View (am ales aceast clas pentru a putea lucra mai usor cu membrii acestei clase dar la fel se
putea folosi oricare alt clas), iar la Object IDs selectai ADAUGARE_PERSOANA. Selectati astfel ca tipul
mesajului care s fie tratat s fie COMMAND apoi efectuai un clic-stnga pe Add Function (vezi imaginea de
mai jos pentru detalii).
Schimbai numele implicit de funcie care apare n caseta de dialog Add Member Function (sau putei s-l
lsai nemodificat dac v convine acest nume de funcie mai mult) cu numele OnAdaugarePersoana i apsai
pe butonul OK.
115
Laborator C++
n final apsai pe butonul Edit Code pentru ca ClassWizard s v deschid fiierul unde s-a creat noua funcie
i sa editai codul surs al acestei funcii. Acolo adugai liniile de cod de mai jos:
1) /////////////////////////////////////////////////////////////////////////////
2) // CPersoane2View message handlers
3) #include "Persoana.h"
4) #include "DlgPers.h"
5) void CPersoane2View::OnAdaugarePersoana()
6) {
7) // TODO: Add your command handler code here
8) CPersoane2Doc* pDoc = GetDocument();
9) ASSERT_VALID(pDoc);
10)
11) CDlgPers dlg;
12) int valoare_return;
13)
14) valoare_return=dlg.DoModal();
15) if(valoare_return==IDOK)
16) {
17) pDoc->persoanele.push_back(CPersoana(dlg.m_Nume,dlg.m_Prenume,dlg.m_Varsta));
18) }
19) Invalidate();
20) }
n liniile 8-9 declarm un pointer de tipul CPersoane2Doc prin care vom face o legtur ntre clasa reprezentare
i clasa document. n linia a 11-a declarm un obiect de tipul CDlgPers n linia a 14-a folosind funcia membru
DoModal() se va deschide caseta de dialog dlg. Dac vom apsa butonul OK al acestei casete de dialog atunci
se va returna constanta ntreag predefinit IDOK, iar dac apsm pe butonul Cancel al acestei casete de dialog
se va returna IDCANCEL. Folosind functia membru push_back(), vom introduce n vectorul de persoane
persoanele acea nou persoan pe care tocmai am introdus-o n aceast caset de dialog. Astfel c, folosind
variabilele membru ale casetei de dialog, vom transmite constructorului clasei CPersoana cele trei variabile:
m_Nume, m_Prenume i m_Varsta. Pentru a redesena ecranul (zona Client a ferestrei) folosim funcia
Invalidate().
Pasul 7: Pe numele funciei OnDraw() pe care o gsii pe pagina ClassView (vezi imaginea de mai jos)
116
Laborator C++
117
Laborator C++
n liniile 9-10 setm culoarea de scris i cea de fundal pe care le-am ales (altfel rmn cele implicite). n liniile
12-17 schimbm fontul de scriere (asta doar n cazul n care utilizatorul a ales vreun font). n liniile 26-29 vom
crea o bar de derulare vertical atunci cnd este cazul (adic atunci cnd avem mai multe linii de afiat dect se
poate afia ntre dimensiunile curente). Iar in liniile 33-37 se afieaza toate persoanele pe care le-am introdus n
vectorul persoanele.
Pasul 8: Vom aduga acum opiunile de meniu necesare schimbrii culorii de fundal, culorii de scriere i a
fontului. Pentru aceasta vei lucra analog cu pasul 6 (vezi imaginea urmtoare pentru mai multe detalii). Astfel
c vei crea un meniu nou Setari culoare si font, unde vei crea trei opiuni de meniu: Setare Font, Culoare
afisare i Culoare fundal.
118
Laborator C++
Cu ajutorul lui ClassWizard creai cele trei funcii de tratare a acestor trei opiuni de meniu (nu uitai s alegei
astfel nct clasa de baz s fie CPersoane2View !).
Dup ce apsai pe butonul Edit Code inserai liniile de cod de mai jos:
1) void CPersoane2View::OnFont()
2) {
3) // TODO: Add your command handler code here
4) //schimbarea fontului folosit
5)
6) CFontDialog dlg;
7) int ret = dlg.DoModal();
8) if (ret == IDOK)
9) {
10) schimbare_font=1;
11) dlg.GetCurrentFont(&lf);
12) Invalidate();
13) }
14) }
15)
16) void CPersoane2View::OnCuloareAfisare()
17) {
18) // TODO: Add your command handler code here
19)
20) CColorDialog dlg;
21)
22) int valoare_return;
23) valoare_return=dlg.DoModal();
24) if(valoare_return==IDOK)
25) {
26) culoare_scris=dlg.GetColor();
27) }
28) Invalidate();
29)
30) }
31)
32) void CPersoane2View::OnCuloareFundal()
33) {
34) // TODO: Add your command handler code here
35) CColorDialog dlg;
36)
37) int valoare_return;
38) valoare_return=dlg.DoModal();
39) if(valoare_return==IDOK)
40) {
41) culoare_fundal=dlg.GetColor();
42) }
43) Invalidate();
44) }
n liniile 20 i respectiv 35 am declarat un obiect (dlg) de tip CColorDialog. Cu ajutorul funciei membru
DoModal() deschidem aceast caset de dialog. Dac vom apsa pe butonul OK aceast caset de dialog va
returna constanta IDOK. n acest caz, cu ajutorul funciei membru GetColor(), vom obine culoarea selectat i
o vom copia n variabila membru a clasei reprezentare culoare_scris respectiv culoare_fundal. Analog se
opereaz i n cazul celeilalte funcii (folosind ns CFontDialog). Vom folosi functia Invalidate() pentru a se
redesena zona client de fiecare dat cnd schimbm vreo culoare sau fontul.
119
Laborator C++
Sistemul de operare Windows conine o serie de casete de dialog. Acestea se folosesc pentru alegerea culorii, a
fontului, pentru alegerea unui fiier ce trebuie deschis, etc. Mai sus noi am folosit dou astfel de casete de
dialog: cea pentru alegerea culorii i cea pentru selectarea fontului. Pentru a folosi caseta de dialog pentru
alegerea culorii trebuie doar s declarm un obiect de tipul CColorDialog i s folosim funcia membru
DoModal. Imaginea de mai jos ne arat caseta de dialog ce se folosete pentru alegerea culorii. Funcia
membru GetColor ne returneaz culoarea selectat (de fapt aceast funcie returneaz o valoare de tipul
COLORREF).
Analog i pentru alegerea fontului folosind ns clasa CFontDialog. Imaginea de mai jos ne arat caseta de
dialog ce se folosete pentru alegerea fontului. Cu ajutorul funciei membru (a acesetei clase) GetCurrentFont
care primete ca argument un pointer la o variabil de tipul LOGFONT vom putea obine fontul ales.
120
Laborator C++
n ambele cazuri funcia membru DoModal returneaz una din urmtoarele constante predefinite: IDOK sau
IDCANCEL n funcie de butonul pe care s-a apsat pentru nchiderea casetei de dialog.
Constructorul clasei CColorDialog este:
unde:
Este culoarea implicit de selecie.Dac nu se alege nici o culoare
clrInit
valoarea implicit este RGB(0,0,0) (adica negru).
O mulime de indicatori care personalizeaz funcia i reprezentarea
dwFlags
casetei de dialog.
pParentWnd Un pointer ctre fereastra printe a acestei casete de dialog.
unde:
Un pointer la o structur de date de tip LOGFONT ce v permite
lplfInitial
setarea unor caracteristici ale fontului.
Specific unul sau mau muli indicatori de font alei. Una sau mai
dwFlags
multe valori predefinite se pot combina utiliznd operatorul binar OR.
pdcPrinter Un pointer catre un dispozitiv de context pentru imprimant.
pParentWnd
Un pointer ctre fereastra printe a acestei casete de dialog.
Observai c aceast clas are toi parametri implicii. Vei modifica acesti parametri doar n cazul n care dorii o
caseta de dialog pentru selectarea fontului diferit de cea implicit.
121
Laborator C++
Pasul 9: Vom crea acum nc o opiune de meniu pentru tergerea unei persoane din vector (i implicit tergerea
acelei persoane din persoanele afiate n zona Client a ferestrei). Pentru aceasta creai nc o opiune de meniu
numit Eliminare persoana n meniul Persoane, sub opiunea de meniu Adaugare persoana. (pentru detalii
vezi pasul 6)
Asociai acum o funcie de tratare a acestei opiuni de meniu.(vezi imaginea urmtoare sau pasul 6 pentru
detalii)
1) void CPersoane2View::OnEliminarePersoana()
2) {
3) // TODO: Add your command handler code here
4) CPersoane2Doc* pDoc = GetDocument();
122
Laborator C++
5) ASSERT_VALID(pDoc);
6)
7) CDlgPers dlg;
8) int valoare_returnata=dlg.DoModal();
9) if(valoare_returnata==IDOK)
10) {
11) for(int i=0;i<pDoc->persoanele.size();i++)
12) if(dlg.m_Nume==pDoc->persoanele[i].GetNume() )
13) if(dlg.m_Prenume==pDoc->persoanele[i].GetPrenume() )
14) if(dlg.m_Varsta==pDoc->persoanele[i].GetVarsta() )
15) {
16) pDoc->persoanele.erase(&pDoc->persoanele[i]);
17) break;
18) }
19) Invalidate();
20) }
21) }
n liniile 4-5 vom crea un pointer ctre obiectul clasei document pentru a avea acces la membri acesteia. n liniile
7-8 (folosind acelai tip de caset de dialog ca i pentru adugarea datelor unei persoane) vom afia o caset de
dialog pentru obinerea datelor despre persoana pe care dorim s o tergem din list. n liniile 9-20 cutm n
lista persoanele persoana pe care am introdus-o mai nainte i n cazul n care gsim o persoan care s
corespund cu aceste date o tergem din list.(Observaie: se va terge doar prima persoan din list care
corespunde cu datele introduse. Dac tergem linia a 17-a se vor terge toate persoanele care corespund cu datele
introduse).
Acum compilai i rulai programul.
123
Laborator C++
Laborator 20
Scriei un program care deseneaz drepunghiuri n zona client a ferestrei cu ajutorul mouse-ului. Un col al
dreptunghiului va fi punctul n care se apasa butonul din stanga al mouse-ului iar colul opus va fi punctul n care
se elibereaza butonul din stnga al mouse-ului. Se va putea modifica grosimea liniei cu care se deseneaz
dreptunghiul printr-o caset de dialog personalizat, culoarea liniei i culoarea de umplere a dreptunghiului.
Cuvinte cheie: mesaje, WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_LBUTTONUP
n funcia OnMouseMove() se verific dac se mic mouse-ul cu butonul din stnga apsat. (constanta
MK_LBUTTON). CBrush, CPen, Invalidate(), InvalidateRect().
Rezolvare:
Pasul 1: Creati o nou aplicaie SDI i dai-i numele DesenareDreptunghiuri.
Pasul 2: Creai o nou clas (generic) i dai-i numele CDreptunghi (vezi imaginea de mai jos).
n constructorul acestei clase introducei variabilele membru: punct_initial i punct_final ambele de tipul
CPoint, funcia membru:Rect() (va returna un obiect de tip CRect) i constructorul: CDreptunghi(CPoint
initial, CPoint final); astfel declaraia clase va arta ca mai jos:
1) class CDreptunghi
2) {
3) public:
4) CDreptunghi();
5) CDreptunghi(CPoint initial, CPoint final);
6) virtual ~CDreptunghi();
7) CRect Rect();
8) public:
9) CPoint punct_initial, punct_final;
10) };
Acum vom codul surs pentru fiecare funcie membru. Pentru aceasta introducei liniile de cod surs de mai jos:
124
Laborator C++
1) //////////////////////////////////////////////////////////////////////
2) // Construction/Destruction
3) //////////////////////////////////////////////////////////////////////
4)
5) CDreptunghi::CDreptunghi()
6) {
7)
8) }
9)
10) CDreptunghi::~CDreptunghi()
11) {
12)
13) }
14)
15) CDreptunghi::CDreptunghi(CPoint initial, CPoint final)
16) {
17) punct_initial=initial;
18) punct_final=final;
19) }
20)
21) CRect CDreptunghi::Rect()
22) {
23) return CRect(punct_initial, punct_final);
24) }
Liniile de cod 1-13 sunt introduse implicit, deci nu trebuie s mai introducem dect liniile 14-24. Liniile 15-19
reprezint constructorul clasei pe care tocmai am creat-o. Acest constructor va accepta ca parametri dou
variabile de tipul CPoint. punct_initial i punct_final vor reprezenta cele dou vrfuri opuse (nealturale) ale
unui dreptunghi desenat. Atunci cnd vom desena dreptunghiul, vom avea nevoie de un obiect de tipul CRect.
Funcia membru Rect() (vezi liniile 21-24) ne returneaz tocmai un obiect de tipul CRect corespunztor
punctelor punct_initial i punct_final.
Pasul 3: Acum vom declara un vector de obiecte de tipul CDreptunghi. Scopul este de a putea memora toate
dreptunghiurile pe care le desenm astfel c la o eventual redimensionare sau doar la o redesenare a zonei
client dreptunghiurile desenate s nu se tearg. Pentru acesta efectuai un dublu-clic pe numele clasei document
CDesenareDreptunghiuriDoc i introducei liniile de cod 3,4 i 17 ca mai jos:
1) #pragma once
2) #endif // _MSC_VER > 1000
3) #include<vector>
4) #include"Dreptunghi.h"
5)
6) class CDesenareDreptunghiDoc : public CDocument
7) {
8) protected: // create from serialization only
9) CDesenareDreptunghiDoc();
10) DECLARE_DYNCREATE(CDesenareDreptunghiDoc)
11)
12) // Attributes
13) public:
14)
15) // Operations
16) public:
17) std::vector<CDreptunghi> toate_dreptunghiurile;
18) // Overrides
125
Laborator C++
Pasul 4: n acest pas vom introduce n clasa reprezentare codul surs necesar desenrii unui dreptunghi i
memorrii acestuia n vectorul toate_dreptunghiurile.
Pentru nceput vom avea nevoie de dou variabile de tipul CPoint pe care le vom numi punct_initial_apasat i
punct_tinut_apasat. Cu ajutorul acestora vom ti pentru fiecare dreptunghi desenat care este punctul unde s-a
apsat pe butonul stng al mouse-ului i respectiv unde a fost eliberat ultima dat butonul stng. Pentru a ti unde
s-a apsat butonil stng al mouse-ului vom trata mesajul WM_LBUTTONDOWN. Pentru aceasta pe numele
clasei reprezentare efectuai un clic-dreapta i selectai opiunea Add Windows Message Handler(vezi
imaginea de mai jos).
Selectai apoi opiunea WM_LBUTTONDOWN dup care efectuai un clic pe butonul Add and Edit.(vezi
imaginea urmtoare).
126
Laborator C++
Astfel n linia a patra introducem n punct_initial_apasat poziia unde s-a apasat butonul stng al mouse-ului.
Analog tratai mesajele WM_MOUSEMOVE i WM_LBUTTONUP.
Funcia OnMouseMove() va desena dreptunghiul ce are vrfurile opuse: punctul unde s-a apsat butonul stng
al mouse-ului i punctul curent obinut din micarea mouse-ului (butonul stng rmnnd n continuare apsat).
Pentru a detemina dac butonul stng este apsat trebuie verificat parametrul nFlags. Acest parametru poate fi
orice combinaie a urmtoarelor valori:
MK_CONTROL setat dac este apsat tasta Ctrl.
MK_LBUTTON setat dac este apsat butonul stng al mouse-ului
MK_MBUTTON setat dac este apsat butonul din mijloc al mouse-ului
MK_RBUTTON setat dac este apsat butonul drept al mouse-ului
MK_SHIFT setat dac este apsat tasta SHIFT
Scriei liniile de cod de mai jos pentru funciile de tratare a mesajelor WM_MOUSEMOVE i
WM_LBUTTONUP.
127
Laborator C++
5) pdc=GetDC();
6) if(nFlags==MK_LBUTTON)
7) {
8) //sterge ultimul dreptunghi desenat
9) InvalidateRect(CRect(punct_initial_apasat,punct_tinut_apasat));
10)
11) pdc->Rectangle(CRect(punct_initial_apasat, point));
12) punct_tinut_apasat=point;
13) }
14) CView::OnMouseMove(nFlags, point);
15) }
16)
17) void CDesenareDreptunghiView::OnLButtonUp(UINT nFlags, CPoint point)
18) {
19) // TODO: Add your message handler code here and/or call default
20) CDesenareDreptunghiDoc* pDoc = GetDocument();
21) ASSERT_VALID(pDoc);
22) pDoc->toate_dreptunghiurile.push_back(CDreptunghi(punct_initial_apasat,point));
23) Invalidate();
24) CView::OnLButtonUp(nFlags, point);
24) }
Pasul 5: Vom desena toate dreptunghiurile din vectorul toate_dreptunghiurile folosind grosimea liniei i
culorile (pentru umplere respectiv pentru culoarea liniei) cu valori implicite. Pentru aceasta declarai nc dou
variabile membru culoare_penita, culoare_brush (de tip COLORREF) i grosime_linie (de tipul int) dup
care n constructorul clasei reprezentare le vom iniializa:
1) CDesenareDreptunghiView::CDesenareDreptunghiView()
2) {
3) // TODO: add construction code here
4) culoare_penita=RGB(0,0,0);
5) culoare_brush=RGB(0, 0, 255);
6) grosime_linie=3;
7) }
Pentru desenarea tuturor dreptunghiurilor de vector introducei n funcia OnDraw() urmtoarele linii de cod:
128
Laborator C++
12)
13) for(int i=0; i<pDoc->toate_dreptunghiurile.size();i++)
14) pDC->Rectangle(pDoc->toate_dreptunghiurile[i].Rect());
15)
16) pDC->SelectObject(pOldBrush);
17) pDC->SelectObject(pOldPen);
18) }
n liniile 6-11 facem ca penia i pensula s aib foloseasc culorile din variabilele membru culoare_brush,
culoare_penita i grosime_linie.
Pasul 6: n acest pas vom crea o opiune de meniu pentru schimbarea culorilor i a grosimei liniei de desenare a
dreptunghiurilor. Pentru aceasta vom crea o caset de dialog creia i vom asocia apoi o clas.
Creai o caset de dialog asemntoare celei din imaginea de mai jos:
Schimbai numele casetei de dialog i ID-ul acestuia astfel: Setari culoare si grosime i respectiv
IDD_SETARI.
Apsai un clic-dreapta pe primul buton i selectai opiunea Properties. Schimbai numele ID i Caption ca n
imaginea de mai jos.
129
Laborator C++
n cazul celor trei butoane de opiune setai numele identificatorului i al celui de la Caption ca n imaginile de
mai jos:
La primul (li doar la primul) selectai opiunea Group.
n cazul celui de-al doilea buton asigurai-v c nu este selectat opiunea Group.
Acum, pentru a crea o nou clas (pentru caseta de dialog pe care ai creat-o) apsai un clic oriunde pe suprafaa
casetei de dialog i apsai Ctrl+W. Se va deschide urmtoarea caset de dialog:
130
Laborator C++
Apsai pe butonul OK dup care se va deschide caseta de dialog New Class. Introducei numele CDlgSetari.
Apsai apoi pe OK pentru a nchide aceast caset de dialog i apoi nc o dat pe OK pentru a nchide
ClassWizard.
Aici introducei dou noi variabile membre ale acestei noi clase: clr_linie, clr_umplere (ambele de tipul
COLORREF) ca mai jos:
131
Laborator C++
1) void CDlgSetari::OnCuloareLinie()
2) {
3) // TODO: Add your control notification handler code here
4) CColorDialog dlg;
5) int ret=dlg.DoModal();
6) if(ret==IDOK)
7) {
8) clr_linie=dlg.GetColor();
9) }
10) }
Aceast funcie seteaz valorarea lui clr_linie la noua valoare aleas (doar n cazul apsrii butonului OK a
casetei de dialog dlg). n mod analog se efectueaz n cazul celui de-al doilea buton. Acceptai numele implicit
OnCuloareUmplere dup care apsai pe butonul OK i introducei liniile de cod urmtoare:
1) void CDlgSetari::OnCuloareUmplere()
2) {
3) // TODO: Add your control notification handler code here
4) CColorDialog dlg;
5) int ret=dlg.DoModal();
6) if(ret==IDOK)
7) {
8) clr_umplere=dlg.GetColor();
9) }
10) }
Pentru grosimea liniei va trebui s mapm o variabil peste primul buton de opiune. Pentru aceasta deschidei
Class Wizard (apasai pentru aceasta Ctrl+W). Noi am numit aceast variabil m_grosime_aleasa (de tipul
int). Acum Class Wizard trebuie s arate ca n imaginea de mai jos:
132
Laborator C++
Pasul 7: Pn acum am determinat ce anume s fac caseta de dialog. Mai trebuie doar s apelm, printr-o
opiune de meniu aceast fereastr i o determinm s interacioneze cu clasa reprezentare. Inserai o nou
opiune de meniu. Noi am denumit aceast nou opiune de meniu Alege setarile (am creat iniial un nou
submeniu numit Setari). (vezi imaginea de mai jos).
Pentru a scrie codul surs necesar acestei noi opiuni de meniu deschidei Class Wizard, selectai ca numele
clasei s fie clasa reprezentare, identificatorul obiectului s fie ALEGE_SETARI, selectai mesajul
COMMAND i apsai bulonul Add Function. Acceptai numele implicit de funcie dup care apsai pe
butonul OK pentru a nchide aceast caset de dialog i apoi apsai pe butonul Edit Code.
133
Laborator C++
1) #include"DlgSetari.h"
2) void CDesenareDreptunghiuriView::OnSetari()
3) {
4) // TODO: Add your command handler code here
5) CDlgSetari dlg;
6) //dam valori implicite variabilelor
7) dlg.clr_linie=culoare_penita;
8) dlg.clr_umplere=culoare_brush;
9) dlg.m_grosime_aleasa=grosime_linie;
10)
11) int ret=dlg.DoModal();
12) //daca vom apasa butonul OK
13) if(ret==IDOK)
14) {
15) culoare_penita=dlg.clr_linie;
16) culoare_brush=dlg.clr_umplere;
17) grosime_linie=dlg.m_grosime_aleasa;
18) }
19) Invalidate();
20) }
n liniile 7-9 dm valori implicite variabilelor casetei de dialog dup care, n linia 11 afism caseta de dialog. n
cazul n care se apas pe butonul OK se vor actualiza variabilele clasei reprezentare cu valorile noi alese dup
care reafim toat zona client pentru a se vedea eventualele schimbri ale setrilor culorilor i/sau grosimii
liniei.
134
Laborator C++
Laborator 21
Scriei un program MFC care s permit introducerea unor date despre studeni: nume, prenume,
vrsta, este sau nu bursier, materiile studiate precum i specializarea la care studiaz. Numele i prenumele se
vor introduce printr-o caseta de editare (EditBox), vrsta, care poate lua valori ntre 18 i 100, se va modifica cu
ajutorul unui Spiner. Cu ajutorul unei casete de validare (CheckBox) se va determina dac studentul este sau nu
bursier. De asemenea se va putea selecta dintr-o list (ListBox) cu toate materiile disponibile acele materii pe
care studentul le-a studiat pn n prezent iar cu ajutorul unui buton (Button) le vom introduce pe acestea din
urm ntr-o alt list. n final vom putea alege, dintr-o caset combinat (ComboBox), specializarea studentului.
Imaginea urmtoare ne reprezint caseta de dialog (pe care o vom crea) cu ajutorul creia vom introduce datele:
Rezolvare:
Pasul 1: Creai o nou aplicaie MFC de tip SDI pe care s o denumii DateStudenti i a crei clas de baz s
fie CScrollView. La acest pas vom crea caseta de dialog (pe care o vom utiliza pentru introducere datelor) i
vom crea pentru aceasta o nou clas.
Mai nti inserai o nou caset de dialog. Efectuai un clic-dreapta ce suprafaa acesteia i selectai opiunea
Properties. Se va deschide caseta de dialog Dialog Properties. Introducei IDD_STUDENT n dreapta
etichetei ID i Fisa individuala a studentului n dreapta etichetei Caption (vezi imaginea de mai jos).
135
Laborator C++
Creai acum o nou clas care s corespund acestei casete de dialog. Pentru aceasta efectuai un clic pe
suprafaa acesteia i apsai Ctrl+W pentru a deschide ClassWizard. Se va deschide caseta de dialog Adding a
Class care are selectat implicit butonul radio Create a new class. Efectuai acum un clic pe butonul OK pentru a
crea o nou clas. Se va deschide acum automat caseta de dialog New Class. Introducei un nume pentru aceast
nou clas, de exemplu CdlgStudent dup care apsai de dou ori pe butonul OK pentru a nchide aceast
caset de dialog i caseta de dialog MFC ClassWizard.
Acum redimensionai caseta de dialog pentru a fi suficient de mare. Vom aduga elementele necesare
pentru ca aceast caset de dialog s arate ca n imaginea ce se afl imediat dup enunul acestui laborator (de
aceea, ghidai-v dup acea imagine pentru poziionarea lor). Adugai urmtoarele controale:
-ase etichete statice (static text) care s indice Nume:, Prenume:, Varsta:, Lista materiilor disponibile:,
Lista materiilor studiate: i respectiv Specializarea:.
-trei casete de editare (edit box) cte una n dreapta etichetelor Nume:, Prenume:, respectiv Varsta:, a cror
ID s fie respectiv IDC_NUME, IDC_PRENUME i IDC_INT_VARSTA
-un control de modificare incremental (Spin) n dreapta casetei de editare care se afl n dreapta etichetei
Varsta:. Deschidei caseta de dialog Spin Properties (pentru aceasta efectuai un clic-dreapta pe suprafaa
acestuia i selectai opiunea Properties). Introducei IDC_VARSTA n dreapta etichete ID. Selectai opiunile
Auto buddy i Set buddy integer, apoi opiunea Right din lista Alignment.
-o caset de validare (Check Box) a crui ID s fie IDC_BURSIER, iar n dreapta etichetei Caption
introducei Este bursier:. Selectai apoi opiunea Right aligned text pentru ca textul s apar scris n stnga
dreptunghiului pentru validare.
-dou casete cu list (List Box), cte una sub fiecare din etichetele Lista materiilor disponibile: i Lista
materiilor studiate a cror identificatori s fie IDC_LIST1i IDC_LIST2.
-dou butoane (Button) cu ajutorul crora vom putea modifica cele dou liste traversnd cte un element
dintr-o list n cealalt. Noi le-am etichetat cu -------- > respectiv cu < ----------- .
-ultimul element adugat va fi o caset combinat (Combo Box) cu ajutorul creia vom selecta specializarea
studentului. Schimbai ID-ul su cu IDC_SPECIALIZAREA i selectai opiunea Drop List al listei de
opiuni Type din pagina Styles. Pentru a popula aceast caset combinat procedai astfel: selectai pagina
Data i introducei cte un element dup care, pentru a scrie pe rnd nou, apsai Ctrl+W. Introducei astfel
elementele urmtoare: Matematica-Informatica, Matematica-Fizica, Fizica-Chimie, Informatica-colegiu,
Fizica, Chimie, Chimie-Biologie i Biologie.
Pentru a putea lucra cu aceast caset de dialog vom mapa cteva controale i variabile aa cum se arat n
imaginea de mai jos:
136
Laborator C++
Mai adugai dou variabile membru, selecia1 i selecia2 de tip int acestei clase (CDlgStudent) . Acestea vor
reprezenta indexul elementului curent selectat n fiecare din cele dou casete cu list.
Pasul 2: La acest pas vom popula prima lista cu materiile de studiu, vom stabili vrsta implicit care s fie
selectat la momentul apariiei caseta de dialog. Pentru a putea iniializa aceast caset de dialog vom trata
mesajul Windows numit OnInitDialog. Pentru aceasta efectuai un clic dreapta pe numele clasei asociate casetei
de dialog CDlgStudent i selectai opiunea Add Windows Message Handler . Se va deschide astfel caseta
de dialog New Windows Message and Event Handlers for class CDlgStudent. Selectai WN_INITDIALOG
dup care apsai pe butonul Add and Edit.
Aici introducei liniile de cod de mai jos pentru a iniializa caseta de dialog.
1) BOOL CDlgStudent::OnInitDialog()
2) {
3) CDialog::OnInitDialog();
4) // TODO: Add extra initialization here
5) m_ctrl_varsta.SetRange(18,100);
6) m_ctrl_varsta.SetPos(18);
7) m_ctrl_lista_disponibile.ResetContent();
8) m_ctrl_lista_studiate.ResetContent();
9) m_ctrl_lista_disponibile.AddString("materia01");
10) m_ctrl_lista_disponibile.AddString("materia02");
11) m_ctrl_lista_disponibile.AddString("materia03");
12) m_ctrl_lista_disponibile.AddString("materia04");
13) m_ctrl_lista_disponibile.AddString("materia05");
14) m_ctrl_lista_disponibile.AddString("materia06");
15) m_ctrl_lista_disponibile.AddString("materia07");
16) m_ctrl_lista_disponibile.AddString("materia08");
17) m_ctrl_lista_disponibile.AddString("materia09");
18) m_ctrl_lista_disponibile.AddString("materia10");
137
Laborator C++
19) m_ctrl_lista_disponibile.AddString("materia11");
20) m_ctrl_lista_disponibile.AddString("materia12");
21) m_ctrl_lista_disponibile.AddString("materia13");
22) m_ctrl_lista_disponibile.AddString("materia14");
23) m_ctrl_lista_disponibile.AddString("materia15");
24) m_ctrl_lista_disponibile.AddString("materia16");
25) selectia1=-1;
26) selectia2=-1;
27) return TRUE; // return TRUE unless you set the focus to a control
28) // EXCEPTION: OCX Property Pages should return FALSE
29) }
n linia 5) stabilim limitele pentru controlul de modificare incremental m_CtrlVarsta iar n linia 6) stabilim
poziia sa iniial (implicit).
Un control de modificare incremental are urmtoarele funcii membre:
n linile 7), 8) tergem orice toate elementele din cele dou liste cu materii., iar n liniile 9) - 24) populm prima
list cu 16 elemente. O parte din funciile membre ale unui control de tip list combinat este scris mai jos:
138
Laborator C++
1) void CDlgStudent::OnSelchangeList1()
2) {
3) // TODO: Add your control notification handler code here
4) //GetSel returneaza 0 daca nu este selectat, LB_ERR daca apare eroare, un nr pozitiv daca e selectat
5) for(int i=0;i<m_ctrl_lista_disponibile.GetCount();i++)
6) if(m_ctrl_lista_disponibile.GetSel(i)!=0 && m_ctrl_lista_disponibile.GetSel(i)!=LB_ERR)
7) selectia1=i;
8) Invalidate();
9) }
Acum apsai un dublu-clic pe butonul -------- > pentru a crea funcia corespunztoare acestuia (i care ca
rspunde mesajului BN_CLICKED). Acceptai numele implicit OnButton1 (sau putei s-l schimbai cu altul
mai convenabil dac dorii) i introducei liniile de cod de mai jos. Aceast funcie va face ca, n cazul n care
este selectat un element din prima list (adic selecia1 reprezint un numr de indice valid pentru numrul de
ordine al vreunui element din prima list), acesta s fie inserat n lista a doua.
1) void CDlgStudent::OnButton1()
2) {
3) // TODO: Add your control notification handler code here
4) CString str;
5) if(selectia1>=0)
6) {
7) int lungime_cuvant;
8) lungime_cuvant = m_ctrl_lista_disponibile.GetTextLen(selectia1);
9) m_ctrl_lista_disponibile.GetText(selectia1,str.GetBuffer(lungime_cuvant));
10) m_ctrl_lista_studiate.AddString(str);
11) m_ctrl_lista_disponibile.DeleteString(selectia1);
12) selectia1=-1;
13) str.ReleaseBuffer();
14) }
15) //salvam in materiile_alese ce avem in lista a doua
16) int n=m_ctrl_lista_studiate.GetCount();
17) for(int i=0;i<n;i++)
18) {
139
Laborator C++
n linile 7-11 inserm elementul selectat din prima list n lista a doua dup care l tergem din prima list. n
linia 12) reiniializm variabila selectia1 cu valoarea 1. n liniile 16-21 salvm aceste elemente n vectorul
materiile_alese. Liniile 22-23 ne asigur c restul elementelor din vector sunt nule.
Absolut analog vom proceda pentru cellalt buton i pentru cea de-a doua list. Deosebiri sunt mici n ceea ce
privete codul surs:
1) void CDlgStudent::OnSelchangeList2()
2) {
3) // TODO: Add your control notification handler code here
4) for(int i=0;i<m_ctrl_lista_studiate.GetCount();i++)
5) if(m_ctrl_lista_studiate.GetSel(i)!=0 && m_ctrl_lista_studiate.GetSel(i)!=LB_ERR)
6) selectia2=i;
7) Invalidate();
8) }
9)
10) void CDlgStudent::OnButton2()
11) {
12) // TODO: Add your control notification handler code here
13) CString str;
14) if(selectia2>=0)
15) {
16) int lungime_cuvant;
17) lungime_cuvant = m_ctrl_lista_studiate.GetTextLen(selectia2);
18) m_ctrl_lista_studiate.GetText(selectia2,str.GetBuffer(lungime_cuvant));
19) m_ctrl_lista_disponibile.AddString(str);
21) m_ctrl_lista_studiate.DeleteString(selectia2);
22) selectia2=-1;
23) str.ReleaseBuffer();
24) }
25) //salvam in materiile_alese ce avem in lista2
26) int n=m_ctrl_lista_studiate.GetCount();
27) for(int i=0;i<n;i++)
28) {
29) int lungime_cuvant=m_ctrl_lista_studiate.GetTextLen(i);
30) m_ctrl_lista_studiate.GetText(i, materiile_alese[i].GetBuffer(lungime_cuvant));
31) }
32) for(i=n;i<16;i++)
33) materiile_alese[i]="";
34) Invalidate();
35) }
Pasul 4: Vom crea acum o nou clas (generic), CFisaIndividualaStudent, clas care va avea urmtoarele
variabile membre: Nume, Prenume, Specializarea, MateriiStudiate (ambele de tipul CString), Varsta (de
tipul int) i Bursier (de tipul BOOL).
Pentru aceast clas vom crea urmtorul constructor:
140
Laborator C++
1) class CFisaIndividualaStudent
2) {
3) public:
4) CFisaIndividualaStudent(CString nume, CString prenume, int varsta,
5) CString materiistudiate, BOOL bursier, CString specializarea);
6) virtual ~CFisaIndividualaStudent();
7) public:
8) CString Nume, Prenume, MateriiStudiate, Specializarea;
9) int Varsta;
10) BOOL Bursier;
11) };
Astfel n linia 12) am declarat o variabil membru pentru clasa document numit lista_studenti i n care vom
stoca mai multe obiect de tip CFisaIndividualaStudent. (motiv pentru care am i scris comanda din linia 2) )
Pasul 5: Creai un nou submeniu numit Student i o opiune de meniu numit Adaugare dup care apsai un
clic dreapta i selectai opiunea Properties. Introducei identificatorul ID_ADAUGARE apoi apsati enter
pentru a valida. Deschidei MFC ClassWizard. Selectai numele clasei CDateStudentiDoc, numele
identificatorului selectat s fie ID_ADAUGARE, electai mesajul COMMAND dup care selectai butonul
Add Function . Acceptai numele implicit OnAdaugare apsnd pe butonul OK dup care apsai pe butonul
Edit Code. Apoi completai cu liniile de cod de mai jos:
1) #include "DlgStudent.h"
2) void CDateStudentiDoc::OnAdaugare()
3) {
4) // TODO: Add your command handler code here
5) CDlgStudent dlg;
6) int ret=dlg.DoModal();
7) if(ret==IDOK)
8) {
9) CString materii="", str1;
10) for(int i=0;i<16;i++)
141
Laborator C++
11) if(dlg.materiile_alese[i]!="")
12) {
13) str1.Format("%s, ",dlg.materiile_alese[i]);
14) materii=materii+str1;
15) }
16) CFisaIndividualaStudent student(dlg.m_nume, dlg.m_prenume, dlg.m_varsta,
17) materii ,dlg.m_este_bursier, dlg. m_specializarea);
18) lista_studenti.push_back(student);
19) }
20) UpdateAllViews(NULL);
21) }
n linia 6) se va deschide caseta de dialog dlg. n cazul apsrii pe butonul OK (deci a validrii opiunilor
fcute) introducem n irul materii numele tuturor materiilor alese (adic cele care vor fi n lista a doua) dup
care vom construi un obiect de tipul CFisaIndividualaStudent pe care l vom aduga n vectorul lista_studenti.
Obs. Variabila m_varsta este variabila de tipul int pe care am mapat-o peste caseta de editare unde se introduce
varsta. Am mapat aceast variabil deoarece este mult mai uor de folosit. Deschidei deci caseta de dialog
MFC ClassWizard i n pagina Member Variables selectai clasa CDlgStudent. Acum adugai o variabil de
tipul int peste caseta de editare al crui identificator IDC_INT_VARSTA. Astfel de fiecare dat cnd vei dori
s aflai care este valoarea nscris n aceast caset de editare va trebui doar s consultai aceast variabil de
tipul int.
Pasul 6: n funcia OnDraw() a clasei reprezentare introducei urmtoarele linii de cod:
n liniile 11)-25) afim fiecare student din list mpreun cu datele sale personale.
142
Laborator C++
Laborator 22
Problema:
Scriei un program MFC de tip SDI care permite utilizatorului s deseneze cercuri si ptrate in zona client a
ferestrei prin apsarea butonului stng al mouse-lui. Instrumentul de desenare se selecteaza dintr-o caseta de
dialog n care sunt dou butoane radio (cerc respectiv ptrat). Grosimea i culoarea liniilor se stabilete fiecare
cu o caseta de dialog personalizat. Datele se vor salva pe disc.
Observaii:
/* Crearea unei funcii mesaj rspuns la mesajul WM _LBUTTONUP, care deseneaz un patrat.
Crearea unei funcii mesaj rspuns la mesajul WM _MOUSEMOVE, care deseneaz un cerc la fiecare punct prin
care trece mouse-ul. Atenie !!! funciile mesaj rspuns vor face parte din clasa View.
In aceste funcii se va crea un context de dispozitiv cu CClientDC dc(this). (Codul pentru desenare nu va aprea
n OnDraw ci n functia care trateaz mesajele)
Adugarea unor variabile membre n clasa vizualizare. Ultimul punct n care s-a dat click, culoare folosit pt.
desenare si unealta care se folosete (cerc, patrat).
Mutarea codului pt. desenare n funcia OnDraw(). Apelarea funciei Invalidate() din funciile care trebuie s
modifice vizualizarea.
Adugarea unei opiuni de meniu pt. Stabilirea culorii de desenare care se alege folosind clasa CColorDialog.
Funcia doModal().
Adugarea unei opiuni de meniu pt. Stabilirea uneltei de desenare. Uneltele disponibile se vor defini ntr-o
enumerare enum Tool {Cerc, Patrat}.
Editarea constructorului clasei vizualizare pt. a iniializa culoarea curent, unealta i punctul curent.
*/
Rezolvare:
Se creaz un proiect de tip SDI cu numele Desenare, dup care se adaug o clas de tip generic cu numele
Forma de tip generic care va fi clas de baz pentru clasele CCerc i CPtrat pe care le vom implemeta pe
urm.
Dar s revenim la clasa Forme dup ce se va implemeta i se va aduga un constructor care va arta astfel:
Forme::Forme(CPoint c, unsigned d, COLORREF u, COLORREF l, UINT g)
{
centru=c;
x=d;
fillcolor=u;
linecolor=l;
grosime=g;
}
variabilele care apar vor fi declarate tot n clasa Forme
UINT grosime;
COLORREF fillcolor;
COLORREF linecolor;
unsigned x;
CPoint centru;
De asemenea clasei Forme i se adaug i o funcie membru virtual pur cu numele Draw, adic n declaraia
clasei se ntroduce urmtorul cod n seciunea public:
virtual void Draw(CDC *) =0;
Clasele CCerc i CPatrat vor fi implementate la fel.
Se apas click dreapta pe Desenare Clasess din ClassView se alege New Class i se scrie numele clasei, tipul
acesteia n cazul nostru Generic Class i clasa din care se va deriva n cazul nostru Forme
143
Laborator C++
La fel se procedeaz i n cazul clasei CPatrat doar funcia Draw va fi puin schimbat n sensul c n loc de
Ellipse se va scrie Rectangle.
144
Laborator C++
Urmtorul pas n rezolvarea problemei va fi adugarea unei funcii care trateaz apsarea butonul stng al mouse-
ului adic atunci cnd vom apsa butonul stng se va desena n zona client un cerc sau n ptrat n funcie de
opiunea aleas. Iniial se va desena cercuri, pentru a realiza acest lucru se va introduce urmtorul cod n
constructorul clasei CDesenareView
raza=30;
formacurenta=0;
int formacurenta;
UINT raza;
forma curent se va folosi pentru a seta forma patrat sau cerc, iar raza va fi raza cercului respectiv a ptratului.
Se deschide ClassWizard din meniul View i se adaug funcia WM_LBUTTONDOWN apsnd butonul Add
Function dup care Edit Code pentru a aduga cod n noua funcie creat.
Dup apsarea butonului Edit Code funcia va fi modificat ca s arate astfel:
145
Laborator C++
switch (curentshack)
{
case 0: r=new CCerc(point,raza,0,0,1);break;
case 1: r=new CPatrat(point,raza,0,0,1);break;
}
pDoc->forme.push_back(r);
Invalidate();
CScrollView::OnLButtonDown(nFlags, point);
}
Pentru a se realiza serializarea se introduce urmtorul cod n declaraia clasei CdesenareDoc n seciunea public
#include <vector>
#include "Forme.h"
Pentru a se schimba forma cu care se deseneaz adic cercuri i ptrate se introduce o opiune de meniu cu
numele Imagine i un submeniu cu numele Change. Acest lucru se realizeaz apsnd un click dreapta pe
opiunea ResourceView i se deschide directorul Menu i n cadrul lui opiunea IDR_MAINFRAME
146
Laborator C++
dup care se va aduga meniu dorit apsndu-se un dublu click n locul destinat scrieri de noi meniuri dup
meniul Help i pe urm se va muta n faa meniului Help prin apsarea butonului stng al mouse-ului i
drenarea(adic se ine apsat n timpul deplasrii la stnga) acestuia n stnga. Dup realizarea meniului se apas
dublu click pe opiunea Change i ne va aprea urmtoarea fereastr
n care putem observa ID-ul opiunii Change n cazul nostru ID_ IMAGINE_CHANGE.
n ClassWizard se va aduga funcia COMMAND cu ajutorul opiunii Add Function i va fi afiat
urmtoarea fereastr
n care se va putea schimba numele funciei care trateaz apsarea acestui meniu adic Change.
Dup apsarea butonului OK se va introduce n aceast funcie urmtorul cod:
if (formacurenta==1) formacurenta=0;
else formacurenta=1;
n care se schimb efectiv forma care se va desena n cadrul zonei client a ecranului.
Dup compilarea i execuia programului vom putea desena cercuri i ptrate cu ajutorul mouse-ului.
147
Laborator C++
148
Laborator C++
Laborator 23
Scrieti un program MFC pentru testarea functiei Message Box. Aplicatie de tip SDI. Se va crea o casuta de
dialog personalizata cu urmatoarea forma:
La apasarea butonului OK se va afisa un MessageBox care va avea prop. date de caseta de dialog de mai sus.
Dupa apasarea unui buton din Message Box va aparea un alt Message Box in care va aparea icoana Information
butonul OK iar textul va indica butonul apasat.
149
Laborator C++
Laborator 24
Scrieti un program MFC care cere utilizatorului introducerea unor date despre persoane nume, prenume, varsta
sau data nasteri, locul de munca, starea civila. Sa se introduca intr-o caseta de dialog. Datele care vor fi introduse
intr-o colectie numai daca sunt validate. Exemplu: Numele sa fie fara spatiu. Daca datele nu sunt vald atunci se
va afisa un MessageBox prin care utilizatorul va fi informat ca a gresit ceva. Sa se incrementeze serializarea
datelor (incarcarea din fisier).
150
Laborator C++
Laborator 25
Scrieti un program MFC care permite introducerea unor siruri de caractere prin intermediul unei casete de dialog
personalizata, siruri care vor fi afisate in zona client a ferestrei unul sub altul. Primul sir care se afiseaza este un
antet care se va putea modifica oricand cu ajutorul unei alte casete de dialog personalizata. Sirurile vor fi salvate
intr-o colectie de strianguri. CStringArray. Se va slava starea obiectului pe disc in fisier. Se va putea si incarca
de pe disc acel obiect.
151
Laborator C++
Laborator 26
Scrieti un program care sa permita desenarea in partea client cercuri prin apasarea butonului stang al mousului.
Se vor putea parametriza prin casete de dialog: raza cercului, culoarea cercului, culoarea de umplere. Se va folosi
o colectie de cercuri care se va putea salva pe si de pe disc.
152
Laborator C++
Laborator 27
Lucrul direct cu fisiere de pe disc.
Problem:
Scriei un program care permite deschiderea unui fiier text de pe disc prin intermediul unei casete de dialog File
-> Open. Se folosete CFlieDialog. i afiarea coninutului fiierului in zona client a ferestrei. Pentru lucru cu
fiiere se folosete CFile (nume fiier, mod de deschidere, etc).
Rezolvare:
Se creaz un proiect de tip SDI cu numele Fiiere. Clasa de baz a acestui proiect va fi CScrollView, deci la
pasul 6 al aplicaiei se va nlocui n caseta Base Class clasa CView cu clasa CScrollView.
n clasa CFisiereDoc se declar o variabil de tip CStringArray cu numele linii:
CStringArray linii;
Aceast variabil se va folosi pentru a citi linii din fiierul ce urmeaz a fi descris.
Funcia OnDraw a clasei CFisiereView se va modifica astfel nct s arate astfel:
n linia 6 se declar o variabil de tip ntreg cu numele height i se iniializeaz cu valoarea 20 care se va folosi
pentru a seta nlimea textului afia..
Se deschide ResourseView, directorul Toolbar i pe urm IDR_MAINFRAME i se adaug un buton astfel:
153
Laborator C++
Dup care se va apsa un dublu click pe butonul nou creat i se va modifica ID-ul butonului astfel:
La urmtorul pas se va deschide ClassWizard i se va alege pagina Message Maps, Object ID-ul ales va fi
ID_FOpen adic cel creat de noi pentru noul butonul. n fereastra Messages va fi aleas opiunea COMMAND
154
Laborator C++
i pe urm va fi apsat butonul Add Function i se va aduga o funcie cu numele OnFOpen astfel:
1 void CFisiereView::OnFOpen()
2 {
3 // TODO: Add your command handler code here
4 CFileDialog dlg(TRUE, "txt", "Untitled");
5 int ret = dlg.DoModal();
6 ifstream file;
7 char buffer[501];
8 CString temp;
9 CFisiereDoc* pDoc = GetDocument();
10 ASSERT_VALID(pDoc);
11 if (ret == IDOK)
12 {
13 file.open(dlg.GetPathName());
14 if (!file) MessageBox("Nu am reusit sa deschid fisierul");
15 else
155
Laborator C++
16 {
17 pDoc->linii.RemoveAll();
18 while(! file.eof())
19 {
20 file .getline(buffer, 500);
21 if (buffer[0] != '\0')
22 {
23 temp.Format("%s", buffer);
24 pDoc->linii.Add(temp);
25 }
26 Invalidate();
27 }
28 }
29 }
n fisierul FisiereView.cpp se va aduga la nceputul fisierul dup seciunea unde se include fiierele urmtoarea
linie:
#inlcude <fstream.h>
156
Laborator C++
Laborator 28
L26 Lucru cu bitmap.
L28 Lucru cu pagini de proprieti.
157