joi, 23 aprilie 2020

Qt - Saptamana a 10-a



Qt - Saptamana a 10-a

Widget-uri grafice, conform capitolului al 9-lea din manualul de buzunar de la editura EIKON. Il puteti folosi si pe cel de la editura Alma Mater, editia mai veche.

Ce ne propunem sa facem astazi:

1) Am sa va trimit pe e-mail capitolul al 9-lea din carte. Verificati-va cutiile postale.
Ok, verificati-va cutiile postale si deschideti capitolul din carte.
2) Am sa comentez ca de obicei pe scurt paragrafele din care este format capitolul.
3) Facem implementarea.

Deschideti manualul in format de buzunar la capitolyul al 9-lea, pg 125, la formatul mic. Cititi primul paragraf.

Comentariu: Data trecuta am facut o mica aplicatie, in care un panou de control, LCDRange si un widget inca nedesenat, dar "printat" in mod grafic comunicau prin semnale.Nu C7, era C8.

Daca va amintiti cum functiona, unii au vazut acuma: semnalul dat de cursorul din stanga, din LCDRange, era transmis atat afisajului LCD, cat si "bifurcat", scos inafara obiectului compus (de clasa LCDRange) si putea fi propagat la alte obiecte. In C7 il propagasem de-a lungul unui sir de obiecte.

Urma sa dezvoltam aplicatia si sa inlocuim acel mesaj Angle=24 de mai sus cu un widget adevarat in forma de tunuletz, care chiar sa fie desenat ca un tun, si sa se miste conform comenzii.Unghiul pe care il programam pe afisaj, sa fie chiar unghiul la care se rididca tunul.

Deocamdata avem implementata clasa tunului:


Dar partea grafica nu este implementata!
Comunicarea insa intre tun si afisaj a functionat corect, insa.
Acest lucru ne ajuta, fiindca daca vom adauga desenarea graficii, si totusi tunuletzul nu se va misca corect, noi stim deja ca semnalul cu valoarea unghiului ii ajunge cu bine.

Continuati sa cititi pagina 125, 126, 127.

Ati facut vreodata geometrie analitica ? Dar OpenGL ? (Acum stiu ca ati facut OpenGL, deci voi fi scurt.)

Daca la geometrie analitica avem un reper de forma:

/|\ Y
 |
 |
 |
 |
 |
 |
 |  (0,0)                                          
-|---------------------------------------------->
O                                                  X

La Qt avem un reper invers:
 O
-|---------------------------------------------->
 |  (0,0)                                           X
 |
 |
 |
 |
 |
 |
\|/ Y

Mai mult, la geometrie avem un reper fix.
Pe cand la Qt, exact ca la  OpenGL reperul se poate modifica, se poate supune la TRANSFORMARIGEOMETRICE:
- translatii
- rotatii
- scalari (erau in OpenGL)
iar noi desenam tot timpul in reperul modificat.

Cum vom desena un sfert de cerc (tunul fara teava) undeva pe baza ferestrei ?
Ne ducem cu reperul undeva la baza:

 O
-|---------------------------------------------->
 |  (0,0)                                           X
 |
\|/ Y

Reperul, care era in coltul din stanga sus al ferestrei, unde se intalneste bara gri inchis cu soatiul gri deschis, in coltulk din stanga sus, va fi mutat pina in locul indicat de sageata, pe verticala lateralei drepte a butonului Quit.

Aici va fi noua origine a reperului nostru !

Aici vom desena:
- sfertul de cerc al tunuletului.
- Apoi vom roti reperul in sens antiorar:
O
\
 \
  \ Y
si axa OY va fi ... stramba. Iar in noul reper rotit vom desena un QRectangle, adica un dreptunghi.

In final se va obtine ceva cam ca la pagina: 127.


Imaginea a ceea ce vom obtine.


Dupa pauza incepem direct implementarea. Am sa va rog sa faceti o copie a dosarului qt-nonvisual-C8 si sa il numiti qt-nonvisual-C9, modificand corespunzator fiiserul .pro. Ceea ce voi face si eu. Astfel veti avea in dosarul cu proiecte, ambele aplicatii.
In noul dosar redenumiti fisierele .pro cu C9:
La mine sunt numite asa:


Revenim la lucru:

Dati click pe fisierul .pro si deschideti-l : Open With Qt Creator. Acum hai sa actualizam si numele aplicatiei, din fisierul .pro:


Acum putem sa ne ocupam de adaosurile de facut la codul claselor .... la lucru !

Am adaugat noul cod al metodei de redesenare a tunuletului (cel cu albastru se va sterge) este vorba de metoda: paintEvent(QPaintEvent * ) a clasei Cannon:

