Magyar
Bevezetés a Qt programozás alapjaiba
Üdvözöllek a Qt keresztplatformos fejlesztői rendszer világában. Ebben a leírásban egy egyszerű jegyzettömb alkalmazás elkészítése során bemutatjuk a Qt programozás alapfogásait. Az útmutató tanulmányozása során nyugodtan nézz bele az API dokumentációba, amennyiben valamivel kapcsolatban több információra van szükséged.
Az útmutató angol nyelvű változata elérhető az http://doc.qt.nokia.com/gettingstartedqt.html [doc.qt.nokia.com] oldalon.
Hello Jegyzettömb
Példánkban egy egyszerű szövegdobozt hozunk létre egy ablakkeretben. Ez lesz a legegyszerűbb felhasználói felülettel rendelkező Qt segítségével írt program.

Íme a kód:
- #include <QApplication>
- #include <QTextEdit>
- int main(int argv, char **args)
- {
- QTextEdit textEdit;
- textEdit.show();
- return app.exec();
- }
Vizsgáljuk meg a kódot sorról sorra. Az első két sorban a QApplication [doc.qt.nokia.com] és a QTextEdit [doc.qt.nokia.com] osztály használatához szükséges headerfájlokat includoljuk be a programunkba. A Qt összes osztályának megvan a nevével megegyező headerje.
A 6. sorban létrehozunk egy QApplication [doc.qt.nokia.com] objektumot. Ez az objektum kezeli az alkalmazás összes erőforrását. Egy ilyen objektum létrehozása szükséges minden grafikus Qt alkalmazáshoz. Argumentumként át kell adni az argv és args paramétereket, mivel a Qt-ban írt alkalmazásoknak van néhány beépített parancssori argumentuma [doc.trolltech.com].
A 8. sorban létrehozunk egy QTextEdit [doc.qt.nokia.com] objektumot. Ez a szövegdoboz egy megjeleníthető grafikus elem. A Qt-ban az ilyeneket widgeteknek hívjuk. További widgetek például: gördítősávok, címkék, rádiógombok. Minden widget lehet egyfajta konténer további widgetek számára, mint például egy ablak, vagy egy dialógus.
A 9. sorban megjelenítjük a szövegdobozt a saját ablakkeretében. Mint már említettem, a widgetek konténerként is funkcionálnak mint például a QMainWindow [doc.qt.nokia.com], amelynek van menüsora, státuszsora, és még néhány egyéb beépített widgete. Továbbá lehetőség van egyetlen widget megjelenítésére is főablakba helyezés nélkül, ez esetben maga a widget kap egy ablakkeretet. A widgetek alapból nem láthatóak, a show() metódus meghívása teszi őket azzá.
A 11. sorban meghívjuk a QApplication [doc.qt.nokia.com] eseménykezelő rutinját. Ha egy Qt alkalmazás futása közben esemény történik, akkor az kiküldődik a megfelelő widgethez. Például az egérkattintás és a billentyűleütések esetében a szövegdobozunk fogja megkapni ezeket az eseményeket. Az ilyen és ehhez hasonló feladatokat intézi ez a metódus.
Az alakalmazás fordításához és futtatásához nyiss meg egy parancssort, lépj be abba a mappában, ahol a .cpp fájlod található, és futtasd le a következő parancsokat:
- qmake -project
- qmake
- make
Ezen műveletek után egy futtatható binárisnak kell megjelennie a part1 mappában. (Megjegyzés a Windowst és VisualStudiot használóknak: a make nmaket kell futtatniuk, továbbá a bináris a part1/debug vagy part1/release mappában fog létrejönni.)
A qmake a Qt build eszköze ami argumentum nélkül egy projekt fájlt keres, amit fel tud dolgozni. A -project argumentummal létrehoz automatikusan egy .pro fájlt a mappában található fájlokat hozzáadva. A qmaket futtatva létrejön a Makefile, amit a make programod fog feldolgozni. A .pro fájlok írásáról később még lesz szó. Amennyiben Windows alatt valamit hiányolna a fordítás során, akkor keresd ki a start menüből a Qt Command prompt-ot, és abból futtasd a parancsokat.
További olvasnivalók:
| Miről | Hol |
|---|---|
| Widgetek és ablakok geometriája | Window and Dialog Widgets [doc.qt.nokia.com] |
| Események és a Qt eseménykezelője | The Event System [doc.qt.nokia.com] |
Kilépés gomb hozzáadása
Egy igazi alkalmazásban általában egynél több widgetre van szükséged. Helyezzünk egy QPushButtont [doc.qt.nokia.com] a szövegdoboz alá. Ez arra fog szolgálni, hogy ha a felhasználó rákattint, a program lépjen ki.

