Skip to content

Commit 5d25bb1

Browse files
lorant3600csorbakristof
authored andcommitted
jeti123 team snippet added (bmeaut#62)
* jeti123 team snippet added * Rename from 31 to 34 and header added
1 parent 917883d commit 5d25bb1

File tree

2 files changed

+352
-0
lines changed

2 files changed

+352
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# A jeti123 csapat tanulságai az Alkalmazásfejlesztés házi feladattal kapcsolatban.
2+
3+
## .c .h fileok
4+
5+
Mindenképpen javasolt szépen struktúrált .cpp és .h fileokat készíteni, melyeknek beszédes neveik vannak. Ez jelentősen megkönnyíti a projekt átláthatóságát, valamint debuggolásnál is egyértelmű lesz miért és hova ugrálunk.
6+
7+
## Osztályok, öröklés
8+
9+
Az előbb leírtak itt is érvényesek, beszédes osztályneveket ajánlott kitalálni. Ne féljünk, ha esetleg hosszúra sikerül, inkább legyen átlátható, a code completion úgy is megkönnyíti a gépelést. Kiemelném, hogy az öröklési mechanizmus egy rendkívül hasznos funkciója a c++ -nak. Ne sajnáljuk az időt attól, hogy egy korrekt ősosztályt alkossunk meg, melyből örökölt példányok könnyebben átláthatóak.
10+
11+
Esetünkben a `` WindowEventHandling `` osztályból származnak a szimulátor és a monitor ablakkezelői, rendre `` MonitorWindowEventHandling `` és `` SimulatorWindowEventHandling `` . Az ősosztály tartalmazza a QML oldali elemek keresésére szolgáló `` FindItemByName `` függvényeket, protected öröklési mechanizmussal. A konstruktora átveszi a `` QQmlContext `` objektumot, mely tovább öröklődik. Szintén itt kerül deklarálásra az ablakkezelők signal-slot mechanizmusához szükséges virtual öröklődésű `` ConnectQmlSignals `` függvénye, mely az alosztályokban az override kulcsszóval felülírható mint pl.: `` void ConnectQmlSignals(QObject *rootObject) override; `` Ennek segítségével az örököltetett osztályok saját módon írhatják felül az adott függvényt.
12+
13+
## c++ és QML környezet közötti változó átadás
14+
15+
Ez talán a grafikus felület egyik alapvető működési feltétele. Ha nem vagyunk képesek átadni a cpp oldali változóinkat a grafikus felületet alkotó QML-nek, szinte semmi értelme GUI-t készíteni. Ez persze visszafelés is igaz, hiszen olykor pl. egy csúszkával beállított értéket kell a cpp oldalon megvalósított funkciónknak átadni.
16+
17+
A probléma megoldása a következő:
18+
19+
#### cpp -> QML: "QString"
20+
* Az átadni kívánt változó létrehozása:
21+
```cpp
22+
QString testResult = (testOK == true) ? "OK" : "NOK";
23+
```
24+
* Átadás a QML környezetnek "testResultText" néven:
25+
```cpp
26+
qmlContext.setContextProperty(QStringLiteral("testResultText"), QVariant::fromValue(testResult));
27+
```
28+
* Ezzel létrejött egy `` testResultText `` nevű változó a QML oldalon, melyet tetszőleges módon használhatunk a QML környezetben.
29+
30+
#### cpp -> QML: "QVector"
31+
* Az átadni kívánt vektor:
32+
```cpp
33+
QVector<int> activeAlarmZones;
34+
```
35+
* Az átadáshoz deklarálni kell egy `` QVarianList `` nevű változót, melyet fel kell tölteni az átadni kívánt tömb elemeivel:
36+
```cpp
37+
QVarianList alarmZonesQML;
38+
```
39+
* A feltöltés:
40+
```cpp
41+
QVariantList alarmzone = QVariantList{}; //Átmeneti változó
42+
for(int i = 0; i < activeAlarmZones.length(); i++)
43+
{
44+
int zone = activeAlarmZones[i];
45+
alarmzone.append(QVariant::fromValue(zone));
46+
}
47+
alarmZonesQML = alarmzone;
48+
```
49+
* Átadás a QML környezetnek `` alarmZones `` néven:
50+
```cpp
51+
qmlContext.setContextProperty(QStringLiteral("alarmZones"), QVariant::fromValue(alarmZonesQML));
52+
```
53+
54+
#### cpp -> QML: "2D vektor"
55+
* A probléma a következő:
56+
A szimulátorunk egy házat modellez, melyben több szoba van. A szobák hőmérséklete különbözik, melyet szeretnénk átadni a QML környezetnek. Az ábrázolhatóság érdekében azonban szeretnénk az utolsó N értéket megjeleníteni ezzel minden szobához N hőmérséklet tartozik. Az így keletkezett 2D tömb pl. a következőképpen nézhet ki:
57+
Szoba1: | T1,1 | T1,2 | T1,3 | ... | T1,N |
58+
Szoba2: | T2,1 | T2,2 | T2,3 | ... | T2,N |
59+
Szoba3: | T3,1 | T3,2 | T3,3 | ... | T3,N |
60+
Szoba4: | T4,1 | T4,2 | T4,3 | ... | T4,N |
61+
* Az átadáshoz deklarált változó:
62+
```cpp
63+
QVariantList roomTemperaturesQML;
64+
```
65+
* Az adatok másolása és a 2D tömb létrehozása:
66+
A "container" eltárolja a szobák állapotát minden új állapot érkezésekor, azaz ebben megtalálható az utolsó N állapot.
67+
```cpp
68+
for (int i = 0; i < container[0].get()->rooms.length(); i++)//Ciklus végig a szobákon
69+
{
70+
auto index = container.size() - N; //Megjelenítendő utolsó N adat első elemének helye
71+
72+
QVariantList ll = QVariantList{};//Átmeneti QVariantList típusú változó
73+
for(; index != container.size(); index++) //Ciklus végig az utolsó N bejegyzésen
74+
{
75+
float temp = container[index].get()->rooms[i].temperature; //Egy érték kinyerése
76+
ll.append(QVariant::fromValue(temp)); //ll lista feltöltése 1. dimenzió
77+
}
78+
l << QVariant::fromValue(QVariantList(ll)); //Az ll lista hozzáfűzése az l listához: 2. dimenzió
79+
}
80+
roomTemperaturesQML = l; // a 2D lista másolása az átadni kívánt változóba
81+
```
82+
* Átadás a QML környezetnek `` roomTemperatures `` néven:
83+
```cpp
84+
qmlContext.setContextProperty(QStringLiteral("roomTemperatures"), QVariant::fromValue(roomTemperaturesQML));
85+
```
86+
* A QML oldalon az ismert módon érjük el a tömb elemeit:
87+
```cpp
88+
var T = graphTemperatures[i][j];
89+
```
90+
91+
## Kommunikáció a QML oldalról a CPP oldalnak
92+
* Ezt könnyen megtehetjük a "signal & slot" mechanizmussal. A cpp oldalon definiáljuk a QML oldalról meghívandó slotot pl.:
93+
```cpp
94+
public slots:
95+
void setHeatingSetPoint(int value);
96+
```
97+
* A QML oldalon létrehozunk egy signalt:
98+
```cpp
99+
signal setHeatingSetPointCpp(int value);
100+
```
101+
* A QML ojektumunk, melyet majd meg kell keressünk a CPP oldalról `` <objectName> `` néven:
102+
```cpp
103+
Item
104+
{
105+
objectName: "controlPanel"
106+
...
107+
//Ezen objektumon belül található majd az a slider pl. mely az adott értéket változtatni akarja.
108+
}
109+
```
110+
* Összekötés a cpp slottal:
111+
```cpp
112+
QQuickItem *controlPanel = FindItemByName(rootObject,QString("controlPanel")); //Megkeressük a QML "controlPanel" objektumát
113+
if (controlPanel) //Ha megtaláltuk összekapcsoljuk a QML signalt a cpp slottal:
114+
QObject::connect(controlPanel, SIGNAL(setHeatingSetPointCpp(int)), this, SLOT(setHeatingSetPoint(int)));
115+
else //Ha nem, sírunk...
116+
qDebug() << "HIBA: Nem találom a controlPanel objektumot a QML környezetben.";
117+
```
118+
* A "slider" elem blokkján belül létrehozunk egy JS függvényt, mely az érték megváltozásakor meghívja a cpp oldalon regisztrált signalt:
119+
```cpp
120+
Slider
121+
{
122+
function setHeating() {setHeatingSetPointCpp(heatingSlider.value)} //JS függvény
123+
id:heatingSlider
124+
onValueChanged: setHeating() //JS függvény meghívása, mely a CPP signalt aktiválja
125+
}
126+
```
127+
* Az így meghívódott cpp oldali `` setHeatingSetPoint `` függvényünk tetszőlegesen használhatja az átadott értéket.
128+
129+
## Grafikonok rajzolása qml oldalon
130+
Ha nagyon nincs ötlete az embernek, hogyan lehet qml-ből grafikont rajzolni, akkor érdemes szétnézni a példák között. A Qt Creator Welcome felületéről is elérhetőek gyorsan, az Examples gomb alatt. Ezek közül mi a Qml Weather és Qml F1 Legends példa alapján készítettük el a saját grafikonunkat. Ebben a snippet-ben a ChartView általunk felfedezett lehetőségeit szeretnénk bemutatni.
131+
132+
#### ChartView
133+
Egyszerűen lehet grafikont rajzoltatni vele, mi a hőmérséklet kijelzésére használtuk. Az idő előre haladtával a grafikon is változott, mindig az utolsó pár értéket jelenítette meg.
134+
```cpp
135+
ChartView
136+
{
137+
id: chartView
138+
animationOptions: ChartView.SeriesAnimations
139+
antialiasing: true
140+
141+
ValueAxis{
142+
id: valueAxisY
143+
min: 10
144+
max: 40
145+
titleText: "Temperature [&deg;C]"
146+
}
147+
148+
LineSeries {
149+
id: tempNappali
150+
axisX: valueAxisX
151+
axisY: valueAxisY
152+
name: "Nappali"
153+
}
154+
// ...
155+
```
156+
* `` ValueAxis `` segítségével megadhatjuk, hogy mi legyen a tengelyek neve, a tengelyen mi legyen a minimális és maximálisan kijelzett érték. A minimum és a maximum menet közben dinamikusan változtatható. Példáil: `` chartView.axisY().max = 30 ``
157+
* `` LineSeries `` segítségével fogjuk kezelni a kirajzolandó adatokat. Az `` id `` azonosítja a vonalat, a `` name `` pedig legendnél jelenik meg.
158+
* `` tempNappali.append(currentIndex,i1); `` sorral tudunk értéket hozzáfűzni a grafikonunkhoz. A `` currentIndex `` mondja meg, hogy az x tengely melyik értékéhez tartozzon az `` i1 `` változóban megadott érték.
159+
* A grafikon mozgatását úgy oldottuk meg, hogy az x tengelyhez tartozó minimum és maximum értékeket változtattuk, így mindig csak az utolsó 45 érték volt megjelenítve.
160+
```cpp
161+
if (currentIndex > 43) {
162+
chartView.axisX().max = currentIndex + 1;
163+
chartView.axisX().min = chartView.axisX().max - 45;
164+
} else {
165+
chartView.axisX().max = 45;
166+
chartView.axisX().min = 0;
167+
}
168+
```
169+
170+
## Befejezésül
171+
A házi feladattal rendkívül sokat tanultunk, nem csak QML és CPP programozás terén, de abban is jelentős tapasztalatra
172+
tettünk szert, hogyan kell megfelelően struktúrált kódot készíteni és hogyan kell azt átláthatóan ledokumentálni. Reméljük a leírtakkal segíteni tudtunk mindazoknak, akik még az első lépéseket teszik a házi feladat megoldása során.
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
---
2+
layout: default
3+
codename: AlkFejlHF34
4+
title: jeti123 csapat tanulságai
5+
tags: alkfejl afhf skipfromindex
6+
authors: Csőke Lóránt, Frank János, Werkmann Virág
7+
---
8+
9+
# A jeti123 csapat tanulságai az Alkalmazásfejlesztés házi feladattal kapcsolatban.
10+
11+
## .c .h fileok
12+
13+
Mindenképpen javasolt szépen struktúrált .cpp és .h fileokat készíteni, melyeknek beszédes neveik vannak. Ez jelentősen megkönnyíti a projekt átláthatóságát, valamint debuggolásnál is egyértelmű lesz miért és hova ugrálunk.
14+
15+
## Osztályok, öröklés
16+
17+
Az előbb leírtak itt is érvényesek, beszédes osztályneveket ajánlott kitalálni. Ne féljünk, ha esetleg hosszúra sikerül, inkább legyen átlátható, a code completion úgy is megkönnyíti a gépelést. Kiemelném, hogy az öröklési mechanizmus egy rendkívül hasznos funkciója a c++ -nak. Ne sajnáljuk az időt attól, hogy egy korrekt ősosztályt alkossunk meg, melyből örökölt példányok könnyebben átláthatóak.
18+
19+
Esetünkben a `` WindowEventHandling `` osztályból származnak a szimulátor és a monitor ablakkezelői, rendre `` MonitorWindowEventHandling `` és `` SimulatorWindowEventHandling `` . Az ősosztály tartalmazza a QML oldali elemek keresésére szolgáló `` FindItemByName `` függvényeket, protected öröklési mechanizmussal. A konstruktora átveszi a `` QQmlContext `` objektumot, mely tovább öröklődik. Szintén itt kerül deklarálásra az ablakkezelők signal-slot mechanizmusához szükséges virtual öröklődésű `` ConnectQmlSignals `` függvénye, mely az alosztályokban az override kulcsszóval felülírható mint pl.: `` void ConnectQmlSignals(QObject *rootObject) override; `` Ennek segítségével az örököltetett osztályok saját módon írhatják felül az adott függvényt.
20+
21+
## c++ és QML környezet közötti változó átadás
22+
23+
Ez talán a grafikus felület egyik alapvető működési feltétele. Ha nem vagyunk képesek átadni a cpp oldali változóinkat a grafikus felületet alkotó QML-nek, szinte semmi értelme GUI-t készíteni. Ez persze visszafelés is igaz, hiszen olykor pl. egy csúszkával beállított értéket kell a cpp oldalon megvalósított funkciónknak átadni.
24+
25+
A probléma megoldása a következő:
26+
27+
#### cpp -> QML: "QString"
28+
* Az átadni kívánt változó létrehozása:
29+
```cpp
30+
QString testResult = (testOK == true) ? "OK" : "NOK";
31+
```
32+
* Átadás a QML környezetnek "testResultText" néven:
33+
```cpp
34+
qmlContext.setContextProperty(QStringLiteral("testResultText"), QVariant::fromValue(testResult));
35+
```
36+
* Ezzel létrejött egy `` testResultText `` nevű változó a QML oldalon, melyet tetszőleges módon használhatunk a QML környezetben.
37+
38+
#### cpp -> QML: "QVector"
39+
* Az átadni kívánt vektor:
40+
```cpp
41+
QVector<int> activeAlarmZones;
42+
```
43+
* Az átadáshoz deklarálni kell egy `` QVarianList `` nevű változót, melyet fel kell tölteni az átadni kívánt tömb elemeivel:
44+
```cpp
45+
QVarianList alarmZonesQML;
46+
```
47+
* A feltöltés:
48+
```cpp
49+
QVariantList alarmzone = QVariantList{}; //Átmeneti változó
50+
for(int i = 0; i < activeAlarmZones.length(); i++)
51+
{
52+
int zone = activeAlarmZones[i];
53+
alarmzone.append(QVariant::fromValue(zone));
54+
}
55+
alarmZonesQML = alarmzone;
56+
```
57+
* Átadás a QML környezetnek `` alarmZones `` néven:
58+
```cpp
59+
qmlContext.setContextProperty(QStringLiteral("alarmZones"), QVariant::fromValue(alarmZonesQML));
60+
```
61+
62+
#### cpp -> QML: "2D vektor"
63+
* A probléma a következő:
64+
A szimulátorunk egy házat modellez, melyben több szoba van. A szobák hőmérséklete különbözik, melyet szeretnénk átadni a QML környezetnek. Az ábrázolhatóság érdekében azonban szeretnénk az utolsó N értéket megjeleníteni ezzel minden szobához N hőmérséklet tartozik. Az így keletkezett 2D tömb pl. a következőképpen nézhet ki:
65+
Szoba1: | T1,1 | T1,2 | T1,3 | ... | T1,N |
66+
Szoba2: | T2,1 | T2,2 | T2,3 | ... | T2,N |
67+
Szoba3: | T3,1 | T3,2 | T3,3 | ... | T3,N |
68+
Szoba4: | T4,1 | T4,2 | T4,3 | ... | T4,N |
69+
* Az átadáshoz deklarált változó:
70+
```cpp
71+
QVariantList roomTemperaturesQML;
72+
```
73+
* Az adatok másolása és a 2D tömb létrehozása:
74+
A "container" eltárolja a szobák állapotát minden új állapot érkezésekor, azaz ebben megtalálható az utolsó N állapot.
75+
```cpp
76+
for (int i = 0; i < container[0].get()->rooms.length(); i++)//Ciklus végig a szobákon
77+
{
78+
auto index = container.size() - N; //Megjelenítendő utolsó N adat első elemének helye
79+
80+
QVariantList ll = QVariantList{};//Átmeneti QVariantList típusú változó
81+
for(; index != container.size(); index++) //Ciklus végig az utolsó N bejegyzésen
82+
{
83+
float temp = container[index].get()->rooms[i].temperature; //Egy érték kinyerése
84+
ll.append(QVariant::fromValue(temp)); //ll lista feltöltése 1. dimenzió
85+
}
86+
l << QVariant::fromValue(QVariantList(ll)); //Az ll lista hozzáfűzése az l listához: 2. dimenzió
87+
}
88+
roomTemperaturesQML = l; // a 2D lista másolása az átadni kívánt változóba
89+
```
90+
* Átadás a QML környezetnek `` roomTemperatures `` néven:
91+
```cpp
92+
qmlContext.setContextProperty(QStringLiteral("roomTemperatures"), QVariant::fromValue(roomTemperaturesQML));
93+
```
94+
* A QML oldalon az ismert módon érjük el a tömb elemeit:
95+
```cpp
96+
var T = graphTemperatures[i][j];
97+
```
98+
99+
## Kommunikáció a QML oldalról a CPP oldalnak
100+
* Ezt könnyen megtehetjük a "signal & slot" mechanizmussal. A cpp oldalon definiáljuk a QML oldalról meghívandó slotot pl.:
101+
```cpp
102+
public slots:
103+
void setHeatingSetPoint(int value);
104+
```
105+
* A QML oldalon létrehozunk egy signalt:
106+
```cpp
107+
signal setHeatingSetPointCpp(int value);
108+
```
109+
* A QML ojektumunk, melyet majd meg kell keressünk a CPP oldalról `` <objectName> `` néven:
110+
```cpp
111+
Item
112+
{
113+
objectName: "controlPanel"
114+
...
115+
//Ezen objektumon belül található majd az a slider pl. mely az adott értéket változtatni akarja.
116+
}
117+
```
118+
* Összekötés a cpp slottal:
119+
```cpp
120+
QQuickItem *controlPanel = FindItemByName(rootObject,QString("controlPanel")); //Megkeressük a QML "controlPanel" objektumát
121+
if (controlPanel) //Ha megtaláltuk összekapcsoljuk a QML signalt a cpp slottal:
122+
QObject::connect(controlPanel, SIGNAL(setHeatingSetPointCpp(int)), this, SLOT(setHeatingSetPoint(int)));
123+
else //Ha nem, sírunk...
124+
qDebug() << "HIBA: Nem találom a controlPanel objektumot a QML környezetben.";
125+
```
126+
* A "slider" elem blokkján belül létrehozunk egy JS függvényt, mely az érték megváltozásakor meghívja a cpp oldalon regisztrált signalt:
127+
```cpp
128+
Slider
129+
{
130+
function setHeating() {setHeatingSetPointCpp(heatingSlider.value)} //JS függvény
131+
id:heatingSlider
132+
onValueChanged: setHeating() //JS függvény meghívása, mely a CPP signalt aktiválja
133+
}
134+
```
135+
* Az így meghívódott cpp oldali `` setHeatingSetPoint `` függvényünk tetszőlegesen használhatja az átadott értéket.
136+
137+
## Grafikonok rajzolása qml oldalon
138+
Ha nagyon nincs ötlete az embernek, hogyan lehet qml-ből grafikont rajzolni, akkor érdemes szétnézni a példák között. A Qt Creator Welcome felületéről is elérhetőek gyorsan, az Examples gomb alatt. Ezek közül mi a Qml Weather és Qml F1 Legends példa alapján készítettük el a saját grafikonunkat. Ebben a snippet-ben a ChartView általunk felfedezett lehetőségeit szeretnénk bemutatni.
139+
140+
#### ChartView
141+
Egyszerűen lehet grafikont rajzoltatni vele, mi a hőmérséklet kijelzésére használtuk. Az idő előre haladtával a grafikon is változott, mindig az utolsó pár értéket jelenítette meg.
142+
```cpp
143+
ChartView
144+
{
145+
id: chartView
146+
animationOptions: ChartView.SeriesAnimations
147+
antialiasing: true
148+
149+
ValueAxis{
150+
id: valueAxisY
151+
min: 10
152+
max: 40
153+
titleText: "Temperature [&deg;C]"
154+
}
155+
156+
LineSeries {
157+
id: tempNappali
158+
axisX: valueAxisX
159+
axisY: valueAxisY
160+
name: "Nappali"
161+
}
162+
// ...
163+
```
164+
* `` ValueAxis `` segítségével megadhatjuk, hogy mi legyen a tengelyek neve, a tengelyen mi legyen a minimális és maximálisan kijelzett érték. A minimum és a maximum menet közben dinamikusan változtatható. Példáil: `` chartView.axisY().max = 30 ``
165+
* `` LineSeries `` segítségével fogjuk kezelni a kirajzolandó adatokat. Az `` id `` azonosítja a vonalat, a `` name `` pedig legendnél jelenik meg.
166+
* `` tempNappali.append(currentIndex,i1); `` sorral tudunk értéket hozzáfűzni a grafikonunkhoz. A `` currentIndex `` mondja meg, hogy az x tengely melyik értékéhez tartozzon az `` i1 `` változóban megadott érték.
167+
* A grafikon mozgatását úgy oldottuk meg, hogy az x tengelyhez tartozó minimum és maximum értékeket változtattuk, így mindig csak az utolsó 45 érték volt megjelenítve.
168+
```cpp
169+
if (currentIndex > 43) {
170+
chartView.axisX().max = currentIndex + 1;
171+
chartView.axisX().min = chartView.axisX().max - 45;
172+
} else {
173+
chartView.axisX().max = 45;
174+
chartView.axisX().min = 0;
175+
}
176+
```
177+
178+
## Befejezésül
179+
A házi feladattal rendkívül sokat tanultunk, nem csak QML és CPP programozás terén, de abban is jelentős tapasztalatra
180+
tettünk szert, hogyan kell megfelelően struktúrált kódot készíteni és hogyan kell azt átláthatóan ledokumentálni. Reméljük a leírtakkal segíteni tudtunk mindazoknak, akik még az első lépéseket teszik a házi feladat megoldása során.

0 commit comments

Comments
 (0)