Codul albastru este cel vechi, se va sterge si va fi inlocuit cu cel nou.


Gata, am sters codul vechi.

Si dupa ce il explicam, puteti compila aplicatia, ba nu, mai bine compilati-o ca sa vedem cum functioneaza (aka invatare prin descoperire).

Miscati cursorul ca sa vedeti efectul...
Cum  a fost realizat desenul gasiti la pagina 129 din materialul trimis pe e-mail, din capitolul al 9-lea.

Cum se deseneaza

Tot setul de comenzi grafice folosite în acest program se regăseste în metoda de tratare a evenimentului paintEvent (care răspunde la cererea de redesenare). Veți observa două părți, una care inițializează obiectele Qt pe care le folosim (acestea sunt QPainter – pictorul/zugravul, QBrush - pensula înmuiată în culoarea neagră și QPen - creionul pentru contururi, care a fost ales roșu deși există și alte culori).

void CannonField :: paintEvent(QPaintEvent *)
{
QPainter p;
QBrush brush(Qt::black);
QPen pen(Qt::red);

Urmează desenul propriuzis, făcut de domnul obiect QPainter, pictorul nostru. Acesta este cuprins între un apel al metodei begin() și un apel al metodei end(). Ultima se ocupă de finalizarea desenului care va fi afișat iar prima are rolul, printre altele, de a inițializa zona grafică și a încărca în calculatorul de transformări matriceale matricea unitate cea cu care se vor înmulți următoarele matrice ale transformărilor. Mai
trebuie să-i spunem pictorului cu ce pensulă și cu ce penel să lucreze.

p.begin(this);
p.setBrush(brush);
p.setPen(pen);

Acum reperul se mută în jos, la baza widget-ului. Metoda rect()
- numele vine de la „rectangle” a clasei QWidget - returnează un
obiect-dreptunghi QRect iar acesta poate fi întrebat la ce coordonată
are baza, apelând metoda bottom(). Studiați lista metodelor claselor
QWidget și QRect pentru a vedea ce semnificație are rezultatul.

p.translate(0,rect().bottom());

Aici ma puteti intreba cum le-a gasit: Le gasiti si dumneavoastra consultad in Help listele de metode ale claselor implicate. Aici Cannon era o clasa derivata din QWidget si are toate metodele acesteia.
Iar QRect - adica dreptunghiul, ei bine puneti cursorul pe numele QRect si apasati F1=help sau CTRL-F1 pe unele laptopuri. 

Urmează desenarea sfertului de disc al tunulețului. Știați că unghiurile sunt măsurate în șaisprezecimi de grad? În continuare, numărul 35 indică raza cercului. Observați cum este declarat dreptunghiul de dimensiune 70 x 70 centrat în noua origine, în care se va desena sfertul
de „placintă” - pardon, de disc. 0 și 90x16 sunt unghiul minim și cel
maxim al sectorului de cerc, al feliei de plăcintă, dacă doriți .

p.drawPie(QRect(-35,-35,70,70),0,90*16);

Fiindcă avem de ridicat țeava tunului, reperul se rotește antiorar, cu - ang grade!!

p.rotate(-ang);

Iar acum este momentul să desenăm țeava tunulețului, de formă
dreptunghiulară și plasată într-un reper deja rotit. Ea nu este plasată în
originea reperului ci este cu 35 de unități mai departe în direcția axei
OX, adică a axei tevii. Altfel n-am vedea-o desenată, în afară, fiindcă ar
fi pictată peste disc.

p.drawRect(QRect(35,-4,15,8));
p.end();
}

Nota: Acest paragraf este copiat integral din cartea autorulu, Dan Popa. Rog editorii care scaneaza antiplagiat sa nu considere acest text decat ceea ce este, reutilizare legala a propriilor explicatii, combinata cu niste fragmenete de cod care au fost lansate sub sub licenta libera de tip BSD.

Exercitii (cum vi se par ?)
1*) Incercati sa definiti un Widget grafic numit "termometru" care sa aiba o bula de mercur (o placinta desenata cu drawPie cu unghi 360 de grade) si o coloana de mercur care se ridica sau se coboara functie de un semnal, si are si doua valori, un maxim si un minim.
2*) Transformati clasa Cannon prin derivare intr-o clasa Voltmetru sau Watmetru, care sa aiba un indicator ce se roteste in jurul unui centru  (tot o placinta desenata cu drawPie cu unghi 360 de grade)  si niste valori numerice din 10 in 10 scrise pe un arc de cerc, deasupra indicatorului, asa cum am facut cu ocazia lucrarii C8.

The end.

Niciun comentariu:

Trimiteți un comentariu