Rólam
Főoldal
Önéletrajzom
Képek
Tanulmányok és Oktatás
EAF1
EAF3
EAF4
Fontkészlet
PNY1
PP
ProgKör
Visual Basic
Érdeklődési körök
Linux
Linux PalmLD
RDiff
Munkák
Önéletrajz
CV in English
utolsó módosítás:
2010. augusztus 9.
| A gyakorlat céljai:
-
A QT környezet szövegszerkesztőből és terminálból való használatának elsajátítása.
-
Az assistant súgó használatának elsajátítása.
A gyakorlatnak nem célja a QT designer szerkesztő elsajátítása, mert:
-
Sok szolgáltatás könnyen és több helyen megtalálható benne.
-
Sok szolgáltatás nem található meg benne.
-
Bár az elején nehezebb elindulni ezen [a gyakorlat által bemutatott] módon, később sokkal több előnyt nyújt [például EAF4 esetén is].
-
A designer szerepel előadáson.
Feladat: Hozzunk létre olyan alkalmazást, amelynek segítségével az angolszász hosszmértékegységekre tudunk konvertálni a metrikus mértékegység rendszerből.
(A mértékegységekről bővebben)
- Megjegyzés:
- A kiadandó parancsok előtt egy
$ jel jelöli a promptot.
A grafikus felület létrehozásának lépései:
-
Hozzunk létre egy könyvtárat a projekt számára (ezzel megegyező nevűre fogja a QT a nevet automatikusan állítani). [A továbbiakban feltételezem, hogy ebből a könyvtárból lesznek kiadva a parancsok.]
$ mkdir -p eaf3/qtbead
$ cd eaf3/qtbead
- Megjegyzés:
- A feladat végére a qtbead könyvtáram tartalma ez lett: codes/eaf3/qtbead.
-
Hozzunk létre egy minimális main.cpp állományt.
int main(int argc, char* argv[])
{
}
-
A QT assistant használata.
-
Az QT eseménykezelő algoritmusának fő ciklusa a QApplication osztály exec metódusában van. Ehhez egészítsük ki a main függvény kódját a következőképpen:
#include <qapplication.h>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
app.exec();
return 0;
}
-
Hozzuk létre a projekt állományt.
-
Hozzuk létre a projekt lefordításához szükséges Makefile állományt. Magáról a make rendszerről a make honlapján olvashatunk bővebben.
-
Fordítsuk le a programot. Ennek a pontnak az alpontjai különböző a fordítási környezetből (nem a kódhibából) adódó hibákat és megoldásaikat tartalmazzák. A fordításhoz a következő parancsot kell kiadni:
-
K: A fordító arra panaszkodik, hogy nem találja a qapplication.h állományt.
V: A QT fejléc állományai nem a standard helyen találhatók, ezért a .pro állományban be kell állítani.
-
Keressük meg a
qapplication.h állományt.
$ find / -name qapplication 2>/dev/null
/usr/include/qt/qapplication.h
Ebből megtudjuk, hogy a qapplication.h állományt a /usr/include/qt könyvtárban találjuk.
-
Egészítsük a .pro állományt a következő sorral:
INCLUDEPATH += /usr/include/qt
-
Fordítsuk újra a programot.
-
K: A linker arra panaszkodik, hogy nem találja a -lqt-t.
V: A QT nem találja a függvénykönyvtárát.
-
Keressük meg a QT függvénykönyvtárát ez vagy többszálas (
libqt-mt.so*) vagy egyszálas (libqt.so*). A többszálast kell előnyben részesíteni, erre lesz a beállítás kihegyezve, de ha nem találjuk meg a többszálas függvénykönyvtárat, probáljuk az egyszálassal a következő parancsokat.
-
Keressük meg a függvénykönyvtárat:
$ find / -name libqt-mt* 2>/dev/null
/usr/lib/libqt-mt.prl
/usr/lib/libqt-mt.la
/usr/lib/libqt-mt.so.3.3.4
/usr/lib/libqt-mt.so
/usr/lib/libqt-mt.so.3
/usr/lib/libqt-mt.so.3.3
Ebből láthatjuk, hogy a függvénykönyvtár a /usr/lib függvénykönyvtárban található.
-
Adjuk hozzá a .pro állományhoz a következő sort:
LIBS += -L/usr/lib -lqt-mt
-
Fordítsuk újra a programot.
-
Mostmár elindul a program de még nem történik semmi és nem is lehet kilépni csak a CTRL+C billentyűkombinációval.
-
Hozzunk létre egy főablakot a program számára. Ehhez a QMainWindow osztályból kell származtatnunk egy osztályt.
A mainwnd.h állományt hozzuk létre a következőképpen:
#ifndef __MAINWND_H__
#define __MAINWND_H__
#include <qmainwindow.h>
class MainWnd : public QMainWindow {
};
#endif /* __MAINWND_H__ */
-
És indítsuk el a főprogramból az ablakot (adjuk a következő sorokat az app.exec(); sor elé:
És az include részbe:
Ezután fordítsuk le és futtassuk a programot. Egy üres ablakot fogunk látni, amelyből továbbra is csak a CTRL+C billentyűkombinációval lehet kilépni.
-
A QT widget csomagoló rendszerének használata.
-
A főablakon függőleges elrendezést szeretnénk alkalmazni. A függőleges elrendezés a következő sorokat fogja tartalmazni:
-
Mennyiség felirat és beviteli mezője.
-
Kiinduló mértékegység és kiválasztó listája.
-
Cél méretékegység és kiválasztó listája.
-
Eredmény és megjelenítő mezője.
-
A gombok.
Magának az elrendezőnek a létrehozásához a következő privát tagokat adjuk hozzá a MainWnd osztályhoz:
-
QWidget* cw.
-
QVBoxLayout* vbox.
Hozzuk létre a mainwnd.cpp állományt, abban a következő konstruktort és destruktort a MainWnd számára:
MainWnd::MainWnd() throw ()
: QMainWindow()
{
setCentralWidget(cw = new QWidget(this));
vbox = new QVBoxLayout(cw);
}
MainWnd::~MainWnd() throw ()
{
delete cw;
}
Adjuk hozzá a következő sort a .pro állományhoz:
HEADERS += mainwnd.h
SOURCES += mainwnd.cpp
Tippek:
-
A
QVBoxLayout a qlayout.h fejléc állományban van definiálva.
-
A konstruktort és a destruktort is deklarálni kell a a
mainwnd.h állományban.
-
A
mainwnd.h állományt be kell szerkeszteni (#include) a mainwnd.cpp állományba.
-
Helyezzük fel az 5 vizszintes elrendezőt az ablakra. Tippek:
-
Az osztályhoz adjuk hozzá a következő privát adattagot: QHBoxLayout* line[5].
-
A konstruktor végére illesszük be a következő kódblokkot:
for (int i = 0; i < 5; ++i) {
line[i] = new QHBoxLayout(cw);
vbox->addLayout(line[i]);
}
-
Vegyük fel a mennyiség sorban található objektumokat (először ezt a kettőt a maradékot további egy lépésben majd). Tippek:
-
A felirat a
QLabel objektum segítségével hozható létre, amely a qlabel.h állományban van deklarálva.
-
A beviteli mező a
QLineEdit objektum segítségével hozható létre, ez a qlineedit.h állományban van deklarálva.
-
QLineEdit* unit
-
QLabel* unit_label
-
A konstruktorba a következő blokk kellhet (a for ciklus után):
unit_label = new QLabel("Mennyiség:", cw);
line[0]->addWidget(unit_label);
unit = new QLineEdit(cw);
line[0]->addWidget(unit);
-
Nem tetszik, hogy egymásra lógnak az objektumok. A QHBoxLayout és a QVBoxLayout osztályoknak van egy olyan konstruktora, amely azt mondja meg, mennyi távolságot kell az objektumok között tartani. Tippek:
-
vbox = new QVBoxLayout(cw, 5)
-
line[i] = new QHBoxLayout(5)
-
Na akkor dobáljuk fel a maradék objektumokat:
-
QLabel* from_label
-
QLabel* to_label
-
QLabel* result_label
-
A
QComboBox osztály egy lenyíló menüt valósít meg, ez a qcombobox.h állományban van deklarálva.
-
QComboBox* from
-
QComboBox* to
-
QLineEdit* result
-
A
QPushButton osztály segítségével egy nyomógombot valósíthatunk meg, ez a qpushbutton.h állományban van deklarálva.
-
A
QPushButton a QPushButton(const QString& , QWidget*) metódusával azonnal feliratot is rakhatunk a gombra.
-
Nem tetszik, hogy összevissza vannak a szélességek a beviteli és az eredmény mezőnél. Ez csak a show() metódusban valósítható meg normálisan, ezért felül fogjuk definiálni a QMainWindow::show() metódust. Tippek:
-
void MainWnd::show() throw ()
{
QMainWindow::show();
int width = unit_label->width() < from_label->width()?
from_label->width() : unit_label->width();
width = width < to_label->width()? to_label->width() : width;
width = width < result_label->width()? result_label->width() : width;
unit_label->setMinimumWidth(width);
from_label->setMinimumWidth(width);
to_label->setMinimumWidth(width);
result_label->setMinimumWidth(width);
}
-
QHBoxLayout::addLayout(QWidget*, int) segítségével megmondhatjuk, minek kell átméretezésre kerülnie.
-
Állítsuk be az ablak címét. Tipp:
-
QMainWindow::setCaption("Konvertálás");
-
Még azt kell megvalósítanunk, hogy a kilépés gomb működjön, és készen van a felület. Ehhez szintén egy virtuális metódus felüldefiniálásával tudunk eljutni. Tippek:
-
Az
exit függvény az stdlib.h állományban van deklarálva (az EXIT_SUCCESS makróval együtt).
-
void MainWnd::closeEvent(QClosEvent*) throw ()
{
exit(EXIT_SUCCESS);
}
-
Az ablak a teljes ténykedés eredményeképpen a következőképpen néz ki (enlightenment ablakkezelő alatt):
Az ablak enlightenment alatt
Adjuk meg a funkcionalitást az ablaknak:
-
Töltsük fel a mértékegységek kiválasztó mezőit. A következő mértékegységekre lesz szükségünk:
Bevitelnél:
-
Kilométer,
-
Méter,
-
Centiméter,
-
Milliméter.
A célmértékegységeknél:
-
Mérföld,
-
Yard,
-
Láb,
-
Hüvelyk.
Tipp:
-
ComboBox → insertItem metódus.
-
Oldjuk meg, hogy csak számot lehessen beírni a mennyiség mezőbe. Tippek:
-
A QT-ben segítségünkre vannak az úgynevezett validátorok, amelyek eldönteni képesek, hogy egy beviteli mezőbe mit lehet írni. (Vannak előre definiáltak, és mi is származtathatunk ilyet.) Most létrehozunk egy QIntValidator típusú adattagot, és a beviteli mezőveé közöljük, hogy ez lesz a validátora.
-
QIntValidator intval
-
qvalidator.h
-
QLineEdit → setValidator.
-
Mivel a QIntValidator osztálynak nincs alapértelmezett konstruktora, ne felejtsük el a taginicializátorok között szerepeltetni. Másik megoldás, ha a konstruktorban dinamikusan hozzuk létre az objektumát, ekkor ne felejtsük el a destruktorban megsemmisíteni.
-
Ha valakit zavar, hogy szóközt is lehet a szám elé és mögé írni (a szép megoldás mindenképpen szükségessé teszi), akkor származtatni célszerű a QIntValidator osztályból egy speciálisabb validátort, ami a szóközt elutasítja. Ezután csak a típusát kell átírni a validátornak (demonstrációs célból megcsináltam). Figyeljünk ekkor arra, hogy a felüldefiniálandó virtuális metódus
const típusú, amin túl lehet terhelni C++-ban, ezért ha elfelejtjük odaírni a const jelzőt a függvényünk mellé, akkor nem az fog lefutni, ellentétben azzal, ahogy várnánk.
-
Tiltsuk le, hogy az eredmény mezőbe lehessen írni. Tipp:
-
Oldjuk meg, hogy a kilépés gomb működjön. Ehhez a QT eseménykezelő rendszerét kell használnunk. Amikor egy gombot megnyomnak akkor egy clicked eseményt generál. Ezt a clicked eseményt kell a megfelelő helyre irányítani. Amennyiben eseménykezelést akarunk végezni az osztályunkon belül, akkor az osztály deklarációjának minimum a következőképpen kell kinézni (például a MainWnd esetén):
class MainWnd : public QMainWnd {
Q_OBJECT
};
Ezt a Q_OBJECT makrót az úgynevezett Meta Object Compiler (röviden moc) fogja számunkra átalakítani az eseménykezeléshez megfelelő kódokra (az adott operációs rendszertől függően). Szintén a Meta Object Compiler teszi lehetőve a nem standard C++ kulcsszavak használatát, mint slots és signals. Az utóbbira ebben a feladatban nem lesz szükség, majd előadáson fog szerepelni, az előbbit pedig a konvertálás gomb esetén fogjuk megvizsgálni.
Kapcsoljuk össze a kilépés gomb megnyomásakor keletkező szignált az ablak bezárásának meghívásával. Ezt szintén a moc-nak szóló néhány makróval és a QObject (ami minden QT objektum őse) connect metódusával lehet megtenni:
connect(quit, SIGNAL(clicked()), this, SLOT(close()));
Tipp:
-
Előfordulhat, hogy a
Q_OBJECT makró beírása után nem tudjuk linkelni a programunkat. Ennek a hibás .pro állomány általában az oka. Takarítsunk el minden fordítással keletkező állományt: Ezután a .pro állományból töröljük a CONFIG -= moc sort, ha szerepel benne (ha a CONFIG máshogy is módiosítva van nem csak a moc értékével akkor csak arról győződjünk meg, hogy a moc nem lesz eltávolítva a CONFIG-ból), majd fordítsuk újra a programot. Ha ez nem segít, akkor rendesen van beállítva a környezet, valami más lett elrontva.
-
Oldjuk meg, hogy működjön a konvertálás. Tippek:
-
Konvertálásnál lehet, hogy nincs megadva mennyiség (ez hiba).
-
QMessageBox::question(...), QMessageBox::information(...), QMessageBox::warning(...), QMessageBox::critical(...), ahol "..." egy hosszabb argumentumvektor [assistantból kell kikeresni ezeket a függvényeket].
-
A felsorolt értékekkel olvashatóbbá és típusbiztosabbá tehetjük programunkat (így sok hibát eleve ki tud szűrni a fordítóprogram). C++ nyelv enum lehetősége.
-
Az előző gyakorlaton megadott konvertáló kód használható itt is.
|