Bun venit la laboratorul de Qt din saptamana a 8-a.
Cursul este pe pagina precedenta din blog, tot de azi.
La o precedenta intalnire v-am propus sa faceti un widget rotitor,care sa se roteasca (unii nu s-au prins) in jurul unui centru !
Puteati folosi:
move(x,y);
setGeometry(x,y,w,h);
Dar atentie, intrucat acestea pozitioneaza widget-ul fara sa ii schimbe orientarea (sus ramane sus, jos ramane jos) trebuia inteles ca widgetul nu se roteste in jurul propriului centru, ci in jurul altui widget.
Cam ca o planeta in jurul soarelui:
Exact aceasta am facut, folosind Designerul Visual, un radio buton care e soarele si un buton care e planeta, Pamantul daca vreti.
Le numim "pamant" si "soare". (dreapta sus)
In clasa principala adaugam toate valorile necesare calculului de geometrie analitica:
x0,y0 - coord. Soarelui
x1,y1 - coord Pamantului
raza - raza orbitei (presupusa cerc)
pi - ca sa transform gradele in radiani
alfa - unghiul la care a ajuns planeta , creste pina la 360 de grade apoi creste iar in intervalul 0 ... 360 de grade , fiindca e modulo 360.
alfaRadiani - unghiul alfa convertit in radiani, argument pentru cos si sinus.
Am folosit ca eveniment care declanseaza rotatia acel resize Event (il stiati deja). Miscati coltul ferestrei ca sa animati planeta !
Exercitiu: Folositi un mouseEvent sau un wheelEvent ca sa miscati planeta de la rotita sau de la mouse.
Initializarea: In constructorul clasei am adugat cod de initializare:
Algoritm de initgializare:
- extarg coordonatele soarelui (x0,y0)
- extrag coordonatele planetei (pamant) : (x1,y1)
- calculez raza cu teorema lui Pitagora.
- pornesc rotirea de la unghi alfa = 0
Exercitiu: Ce alte metode de a calcula a la puterea b stiati ?
La fiecare apel al metodei (aici resizeEvent - ca nu ati lucrat cu alte evenimente) facem calculele necesare miscarii planetei:
Variatia coordonatei pe x este Raza * Cos(alfa) - alfa in Radiani ca asa o vrea cosinus. (Un cerc are 2 * Pi radiani, deci formula lui alfaRadiani e usor de dedus.
Variatia coordonatei pe y este Raza * Sin(alfa) - alfa in Radiani ca asa o vrea sinus.
Mutati acum planeta pe coordonatele nou calculate x1,y1.
Pentru reafisare puteti folosi:
- show()
- repaint()
sau
-update().
Show e pentru afisare de widget-uri.
Repaint declanseaza un eveniment repaint si redeseneaza widget-urile grafice, o planeta desenata frumos ar avea nevoie de el.
Update... updateaza desenul intregii ferestre.
La diverse versiuni de Qt se foloseau unul sau altul, dupa nevoi.
Qt 5.9 imi recomanda sa folosesc update()...
surpriza, pe Linux merge si fara el, se fac update-uri implicite. (As adauga ca move se ocupa si de asta!)
Miscati putin coltul drept al ferestrei pentru a roti planeta.
Exercitiu: Folositi alte evenimente decat resize ... am mai propus o data acest exercitiu, insist !
Astept ambele proiecte pe-email, pentru arhivele, portofoliile voastre.
Un raspuns ne trimite A.E:
A introdus o noua metoda in clasa ferestrei principale, care raspunde la evenimentele QWheelEvent.
In magine: Clasa ferestrei principale raspunde la doua evenimente.
Intrebare: Ce ati face pentru ca ambele evenimente sa roteasca Planeta in jurul soarelui la fel ? Dar ca sa o roteasca in sensuri diferite ? Dar ca sa fie codul cat mai scurt in ambele situatii ?
Pentru ca am primit (multumesc S.B) o varianta de solutie mai colorata (QT_VS_7) dar care face apel la niste notiuni nepredate inca, explic cum se poate obtine asa ceva:
1) Intai aveti nevoie de doua Widget-uri care pot sa contina o imagine, acestea sunt QLabel, un QLabel poate contine si text si imagine sau numai una, textul ori imaginea.
2) Aveti nevoie de un fisier de resurse, cu extensie .qrc care trebuie adaugat la proiect. In el creati un dosar /img in care puteti adauga fisiere. Observati ca editorul de resurse va permite sa adaugati folder sau sa adaugati fisier.
Asa se adauga fisierul de resurse, care va "contine" resursele
multimedia, in acest caz imaginile.
3) Constructorul ferestrei principale trebuie sa initializeze:
3.1 QPixmap-urile cu imaginile pamantului si soarelui
3.2 Etichetele goale cu QPixmap-urile de mai sus.
QPixmap soare(":/img/sun.png");
QPixmap pamant(":/img/earth.png");
ui->soare->setPixmap(soare.scaled(75,75,Qt::KeepAspectRatio));
ui->pamant->setPixmap(pamant.scaled(25,25,Qt::KeepAspectRatio));
Nota: Din cauza ca ui-ul are namespace separat se pot folosi aceleasi nume pentru QPixmap-ul soare si pentru eticheta soare din .ui -ul realizat cu designerul. Desi nu recomand. La fel si pentru pamant.
Observati ca nu exista litera a unitatii de disc ca in Windows. Resursele vor fi numite din program asa :/img/sun.png
Exercitiu: Folositi un QTimer ca sa miscati planeta, continuu in jurul soarelui, QTimer-ul urmand sa genereze evenimente.
Indicatii:
Ok, acuma adaugatii in clasa principala: (mainwindow.h)
void timerEvent(QTimerEvent *e);
Si o subrutina similara de prelucrare:
void MainWindow::timerEvent(QTimerEvent *e){
alfa=(alfa+10)%360;
qDebug() << "alfa=" <<alfa;
qDebug() <<"alfaradiani"<<alfaradiani;
alfaradiani=(pi*alfa)/180;
x1=x0+raza*cos(alfaradiani);
y1=y0+raza*sin(alfaradiani);
qDebug() <<"x1="<<x1;
qDebug() <<"y1="<<y1;
qDebug() <<"raza="<<raza;
ui->pamant->move(x1,y1);
show();
}
alfa=(alfa+10)%360;
qDebug() << "alfa=" <<alfa;
qDebug() <<"alfaradiani"<<alfaradiani;
alfaradiani=(pi*alfa)/180;
x1=x0+raza*cos(alfaradiani);
y1=y0+raza*sin(alfaradiani);
qDebug() <<"x1="<<x1;
qDebug() <<"y1="<<y1;
qDebug() <<"raza="<<raza;
ui->pamant->move(x1,y1);
show();
}
Si planeta se va invarti singura in jurul soarelui, daca ii dam startul din constructor cu:
QObject::startTimer(100);
Nota: Aceasta functie a fost introdusa de la Qt 5.9 incoace. Pentru versiuni mai vechi, trebuie folosit un QTimer, care lanseaza un semnal timeout, si acesta este receptionat pe un slot.
Despre cele trei variante de a implementa un timer in QT se gasesc explicatii in Help.
Niciun comentariu:
Trimiteți un comentariu