Nézzük a kódot:
- #include <QtGui>
- int main(int argv, char **args)
- {
- QTextEdit textEdit;
- QVBoxLayout layout;
- layout.addWidget(&textEdit);
- layout.addWidget(&quitButton);
- QWidget window;
- window.setLayout(&layout);
- window.show();
- return app.exec();
- }
Az első sorban beincludoljuk a QtGui [doc.qt.nokia.com] headert, ami magában foglalja a Qt összes grafikus osztályát.
A tizedik sorban a Qt szignál slot mechanizmusa segítségével lekezeljük a Kilépés gomb megnyomását.
A szlot függvény a futás során hívódik meg a neve segítségével. A szignálok olyan függvények, amelyek a megfelelő esemény bekövetkezésekor automatikusan meghívják a hozzájuk csatlakoztatott slotokat. Esetünkben a quit() [doc.qt.nokia.com] a widgetünk egy beépített slotja, amelyet meghívva az alkalmazás kilép. A gombunk clicked() [doc.qt.nokia.com] szignálja pedig a gomb megnyomásakor emittálódik. A szignál-slot hozzárendelést a statikus QObject::connect() [doc.qt.nokia.com]# függvénnyel hozhatjuk létre. Az argumentumként használt SIGNAL és SLOT makrókban kell megadnunk a megfelelő függvényneveket, azok argumentumainak típusával egyetemben. A connect() függvénynek át kell adni a küldő és fogadó objektumokra mutató mutatókat is.
A 12. sorban egy QVBoxLayout-ot [doc.qt.nokia.com] hozunk létre. Ahogy már említettük a widgetek (szülő widget) tartalmazhatnak további widgeteket (gyermek widgetek). Lehetőségünk van a gyermek widgeteknek pontos méretet, pozíciót megadni, de egyszerűbb, ha ehelyett layoutokat használunk, így a azok fogják kezelni a gyermekwidgetek elrendezését. A QVBoxLayout [doc.qt.nokia.com] például a gyermekeket egy függőleges oszlopba rendezi.
A 13. és 14. sorban hozzáadjuk a szövegdobozunkat és a nyomógombunkat a layouthoz, majd a 17. sorban érvénybe léptetjük az elrendezést.
További olvasnivalók:
| Miről | Hol |
|---|---|
| Szignálok és Szlotok | Signals & Slots [doc.qt.nokia.com] |
| Layoutok | Layout Management [doc.qt.nokia.com], Widgets and Layouts [doc.qt.nokia.com], Layout Examples [doc.qt.nokia.com] |
| A QT beépített widgetkészlete | Qt Widget Gallery [doc.qt.nokia.com], Widget Examples [doc.qt.nokia.com] |
Származtatás a QWidget osztályból
Miután a felhasználó a kilépés gombra kattint, sok esetben érdemes egy megerősítést kérő ablakot megjeleníteni, hogy valóban ki akar-e lépni. Példánkban a QWidget [doc.qt.nokia.com] osztályból származtatjuk a programfelület legfelsőbbb osztályát, és létrehozunk egy slotot, amihez hozzákötjük a Kilépés gomb kattintás szignálját.
Íme a kód:
- {
- Q_OBJECT
- public:
- Notepad();
- private slots:
- void quit();
- private:
- };
A Q_OBJECT makrónak kell az osztálydeklaráció elején lennie. Ez a makró az osztályunkat QObjectként [doc.qt.nokia.com] deklarálja (természetesen a használatához a QObjecttől [doc.qt.nokia.com] kell származtatnunk). Ez a példánkban is így van, hiszen a QWidget osztály a QObjectből van származtatva. A QObject [doc.qt.nokia.com] különféle funkciókkal bővíti ki a C++ osztályok tulajdonságait. Például az osztály és szlotok neve lekérdezhetővé válik futásidőben. Továbbá lehetőség van a szlotok argumentumainak típusát lekérdezni, illetve név alapján meghívni azokat.
A 9. sorban deklaráljuk a quit() szlotot a slots makró segítségével. A slotunkat ezután hozzáköthetjük bármilyen szignálhoz, amelynek nincs argumentuma.
A következőekben létrehozunk egy Notepad osztályt, amelynek a konstruktorában hozzuk létre a felületet, és kötjük össze a slotokat a szignálokkal. Ez megoldás elegánsabb, mint ha ezt a main() függvényben tennénk meg.
- Notepad::Notepad()
- {
- textEdit = new QTextEdit;
- connect(quitButton, SIGNAL(clicked()), this, SLOT(quit()));
- layout->addWidget(textEdit);
- layout->addWidget(quitButton);
- setLayout(layout);
- setWindowTitle(tr("Notepad"));
- }
Amint láthatod mutatókat használunka textEdit és a quitButton elérésére. Az ilyen grafikus elemeket mindig a heapen példányosítjuk, és sohasem másoljuk őket.
Az ablak címét a setWindowTitle metódus segítségével állítjuk be. Amint láthatod a felhasználó számára látható szöveget a tr() [doc.qt.nokia.com] függvényen keresztül adjuk át a függvénynek. Ez a függvény a többnyelvű alkalmazások írásánál nyújt segítséget. Most nem megyünk bele a részletekbe, további információt a Qt Linguist [doc.qt.nokia.com] dokumentációjánál találsz.
További olvasnivalók:
| Miről | Hol |
|---|---|
| tr() és a többnyelvűsítés | Qt Linguist Manual [doc.qt.nokia.com], Writing Source Code for Translation [doc.qt.nokia.com], Hello tr() [doc.qt.nokia.com] Example, Internationalization with Qt [doc.qt.nokia.com] |
| QObject [doc.qt.nokia.com] és a Qt objektummodell-rendszere | Object Model [doc.qt.nokia.com] |
| qmake a Qt build rendszere | qmake Manual [doc.qt.nokia.com] |
Az elkövetkezőkben írunk egy saját .pro fájlt, ahelyett, hogy a qmake-el generáltatnánk le.
- HEADERS = notepad.h
- SOURCES = notepad.cpp \
- main.cpp
A következő parancsokkal tudod lefordítani a példát:
- qmake
- make
A QMainWindow használata
Sok alkalmazás írásakor kézenfekvő lehet a használata, ugyanis ez az osztály egy előre megadott layout-ot tartalmaz, amelyre elhelyezhetjük saját menü sorunkat, eszköztárainkat, a dokkolható widgetek számára rögzítési területet, illetve az állapotsort is.
A QMainWindownak [doc.qt.nokia.com] van egy középső területe, ahol elhelyezhetünk bármilyen widgetet. Esetünkben is ide fog kerülni a szövegdobozunk.

