SDI alkalmazás készítése Qt-ben I...3 Feladat...3 A projekt osztálydiagramja...3 A projekt modulszekezete...4 Új projekt létrehozása...5 A számla megtervezése...5 Vezérlőelemek és paraméterezésük...6 Az InvoicerDoc osztály...7 Az InvoicerDoc osztály definíciója...7 Az InvoicerDoc osztály implementációja...7 Eseménykezelés QAction osztállyal...8 Az InvoicerView osztály...9 Az InvoicerView osztály definíciója...9 Az InvoicerView osztály implementációja...9 Főablak: QMainWindow osztály...10 Az eseménykezelés lépései...10 Egy QAction részletesen - File/New...11 A filenew tevékenység (QAction) deklarációja...11 A filenew tevékenység (QAction) objektum létrehozása és inicializálása (initaction())...11 A filenew tevékenység (QAction) elhelyezése a menüsorban (initmenubar())...12 A filenew tevékenység (QAction) beillesztése az eszköztárba (inittoolbar())...12 A filenew slot definíciója ( slotfilenew() )...12 Az Invoicer osztály...13 Inicializáló műveletek...13 Slotok...13 Adattagok...13 Az Invoicer osztály definíciója...14 Az Invoicer osztály implementációja...15 Tevékenység létrehozása/inicializálása...16 Menüpontok létrehozása és inicializálása...17 Invoicer::initMenuBar()...17 Eszköztár létrehozása és inicializálása...17 Invoicer::initToolBar()...17 Státuszsor inicializálása...18 Invoicer::initStatusBar()...18 Az alkalmazás dokumentum létrehozása és inicializálása...18 Invoicer::initDoc()...18 Az alkalmazás nézet (central widget) létrehozása és inicializálása...18 Invoicer::initView()...18 Kilépés kérdezéssel...18 Invoicer::queryExit()...18 Az Invoicer osztály slotjainak implementációja (vázlat)...19 Invoicer::slotFileNew()...19 Invoicer::slotFileOpen()...19 Invoicer::slotFileSave()...19 Invoicer::slotFileSaveAs()...19 Invoicer::slotFileQuit()...20 1. oldal
Invoicer::slotViewToolBar(bool toggle)...20 Invoicer::slotViewStatusBar(bool toggle)...20 Invoicer::slotHelpAbout()...20 Az alkalmazás főprogramja...21 main.cpp...21 Fordítás/Futtatás...21 Projekt összeállítása Qt parancsokkal...22 A projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa honlapról. 2. oldal
! #" $ #" %& (')+*,$ -#*.'0/213-+*54768139;:(4=<>@? Az SDI alkalmazások készítése Qt-ben I, II, III-ban arra mutatunk példát, hogyan készíthetünk a Qt osztályait felhasználva korszerű, menüvezérelt, ablakos alkalmazást. A projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa címről. ACBEDFGHFJI Készítsünk egy olyan alkalmazást, amely alkalmas számlák (invoice) rögzítésére, karbantartására. Egy számla fejlécből (header) és számlatételek (items) sorozatából áll. A számla fejléce a következő adatokat tartalmazza: várárló neve (customer), vásárló címe: irányítószám (zip), helység (city), utca (street), számla sorszáma (invno), kiállítás dátuma (released), teljesítés dátuma (fulfilled), fizetési határidő (dueto). Egy számlatétel az alábbi összetevőkből áll: megnevezés (name), mennyiségi egység (unit), egységár (unitprice), mennyiség (quantity), nettó ár (netprice=unitprice*quantity), áfakulcs (vatpercent), áfa összege (vat=netprice*vat/1), bruttó ár (grossprice=netprice+vat) A program tegye lehetővé a fenti adatok felvitelét, módosítását, a számlák fájlba történő mentését és azok visszaolvasását. Ebben a munkafüzetben az ismeretek alapos elsajátítása érdekében - a projektet alkotó elemeket kézzel illesztjük be a projektbe, és kézi programozással adjuk meg a forrásprogramok kódját is. KMLON PRQSBUTHIHPWVYXYI[Z\D^]HGH_`FEaON2Fb!QF Projektünket az ún, dokument/view architektúra szerint készítjük el, melyben külön osztály felel az adatokért (doc), és külön osztály az adatok megjelenítéséért (view). A QObject osztályból származtatott InvoicerDoc osztály feladata a számla adatok kezelése. A megjelenítéséért a Qt Designerrel megtervezett InvoicerViewBase osztályból származtatott InvoicerView osztály felel. Az alkalmazás főablakát a QMainWindow osztályból származtatjuk. A QMainWindow osztály az ablakos alkalmazásoknál megszokott, menüvel, státuszsorral, stb. ellátott keretablakot valósítja meg. 3. oldal
cmdoe frgshuihjlkmfjnpowq`rysuhuithesuhtjuh main.cpp invoicer.h invoicerdoc.h invoicerdoc.cpp invoicerview.h invoicerview.cpp A főprogram Az alkalmazás főablakát megvalósító Invoicer osztály Az alkalmazás dokumentumtípusát (számla) megvalósító InvoicerDoc osztály Az alkalmazás főablakának belsejét (a számla megjelenítését) megvalósító InvoicerView osztály. Az InvoicerView osztályt az InvoicerViewBase osztályból fogjuk előállítani származtatással. Az InvoicerViewBase osztályt a Qt Designerrel tervezzük meg, majd a segítségével elkészített invoicerviewbase.ui fájlt beillesztjük a projektünkbe. 4. oldal
vxw!yoz w~ W ƒ uz pt ˆ \ \Š Hozzunk létre egy üres KDevelop/Qt/C++ projektet 1. Ha az Ön által használt fejlesztőeszközben nincs ilyen lehetőség, akkor készítsen el egy tetszőleges, Qt alapú projektet, és törölje a projekt.h és.cpp fájljait. Ezzel elkészül egy olyan projekt környezet, amelybe már beilleszthetjük a saját forrásainkat. (A munkafüzet végén talál egy másik technikát az alkalmazás projekt összeállítására.) Y ˆ Œ ŠŽŒ ; u\z E UƒU t A főablak tartalmát elkészítése. Qt Designer segítségével készítjük el. A cél az alábbi formanyomtatvány (widget) Készítse el a fenti formanyomtatványt, majd mentse el invoicerviewbase.ui néven a projekt könyvtárába. Az alábbi táblázatban felsoroltuk a formanyomtatványon szereplő vezérlőelemeket és azok beállításait. (properities) 1 KDevelop2: Project/New/Qt/Qt SDI/(Project name: Invoicer) /Create KDevelop3: Project/New/C++/Qt Application/Create 5. oldal
Vezérlőelemek és paraméterezésük Customer blokk Vezérlő azonosító Class Properties Megjegyzés TextLabel* QLabel Text: Name:, Buddy: customer Buddy: A Name cimke és a customer szerkesztőmező összerendelése. TextLabel* QLabel Text: Zip:, Buddy: zip TextLabel* QLabel Text: Locality:, Buddy: city TextLabel* QLabel Text: Street:, Buddy: street customer zip city street Invoice blokk QLineEdit QLineEdit QLineEdit QLineEdit Vezérlő azonosító Class Properties Megjegyzés TextLabel* QLabel Text: No:, Buddy: invno TextLabel* QLabel Text: Released:, Buddy: released TextLabel* QLabel Text: Fulfilled:, Buddy: fulfilled TextLabel* QLabel Text: Due to:, Buddy: dueto invno released fulfilled dueto Items blokk QLineEdit QLineEdit QLineEdit QLineEdit items QListView Column:Name/Unit/Qty/Unit Price/Net Price/VAT%/VAT/Price Grandtotal blokk TextLabel* QLabel Text: Grandtotal:, Buddy: sum sum QLineEdit A vezérlőelemre duplát kattintva szerkesztheti a listát. * : A *-gal megjelölt feliratoknál nem kötelező egyedi azonosítót megadni. A Qt Designerrel létrehozott.ui fájlt mentse el a projekt könyvtárába invoicerviewbase.ui néven, majd adja hozzá a fájlt a projekthez: Add Existing File.../invoicer/invoicerviewbase.ui 6. oldal
A projekt összeállításakor az invoicerviewbase.ui fájlból az uic (user interface compiler) elkészíti az InvoicerViewBase osztály forráskódját, melyet az invoicerviewbase.h és az invoicerviewbase.cpp fájlokban helyez el. Nekünk csak az invoicerviewbase.ui fájlt kell beilleszteni a projektbe, a forráskódot tartalmazó fájlokat nem. + # [ šh œ\žyÿ š œ šw Y Y [ Y A Document/View architectura szerint az InvoicerDoc osztály felelősége az alkalmazás adatainak kezelése. Az InvoicerDoc osztály definíciója class InvoicerDoc : public QObject Q_OBJECT public: InvoicerDoc(); ~InvoicerDoc(); void newdoc(); bool save(); bool saveas(const QString &filename); bool load(const QString &filename); bool ismodified() const; signals: void documentchanged(); protected: bool modified; ; invoicerdoc.h A függvények pontos (részletes) működését a III. munkafüzet tartalmazza. Ha megváltozott a dokumentum, jelezzük. Ebben az adattagban tároljuk, hogy változtak-e az adatok. A dokumentum osztályban a modified flag tárolja, megváltozott-e a dokumentum. Adataink megváltozásáról a documentchanged() signál tájékoztatja a külvilágot, lehetővé téve, hogy az abban érdekelt objektumok rákapcsolódhassanak erre a signálra. Így az alkalmazás bezárásakor a nézet osztály figyelmeztetheti a felhasználót, ha megváltoztak az adatok, és azokat még nem mentette el. Az InvoicerDoc osztály implementációja #include "invoicerdoc.h" InvoicerDoc::InvoicerDoc() modified = false; InvoicerDoc::~InvoicerDoc() invoicerdoc.cpp A függvényeket részletesen később adjuk meg. A destruktor üres, hiszen a dokumentum osztály az Invoicer osztály gyereke, így az azzal együtt megszűnik. 7. oldal
void InvoicerDoc::newDoc() //TODO Új dokumentum létrehozása ك.ك ل مكى ى A függvényeket részletesen később adjuk meg. bool InvoicerDoc::save() //TODO Dokumentum elmentése return true; bool InvoicerDoc::saveAs(const QString & /*filename*/) //TODO Dokumentum elmentése más néven return true; bool InvoicerDoc::load(const QString & /*filename*/) //TODO Új dokumentum betöltése emit documentchanged(); return true; bool InvoicerDoc::isModified() const return modified; A load() a fájl betöltésekor szignált küld a dokumentum megváltozásáról. A modified adattagban tároljuk, változtak-e az adataink. 0ªW«W W t«e±u«e² Uª ³ µt [ ¹H m¹wªy±y º\²`²»\² A grafikus alkalmazások általában lehetővé teszik a felhasználó számára, hogy több helyről is kezdeményezhessen egy-egy tevékenységet. Például a fájl mentése tevékenység kezdeményezhető menüből, eszköztárról (toolbar), vagy gyorsbillentyű (accelerator) alkalmazásával is. A QAction osztály a felhasználói felületről kezdeményezhető tevékenységek kezelésére szolgáló osztály. A QAction osztályt alkalmazva a kívánt tevékenységet (action) egyetlen egyszer kell létrehozni, melyet azután az alkalmazásunk különböző helyéről aktivizálhatunk. Aktivizálhatjuk menüből, eszköztárból ill. rendelhetünk hozzá gyorsmenüt. A QAction osztály alkalmazásával a különböző helyről aktivizálható események öszzhangban lesznek egymással. Egy QAction objektumban elhelyezhetünk ikont, menü szöveget, státusz szöveget, what is this szöveget és súgó szöveget (tooltip). Ezeket az adatokat megadhatjuk az esemény létrehozásakor a konstruktorban, vagy futás közben is. Egy QAction lehet állapotváltó esemény (toggle action) pl. Bold toolbar eszközgomb-, vagy parancs (command action) típusú esemény pl. File open menüpont -. A QAction típusú objektum az esemény végrehajtásakor activated() szignált küld. A toggle action típusú QAction objektumok állapotváltáskor egy toggled() szignált is küldenek. 8. oldal
¼+½#¾[ À ÁH Ã\ÄYÅ3ÆtÂ Ä ÇÈÁHÉ ½YÊ[Ë\Ì^Í Az osztály felelősége az alkalmazás felhasználói felületének (nézet) kezelése. Az InvoicerViewBase osztályból származtatással hozzunk létre egy új osztályt InvoicerView néven. Az InvoicerView osztály definíciója #include "invoicerviewbase.h" #include "invoicerdoc.h" invoicerview.h class InvoicerView : public InvoicerViewBase Q_OBJECT public: InvoicerView(QWidget *parent=0, InvoicerDoc* doc=0); ~InvoicerView(); protected slots: void slotdocumentchanged(); ; Az InvoicerView osztály az InvoicerViewBase osztály leszármazottja. A konstruktoron és a destruktoron kívül egyetlen publikus slotot tartalmaz (slotdocumentchanged()), amelyet majd akkor hajtunk végre, ha valamilyen változás történt az adatainkban. Az InvoicerView osztály implementációja #include "invoicerview.h" InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) connect(doc, SIGNAL(documentChanged()), this, SLOT(slotDocumentChanged())); invoicerview.cpp Összekötjük a dokumentum osztály adatainak megváltozását jelző signált a megjelenítésért felelős nézetosztály slotjával. InvoicerView::~InvoicerView() void InvoicerView::slotDocumentChanged() //TODO update the view A slot feladata a nézet megjelenítése/frissítése. A konstruktor implementációjában összekapcsoljuk a dokumentum documentchanged() signálját az InvoicerView osztály aktuális példányának slotdocumentchanged() slotjával. A destruktorban nincs tennivalónk, hiszen terveink szerint ezen osztály egyetlen példánya lesz az alkalmazásunk főablaka, amely az alkalmazás bezárásakor automatikusan megszűnik. 9. oldal
ÎCÏWÐÑJÒ`ÐÓtÔpÕ Ö Ð\ØÙ ÚlØÙpÛCÜ ÝÈÜHÞ ßYà[á\Ò^â A QMainWindow osztály az alkalmazás felhasználói felületéül szolgáló keret ( főablak ), melynek felépítése a következő: Az ábrán megadott függvények segítségével megkapjuk a QMainWindow egyes részeire mutató pointert. E pointerek segítségével helyezhetjük el az ablak alkalmazásspecifikus elemeit. Például a menüsor File menüpontját az alábbi függvénnyel tehetjük rá az ablakra: menubar()->insertitem(tr("&file"), filemenu); ã+ä åuæwåuçmè éwêwëåeäuåuì èuæ ì è;íoèuætåuî Megjegyzés Létrehozunk egy tevékenység objektumot (QAction). Beállítjuk a tevékenység alkalmazásspecifikus adatait (menü szövege, státusz sor szövege, stb.) Létrehozzuk a menüpontot, és elhelyezzük azt az alkalmazás főablakában. Tevékenységet rendelünk a menüponthoz. Összekötjük a tevékenységet az őt kezelő slottal. Megadjuk a slot implementációját. A QAction osztállyal a felhasználó által kezdeményezhető eseményeket kezelhetjük (menüből, eszközgombbal, gyorsbillentyűvel aktivizálható események). Ezeket az eseményeket nevezzük a továbbiakban tevékenységeknek, megkülönböztetve a QEvent osztállyal megadott eseményektől, illetve a felhasználói eseményektől (custom event). 10. oldal
ï ðòñôóõ ötø[ù úhûmü ýeþyÿ tø Uþ û Ẅù Ahhoz, hogy jobban megértsük a QAction működését, nézzük meg közelebbről a File/New menüponthoz rendelt filenew eseményt. A filenew tevékenység (QAction) deklarációja class Invoicer : public QMainWindow Q_OBJECT public: invoicer.h void initactions(); void initmenubar(); void inittoolbar(); public slots: void slotfilenew(); A File/New parancsot kezelő slot. private: InvoicerView *view; InvoicerDoc *doc; QPopupMenu *filemenu; QAction *filenew; A File menüpont deklarációja. A filenew tevékenység deklarációja ; A filenew tevékenység (QAction) objektum létrehozása és inicializálása (initaction()) void Invoicer::initActions() filenew = new QAction(tr("&New"), tr("ctrl+n"), this); filenew->seticonset(qpixmap::frommimesource("new.png")); filenew->setstatustip(tr("creates a new document")); filenew->setwhatsthis(tr("new File\n\nCreates a new document")); connect(filenew, SIGNAL(activated()), this, SLOT(slotFileNew()));... A QAction első paramétere a menü szövege, a második paramétere a gyorsbillentyű. A harmadik paraméter this értéke azt jelzi, hogy a tevékenység objektum az őt létrehozó objektum gyereke. Qt-ben a képek kezelése többféleképpen történhet. Betölthetjük a képet futási időben, beilleszthetjük a forráskódba XPM fájlként, vagy használhatjuk a Qt image collection mechanizmusát. Mi a harmadik lehetőséget választjuk, ezért a projektbe be kell illesztenünk a projektben használt kép fájlokat. A seticonset() függvénnyel állítjuk be a tevékenységhez tartozó ikont. A setstatustip() függvénnyel megadjuk a státusz sorban megjelenítendő szöveget, a setwhatsthis() függvénnyel a What is this eszközgombhoz rendelt rövid ismertető szövegét. A connect metanyelvi paranccsal öszekötjük az esemény aktivizálását jelző signált és az őt kezelő slotot. 11. oldal
A filenew tevékenység (QAction) elhelyezése a menüsorban (initmenubar()) void Invoicer::initMenuBar() // menubar entry filemenu filemenu=new QPopupMenu(); filenew->addto(filemenu); fileopen->addto(filemenu); filemenu->insertseparator(); filesave->addto(filemenu); filesaveas->addto(filemenu); filemenu->insertseparator(); filequit->addto(filemenu); // menubar entry viewmenu viewmenu=new QPopupMenu(); viewmenu->setcheckable(true); viewtoolbar->addto(viewmenu); viewstatusbar->addto(viewmenu); // menubar entry helpmenu helpmenu=new QPopupMenu(); helpaboutapp->addto(helpmenu); // MENUBAR CONFIGURATION menubar()->insertitem(tr("&file"), filemenu); menubar()->insertitem(tr("&view"), viewmenu); menubar()->insertseparator(); menubar()->insertitem(tr("&help"), helpmenu); A filenew tevékenység (QAction) beillesztése az eszköztárba (inittoolbar()) void Invoicer::initToolBar() // TOOLBAR filetoolbar = new QToolBar(this, "File operations"); filenew->addto(filetoolbar); fileopen->addto(filetoolbar); filesave->addto(filetoolbar); filetoolbar->addseparator(); QWhatsThis::whatsThisButton(fileToolbar); A filenew slot definíciója ( slotfilenew() ) void Invoicer::slotFileNew() statusbar()->message(tr("creating new file...")); doc->newdoc(); statusbar()->message(tr("ready.")); 12. oldal
"!$#%'&$$()"*,+ Alkalmazásunk menüpontjai: File: New, Open, Save, SaveAs, Quit View: ToolBar, StatusBar Help: About A menüpontoknak megfelelően az alkalmazásunk főablakául szolgáló Invoicer osztályban az alábbi függvényeket és adatokat definiáljuk. Inicializáló műveletek initaction() initmenubar() inittoolbar() initstatusbar() initdoc() initview() Az alkalmazásban elérhető tevékenységeket reprezentáló QAction objektumok létrehozása Menürendszer felépítése Az eszköztár felépítése A sátuszsor inicializálása Kezdeti dokumentum (InvoicerDoc) létrehozása és inicializálása A nézet (InvoicerView) objektum létrehozása és inicializálása Slotok slotfilenew() slotfileopen() slotfilesave() slotfilesaveas() slotfilequit() slotviewtoolbar() slotviewstatusbar() slothelpabout() Új dokumentum létrehozása Dokumentum olvasása fájlból Dokumentum mentése fájlba Dokumentum mentése fájlba más néven Kilépés Az eszköztár megjelenítése/elrejtése A státuszsor megjelenítése/elrejtése Az About ablak megjelenítése Adattagok doc view menü objektumok tevékenységek Az aktuális dokumentum (InvoicerDoc) objektumra mutató pointer Az aktuális (és egyetlen) nézet (InvoicerView) objektumra mutató pointer QPopupMenu, QToolBar QAction 13. oldal
Az Invoicer osztály definíciója #include <qmainwindow.h> #include "invoicerview.h" class QAction; class Invoicer : public QMainWindow Q_OBJECT public: Invoicer(QWidget *parent = 0, const char *name = 0); private: /** initializes all QActions of the application */ void initactions(); void initmenubar(); void inittoolbar(); void initstatusbar(); void initdoc(); void initview(); bool queryexit(); private slots: void slotfilenew(); void slotfileopen(); void slotfilesave(); void slotfilesaveas(); void slotfilequit(); void slotviewtoolbar(bool toggle); void slotviewstatusbar(bool toggle); void slothelpabout(); private: InvoicerView *view; InvoicerDoc *doc; QPopupMenu *filemenu; QPopupMenu *viewmenu; QPopupMenu *helpmenu; QToolBar *filetoolbar; QAction *filenew; QAction *fileopen; QAction *filesave; QAction *filesaveas; QAction *filequit; QAction *viewtoolbar; QAction *viewstatusbar; QAction *helpaboutapp; ; invoicer.h Az Invoicer osztályt a QMainWindow osztályból származtatva hozzuk létre. Tevékenység objektumok létrehozását és inicializálásaát végző segédfüggvények Kilépésnél, rékérdezünk, biztos-e a dolgában. Deklaráljuk a tevékenység- (esemény-) kezelő slotokat, Deklarálunk egy nézetosztályt és egy dokumentum osztályt. (Doc/View architektura). Megadjuk a menüpontokat és egy eszköztárat. Deklaráljuk azokat az eseményeket (tevékenységeket), amelyeket a felhasználó aktivizálhat az alkalmazás futásakor. Az Invoicer osztály implementációja 14. oldal
#include <qapplication.h> #include <qaction.h> #include <qmenubar.h> #include <qpopupmenu.h> #include <qtoolbar.h> #include <qstatusbar.h> #include <qwhatsthis.h> #include <qstring.h> #include <qpixmap.h> #include <qmsgbox.h> #include <qfiledialog.h> #include <qaccel.h> #include "invoicer.h" Invoicer::Invoicer(QWidget *parent, const char *name) :QMainWindow(parent,name) setcaption(tr("invoicer Version 1.0 ")); // call inits to invoke all other construction parts initactions(); initmenubar(); inittoolbar(); initstatusbar(); initdoc(); initview(); viewtoolbar->seton(true); viewstatusbar->seton(true); A programban használt Qt elemek definíciója. Az Invoicer osztályt a QMainWindow osztályból származtatjuk. Ez lesz az ablak cimkesorában. Létrehozzuk és inicializáljuk az ablak egyes részeit. Inicializáljuk a doumentumot és a nézetet. Az eszköztár és a státuszsor jelenjen meg az ablakon. A konstruktorban létrehozzuk a szükséges widgeteket, inicializáljuk az adatokat kezelő dokumentum osztályt, valamint a nézet osztályt. A felhasználói felületen megjelenített szöveget azért foglaljuk be a tr() függvénybe, mert így a későbbiekben könnyen megvalósíthatjuk, hogy alkalmazásunk többféle nyelvi környezetben is futhasson. - Saját jegyzet 15. oldal
."/'021435/46'7 8'1:9<; 1 = >?/A@CB D E$8"FGHI6H JAHF$;IHKD E";E"8$F void Invoicer::initActions() filenew = new QAction(tr("&New"), tr("ctrl+n"), this); filenew->seticonset(qpixmap::frommimesource("new.png")); filenew->setstatustip(tr("creates a new document")); filenew->setwhatsthis(tr("new File\n\nCreates a new document")); connect(filenew, SIGNAL(activated()), this, SLOT(slotFileNew())); fileopen = new QAction(tr("&Open..."), tr("ctrl+n"), this); fileopen->seticonset(qpixmap::frommimesource("open.png")); fileopen->setstatustip(tr("opens an existing document")); fileopen->setwhatsthis(tr("open File\n\nOpens an existing document")); connect(fileopen, SIGNAL(activated()), this, SLOT(slotFileOpen())); filesave = new QAction(tr("&Save"),tr("Ctrl+S"),this); filesave->seticonset(qpixmap::frommimesource("save.png")); filesave->setstatustip(tr("saves the actual document")); filesave->setwhatsthis(tr("save File.\n\nSaves the actual document")); connect(filesave, SIGNAL(activated()), this, SLOT(slotFileSave())); filesaveas = new QAction(tr("Save &as..."),0,this); filesaveas->setstatustip( tr("saves the actual document under a new filename")); filesaveas->setwhatsthis( tr("save As\n\nSaves the actual document under a new filename")); connect(filesaveas, SIGNAL(activated()), this, SLOT(slotFileSave())); filequit = new QAction(tr("E&xit"), tr("ctrl+q"), this); filequit->setstatustip(tr("quits the application")); filequit->setwhatsthis(tr("exit\n\nquits the application")); connect(filequit, SIGNAL(activated()), this, SLOT(slotFileQuit())); viewtoolbar = new QAction(tr("Tool&bar"), 0, this); viewtoolbar->settoggleaction(true); viewtoolbar->setstatustip(tr("enables/disables the toolbar")); viewtoolbar->setwhatsthis(tr("toolbar\n\nenables/disables the toolbar")); connect(viewtoolbar, SIGNAL(toggled(bool)), this, SLOT(slotViewToolBar(bool))); viewstatusbar = new QAction(tr("&Statusbar"), 0, this); viewstatusbar->settoggleaction(true); viewstatusbar->setstatustip(tr("enables/disables the statusbar")); viewstatusbar->setwhatsthis( tr("statusbar\n\nenables/disables the statusbar")); connect(viewstatusbar, SIGNAL(toggled(bool)), this, SLOT(slotViewStatusBar(bool))); helpaboutapp = new QAction(tr("&About..."), 0, this); helpaboutapp->setstatustip(tr("about the application")); helpaboutapp->setwhatsthis(tr("about\n\nabout the application")); connect(helpaboutapp, SIGNAL(activated()), this, SLOT(slotHelpAbout())); 16. oldal
d LNM4OQP$RTSOVU SWYXZ5U [?M4\QS ] ^"_"àz2_nbiob cab`"xbk] ^"X^"_$` A tevékenységek meghatározása után létrehozzuk az alkalmazás menüpontjait és eszköztárait, majd hozzárendeljük a menüpontokat ill. eszközgombokat a tevékenységekhez. e f$gihkj2l5monnhke5hqpsrtl"e5uvqw myx z void Invoicer::initMenuBar() // menubar entry filemenu filemenu=new QPopupMenu(); filenew->addto(filemenu); fileopen->addto(filemenu); filemenu->insertseparator(); filesave->addto(filemenu); filesaveas->addto(filemenu); filemenu->insertseparator(); filequit->addto(filemenu); // menubar entry viewmenu viewmenu=new QPopupMenu(); viewmenu->setcheckable(true); viewtoolbar->addto(viewmenu); viewstatusbar->addto(viewmenu); // menubar entry helpmenu helpmenu=new QPopupMenu(); helpaboutapp->addto(helpmenu); // MENUBAR CONFIGURATION menubar()->insertitem(tr("&file"), filemenu); menubar()->insertitem(tr("&view"), viewmenu); menubar()->insertseparator(); menubar()->insertitem(tr("&help"), helpmenu); V $~ $ ' Vƒ? 4 Q " "â 2 N Ši A ˆ"ƒ K "ƒ " "ˆ Œ Ž$ i k 2 5 o K 5 q ' i C 5 yš void Invoicer::initToolBar() // TOOLBAR filetoolbar = new QToolBar(this, "file operations"); filenew->addto(filetoolbar); fileopen->addto(filetoolbar); filesave->addto(filetoolbar); filetoolbar->addseparator(); QWhatsThis::whatsThisButton(fileToolbar); 17. oldal
œž Ÿi ' $ ' V I i A " Ÿ$ IŸ$ " ª«$ i k 2 5±o²² K«5 q³µ ³ 2³ 5¹$ºQ ±y»¼ void Invoicer::initStatusBar() //STATUSBAR statusbar()->message(tr("ready."), 2000); ½¾ "ÀIÁ$ "ÀI 4¾ Ã"ÄÆÅÈÇÁ É Ê4ËVÌ É ÒÓ Ô$ÕiÖk 2Ø5ÙoÚÚÖKÓ5ÖqÛsÜCÕ ÝÞ À Í Ì Î?Ê4ÏQÇ ¾ Ã"Ä$ aíaänðiëiðñ2ði $ÀIÐK¾ Ã"ÀÃ"Ä$ void Invoicer::initDoc() doc=new InvoicerDoc(); Részletesen később. ßàá"âIã$á"âIä á4à å"æèçqé2àaê ëiìyí"êaçvë îsá"âqïñðò"ó%ê ëkôõâé5ë î?ê4öq à å"æ$áaéaænðiçð í2ðiá$âiðkà å"âå"æ$á øù ú$ûiüký2þ5ÿ ükù5ü Tükþ void Invoicer::initView() // set the main widget here view=new InvoicerView(this, doc); setcentralwidget(view); Részletesen később.!"$#&%('*) +-,..0/21&+-, 324-5'*687 9 bool Invoicer::queryExit() int exit=qmessagebox::information(this, tr("quit..."), tr("do your really want to quit?"), QMessageBox::Ok, QMessageBox::Cancel); if (exit==qmessagebox::ok) return true; else return false; Az alkalmazás bezárásakor rákérdezünk, biztosan befejezte-e a munkát. Részletesen később. 18. oldal
:<;>=@?BÄ C2D EF&GCIH&;&J@KLNMOHL CPJ QSRDT?URVWDTXOYZL FX[F\?ZJ@KIE D ]^QSR`_aAbK\;$LTR2J*c Ebben a fejezetben megadjuk az alkalmazás által kezelt slotok minimális vázát. Ahogy haladunk előre a feladat megoldásában, úgy fogjuk kibővíteni az egyes slotok funkcióit. de$f&g(h*i j-k l ltm nogprqhnn*j-stj uwv x void Invoicer::slotFileNew() statusbar()->message(tr("creating new file...")); doc->newdoc(); statusbar()->message(tr("ready.")); yz$& (*~ - T ƒo r Nƒ* ˆ z\ Š void Invoicer::slotFileOpen() statusbar()->message(tr("opening file...")); QString filename = QFileDialog::getOpenFileName(0,0,this); if (!filename.isempty()) doc->load(filename); setcaption(filename); QString message=tr("loaded document: ")+filename; statusbar()->message(message, 2000); else statusbar()->message(tr("opening aborted"), 2000); Részletesen később. Œ$ &Ž( * - T ož r N * Ũ $ & š void Invoicer::slotFileSave() statusbar()->message(tr("saving file...")); doc->save(); statusbar()->message(tr("ready.")); œ $ž&ÿ( * - T oÿ r N * Uª$ž& «b void Invoicer::slotFileSaveAs() statusbar()->message(tr("saving file under new filename...")); QString fn = QFileDialog::getSaveFileName(0, 0, this); if (!fn.isempty()) doc->saveas(fn); else statusbar()->message(tr("saving aborted"), 2000); statusbar()->message(tr("ready.")); Részletesen később. Részletesen később. 19. oldal
$±&²(³* µ- T ¹o²ºr»³N¹*µ ¼¾½-³*º8 À void Invoicer::slotFileQuit() statusbar()->message(tr("exiting application...")); // exits the Application if(doc->ismodified()) if(queryexit()) qapp->quit(); else qapp->quit(); ; statusbar()->message(tr("ready.")); ÁÂ$Ã&Ä(Å*Æ Ç-È É ÉTÊ ËoÄÌ ÍÎÅ*Ç ÏÑÐ2Ä-Ä(ËÒtÓÈ8ÔÖÕ\ÄÄ2ËÌ8Ä (Ë*Ç Ø void Invoicer::slotViewToolBar(bool toggle) statusbar()->message(tr("toggle toolbar...")); if (toggle== false) filetoolbar->hide(); else filetoolbar->show(); statusbar()->message(tr("ready.")); ÙÚ$Û&Ü(Ý*Þ ß-à á átâ ãoüä åîý*ß æèçuä é äöêâ&ëté-àíìöî\ü-ü(ãä8üïï(ã*ß ð void Invoicer::slotViewStatusBar(bool toggle) statusbar()->message(tr("toggle statusbar...")); if (toggle == false) statusbar()->hide(); else statusbar()->show(); statusbar()->message(tr("ready.")); ñò$ó&ô(õ*ö -ø ù ùtú ûoôürýt &û0þ$ÿ ô \ü void Invoicer::slotHelpAbout() QMessageBox::about(this,tr("About..."), trutf8("invoicer\nversion 1.0 \n(c) 2004 by Szabóné Rozália") ); Nacsa A trutf8 függvény jól konvertálja az ékezetes karaktereket is. 20. oldal
=!#"%$'&(" Végül készítsük el alkalmazásunk főprogramját. main.cpp #include <qapplication.h> main.cpp #include "invoicer.h" int main(int argc, char *argv[]) QApplication app(argc, argv); Invoicer *invoicer=new Invoicer(); app.setmainwidget(invoicer); invoicer->show(); return app.exec(); A főprogramban létrehozzuk a QApplication típusú app objektumot. (Ilyen objektumból csak egy lehet minden alkalmazásban!). Mivel a Qt alkalmazás is képes parancssori paraméterek kezelésére, ezért átadjuk neki a main függvény argumentumait. A szabad tárterületen (heap) létrehozzuk az alkalmazásunk főablakának egy példányát (invoicer), az alkalmazásunknak jelezzük, hogy ez lesz a főablak, majd megjelenítjük a főablakot. A főablak bezárásakor minden, a főablakban létrehozott objektum törlődik, ezért itt nem szükséges a new mellett a delete használata. Ezután futtatjuk (exec) az alkalmazást. Az alkalmazás futása azt jelenti, hogy fut egy üzenetkezelő ciklus, amely várakozik a neki szóló események bekövetkezésére. (A többnyelvű alkalmazás készítését később mutatjuk meg.) )+*-,/. 021435768)-9:1;14< 1435 Ha lefordítjuk és összeszerkesztjük a projektet, majd futtatjuk azt, akkor a főabklakban megjelenik a számla. Ezen a ponton kisérletezhetünk az egyes vezérlőelemek viselkedésével. Figyelje meg a státusz sorban megjelenő szövegeket. Nézze meg mi történik, ha a File/Open parancsot adja ki. Természetesen ezzel még nem készült el a teljes alkalmazás. A feladat további részét az SDI alkalmazás készítése Qt-ben II, III munkafüzetekben mutatjuk meg. Saját jegyzet 21. oldal
>? @BADCEGFGHJIIKLCNMOPOQ2F4MIRTSFUVRJ?WR%X:YLIJ@GEERO A projektet összeállíthatja a Qt parancssori eszközeivel is. 1. Hozzon létre a projekt számára egy könyvtárat: invoicer 2. Hozza létre (vagy a honlapomról töltse le) az alábbi fájlokat: main.cpp, invoicer.h,, invoicerdoc.h, invoicerdoc.cpp, invoicerview.h, invoicerview.cpp, invoicerviewbase.ui. 3. Hozza létre a projekt könyvtárában az images könyvtárat, és másolja oda az ikonok kép fájljait: new.png, open.png, save.png 4. Nyisson meg egy terminál ablakot. Legyen a projekt könyvtárban (invoicer). 5. Hozza létre a platformfüggetlen projekt fájlt (invoicer.pro): qmake -project 6. A képek (ikonok) alkalmazása miatt az automatikusan generált projekt fájlt (invoicer.pro) egészítse ki az alábbiak szerint: ###################################################################### # Automatically generated by qmake (1.06c) Sun Mar 21 17:41:49 2004 ###################################################################### TEMPLATE = app INCLUDEPATH +=. # Input HEADERS += invoicer.h invoicerdoc.h invoicerview.h INTERFACES += invoicerviewbase.ui SOURCES += invoicerdoc.cpp invoicerview.cpp main.cpp IMAGES = images/new.png\ images/open.png\ images/save.png 7. Hozza létre a platform függő make fájlt: qmake invoicer.pro 8. Fordítsa/Szerkessze a programot: make 9. Futtassa a programot:./invoicer A projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa honlapról. 22. oldal