Tekintsük át a Notepad osztály definícióját!
- #include <QtGui>
- {
- Q_OBJECT
- public:
- Notepad();
- private slots:
- void open();
- void save();
- void quit();
- private:
- };
Az elkövetkezendőkben implementálni fogunk két slotot, mely a dokumentum megnyitására és mentésére fog szolgálni.
A fő ablakokban gyakran megesik az, hogy egy szlotot több widget is meghív. Esetünkben a menü egyes elemei és az eszköztár gombjai is ezt teszik. Az ilyen esetek leegyszerűsítésére hozták létre a QAction [doc.qt.nokia.com] osztályt, amelyet átadhatunk több widgetnek is, majd hozzákötjük a megfelelő szlothoz a szignálját. Például a QMenu [doc.qt.nokia.com] és a QToolBar [doc.qt.nokia.com] is létrehozhat menüket, eszköztárelemeket ugyanannak a QAction [doc.qt.nokia.com] -nek a hatására.
Ahogyan már említettük a grafikus elemeket a Notepad osztály konstruktorában inicializáljuk.
- Notepad::Notepad()
- {
- connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
- connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
- connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(openAction);
- fileMenu->addAction(saveAction);
- fileMenu->addSeparator();
- fileMenu->addAction(exitAction);
- textEdit = new QTextEdit;
- setCentralWidget(textEdit);
- setWindowTitle(tr("Notepad"));
- }
A QAction-ök [doc.qt.nokia.com] konstruktorának egy szöveget adunk meg argumentumként. Ez a szöveg fog megjelenni azokon a widgeteken, amelyekhez hozzárendeljük őket (esetünkben a menüelemeken). Ha ugyanazt a funkciót el szeretnénk érni az eszköztárunkról is, akkor az akcióhoz ikont is kell rendelnünk. Tehát ha egy menüre rákattintunk az triggerelni fogja az akciónkat, amely ezáltal a emittálja a triggered() szignálját, amely meghívja a hozzákötött szlotokat.
További olvasnivalók:
| Miről | Hol |
|---|---|
| Főablak és egyéb ablakok | Application Main Window [doc.qt.nokia.com], Main Window Examples [doc.qt.nokia.com] |
| MDI alkalmazások | QMdiArea [doc.qt.nokia.com], MDI Example [doc.qt.nokia.com] |
A következő kódrészletben implementálni fogjuk a mentés és megnyitás kezelésére szolgáló szlotokat.
Kezdjük az open() szlottal:
- tr("Text Files (*.txt);;C++ Files (*.cpp *.h)"));
- if (fileName != "") {
- tr("Could not open file"));
- return;
- }
- textEdit->setPlainText(contents);
- file.close();
- }
Első lépésként bekérjük a felhasználótól a fájl nevét. A Qt-ban direkt erre a feladatra van egy osztály a QFileDialog [doc.qt.nokia.com] , amely egy dialógus megjelenítésére szolgál, amelyből a felhasználó kitallózhatja a kívánt fájlt.

A getOpenFileName() [doc.qt.nokia.com]) statikus metódus egy dialógust jelenít meg (az alkalmazás többi ablaka nem használható ameddig jelen van), és addig nem tér vissza amíg a felhasználó ki nem választott egy fájlt. A visszatérési értékben megkapjuk a fájl elérési útját, vagy egy üres sztringet, ha a felhasználó a mégsem gombra kattintott.
Ha megvan az érvényes fájlnév, akkor megnyitjuk a fájlt a QFile open() [doc.qt.nokia.com] metódusával, amely igazzal tér vissza, ha a megnyitás sikerült. Most nem megyünk bele a hibakezelésbe, de ha érdekel, utána nézhetsz ezeknek a További információ szekcióban. Ha a fájl nem nyitható meg, akkor egy QMessageBox [doc.qt.nokia.com] jelenítjük meg a hibaüzenetet. A részletekért lásd a QMessageBox [doc.qt.nokia.com] osztály súgóját.
Az adatok beolvasása triviális a QFile [doc.qt.nokia.com] readAll() [doc.qt.nokia.com] metódusának köszönhetően. Ez a függvény egy a fájlban lévő adatokat tartlmazó QByteArray [doc.qt.nokia.com] -jel tér vissza. A QByteArray constData() [doc.qt.nokia.com] metódusa segítségével az adatokat const char* formában is elérhetjük, amit már át tudunk adni a QString [doc.qt.nokia.com] konstruktorának. Így a fájl tartalma megjeleníthető a szövegdobozban. Végül a close() [doc.qt.nokia.com] metódussal bezárjuk a fájlt, így adva vissza a fájlleírót az operációs rendszernek.
Most, hogy letudtuk a megnyitás szlotot lássuk a mentést:
- tr("Text Files (*.txt);;C++ Files (*.cpp *.h)"));
- if (fileName != "") {
- // error message
- } else {
- stream << textEdit->toPlainText();
- stream.flush();
- file.close();
- }
- }
Miután megszerkesztettük a szövegdobozunk tartalmát, azt a QTextStream [doc.qt.nokia.com] objektumon keresztül írjuk vissza a fájlunkba. Ez az osztály mintegy ráépül a QFile [doc.qt.nokia.com] objektumunkra, lehetővé téve, hogy a neki küldött szövegeket direktben kiírassuk a fájlunkba.
További olvasnivalók:
| Miről | Hol |
|---|---|
| Fájlok és I/O eszközök | QFile [doc.qt.nokia.com], QIODevice [doc.qt.nokia.com] |

