...2 Feladat...2 A dokumentum típus módosítása...2 A fejlécet ábrázoló mezők deklarálása...3 Mező lekérdező műveletek...3 Mező beállító slotok...3 Az adatbeviteli mezők és az adattagok összekötése...4 Számlatételek kezelése...4 Az InvoiceItem osztály...5 Az InvoiceItem osztály definíciója és (!) implementációja...5 A dokumentum osztály számlatétel listája (_items)...6 Új számlatétel felvitele...6 Új dialógusablak létrehozása...6 A dialógusablak felépítése...7 A dialógusablak paraméterezése...7 A dialógusablakon elhelyezett elemek paraméterezése...7 Új menüpont elhelyezése az alkalmazásban (Items/New)...8 Az itemsnew tevékenység és az azt kezelő slot definíciója...8 Az itemsnew tevékenység objektum létrehozása és inicializálása...9 Az itemsnew tevékenység beillesztése a menübe...9 A slotitemsnew() implementálása...10 Új tétel beillesztése a számlába...11 Új tétel hozzáadása a dokumentumhoz (számlához)...12 Új számlatétel megjelenítése a nézet tétellistájában...12 Számlatétel módosítása...13 Számlatétel felismerése...14 Új sor típus bevezetése származtatással (ListViewInvoiceItem)...14 A ListViewInvoiceItem beágyazott osztály definíciója és implemetációja...15 Új menüpontok elhelyezése az alkalmazásban (Items/Edit; Items/Remove)...16 A itemsedit/itemsremove tevékenységek deklarációja...16 Az itemsedit és itemsremove tevékenység objektumok létrehozása és inicializálása...17 Az itemsedit és itemsremove tevékenységek beillesztése a menübe...17 Az itemsedit slot implementációja (slotitemsedit() )...17 Az itemsremove slot implementációja (slotitemsremove())...19 Új műveletek a dokumentum osztályban (setmodified(), removeitem())...19 Ami még hátra van...19 Projekt összeállítása Qt parancsokkal...20 A munkafüzet programjai letölthetők a people.inf.elte.hu/nacsa/eaf3/projects/2005/invoicer2 címről. A munkafüzetben bemutatott programok készítésekor KDevelop 3.0.2 - t és Qt 3.3.1 - et használtam. Készítette: Szabóné Nacsa Rozália email: nacsa@inf.elte.hu honlap: people.inf.elte.hu/nacsa Budapest, 2006 május 1. oldal
Ebben a munkafüzetben feltételezzük, hogy Ön már feldolgozta a C++/Qt alapú SDI alkalmazás készítése I munkafüzetet. Az előző munkafüzetben elkészítettünk egy SDI alkalmazást Qt-ben, továbbá a Qt Designer segítségével felépítettük a view osztály felhasználói felületét. Feladat 1. A számla típus (doc) és a hozzátartozó számlatétel típus megvalósítása 2. A számla és a view összekötése 3. Számlatétel felvitele, javítása, törlése 4. Számla mentése, beolvasása A dokumentum típus módosítása Alkalmazásunk dokumentuma maga a számla, ezért az előző munkafüzetben elkészített általános dokumentum osztály kibővítésével készítjük el a számlát reprezentáló dokumentum osztályt. A dokumentum osztály privát részébe felvesszük a számla fejlécébe tartozó mezőket, a publikus részben elhelyezzük e mezők értékeit lekérdező műveleteket, valamint a mezők értékeit beállító slotokat. 2. oldal
A fejlécet ábrázoló mezők deklarálása class InvoicerDoc : public QObject protected: bool modified; QString _customer; QString _zip; QString _city; QString _street; QString _invno; QString _released; QString _fulfilled; QString _dueto; ; Mező lekérdező műveletek class InvoicerDoc : public QObject Q_OBJECT public: bool ismodified() const; const QString customer() const return _customer; const QString zip() const return _zip; const QString city() const return _city; const QString street() const return _street; const QString invno() const return _invno; const QString released() const return _released; const QString fulfilled() const return _fulfilled; const QString dueto() const return _dueto; ; Mező beállító slotok class InvoicerDoc : public QObject signals: void documentchanged(); public slots: void setcustomer(const QString &txt) _customer=txt; void setzip(const QString &txt) _zip=txt; void setcity(const QString &txt) _city=txt; void setstreet(const QString &txt) _street=txt; void setinvno(const QString &txt) _invno=txt; void setreleased(const QString &txt) _released=txt; void setfulfilled(const QString &txt) _fulfilled=txt; void setdueto(const QString &txt) _dueto=txt; ; invoicerdoc.h invoicerdoc.h invoicerdoc.h 3. oldal
Az adatbeviteli mezők és az adattagok összekötése A view osztályban megvalósított számla fejlécében szereplő adatbeviteli mezőket hozzákötjük a dokumentum megfelelő adattagjaihoz. Ehhez a signal/slot mechanizmust használjuk. Az összekötéseket a view osztály konstruktorában helyezzük el. #include <qlineedit.h> InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : //invoicerview.cpp InvoicerViewBase(parent) connect(doc, SIGNAL(documentChanged()), this, SLOT(slotDocumentChanged())); invoicerview.cpp A connect-ben szerepl ő változók Q LineEdit típusúak, így az ezt definiáló fájlt be kell illeszteni a forrásfájlunkba. connect(customer, SIGNAL(textChanged(const QString&)), doc, SLOT(setCustomer(const QString&))); connect(zip, SIGNAL(textChanged(const QString&)), doc, SLOT(setZip(const QString&))); connect(city, SIGNAL(textChanged(const QString&)), doc, SLOT(setCity(const QString&))); connect(street, SIGNAL(textChanged(const QString&)), doc, SLOT(setStreet(const QString&))); connect(invno, SIGNAL(textChanged(const QString&)), doc, SLOT(setInvNo(const QString&))); connect(released, SIGNAL(textChanged(const QString&)), doc, SLOT(setReleased(const QString&))); connect(fulfilled, SIGNAL(textChanged(const QString&)), doc, SLOT(setFulfilled(const QString&))); connect(dueto, SIGNAL(textChanged(const QString&)), doc, SLOT(setDueTo(const QString&))); Számlatételek kezelése A számlatételek ábrázolására bevezetjük az InvoiceItem osztályt. Az osztályt a dokumentum osztállyal egy moduban definiáljuk (invoicerdoc.h). Az osztályba felvesszük a számlatétel adatait tartalmazó mezőket, a hozzájuk tartozó lekérdező függvényeket, a számítással meghatározható jellemzőket visszaadó műveleteket, valamint egy konstruktort. A számlatételek adatait is el kell tárolnunk a dokumentumban, ezért az InvoiceItem osztály elkészülte után az InvoiceDoc számla osztály adattagjai közé felveszünk egy új adattagot, a számlatételeket tartalmazó listát. A számlatétel elemei: megnevezés: _name (adatttag) mennyiségi egység: _unit (adatttag) egységár: _unitprice (adatttag) mennyiség: _quantity (adatttag) nettó ár: _netprice=unitprice*_quantity (számított adat) áfakulcs: _vatpercent (adatttag) áfa összege: _vat=_netprice*_vat/100 (számított adat) bruttó ár: _grossprice=netprice+_vat (számított adat) 4. oldal
Az InvoiceItem osztály Az InvoiceItem osztály definícióját is(!) és implementációját is(!) a dokumentum osztály definíciós fájljában (invoicerdoc.h) adjuk meg. Egészítsük ki az invoicerdoc.h fájlt az alábbiak szerint. Az InvoiceItem osztály definíciója és (!) implementációja class InvoiceItem public: InvoiceItem(QString n=qstring::null, QString u=qstring::null, int q=0, int up=0, int vat=0): _name(n), _unit(u), _quantity(q), _unitprice(up), _vatpercent(vat) void update(qstring n=qstring::null, QString u=qstring::null, int q=0, int up=0, int vat=0) _name=n; _unit=u; _quantity=q; _unitprice=up; _vatpercent=vat; const QString& name() return _name; const QString& unit() return _unit; int quantity() return _quantity; int unitprice() return _unitprice; int vatpercent() return _vatpercent; //Bruttó ár int allvalue() const return _quantity*_unitprice*(100+_vatpercent)/100; invoicerdoc.h A konstruktorban inicializáljuk az I n voiceitem adattagjait. V alamennyi adattagnak van alapértelmezett kezdőértéke. Az update() tagfüggvénnyel a paraméterek alapján aktualizáljuk az adatokat. A lekérdez ő mű veletek olyan egyszerű ek, hogy ezeket inline módon adjuk meg. I tt következnek a számított adatok aktuális értékét visszaadó függvények. //nettó ár int netvalue() const return _quantity*_unitprice; //áfa összege int vatvalue() const return _quantity*_unitprice*_vatpercent/100; //adattagok private: QString _name; QString _unit; int _quantity; int _unitprice; int _vatpercent; ; 5. oldal
A dokumentum osztály számlatétel listája (_items) Az InvoicerDoc osztály adattagjai közé felveszünk egy InvoiceItem típusú elemeket tartalmazó listát. A Qt Assistant segítségével nézze meg a QPtrList osztály tagfüggvényeit. // application specific includes #include <qptrlist.h> class InvoicerDoc : public Qobject invoicerdoc.h ; public: const QPtrList<InvoiceItem>& items() const return _items; protected: QPtrList<InvoiceItem> _items; Új számlatétel felvitele A számlatétel felvitelére készítünk egy dialógusablakot. Ehhez a szokásos módon egy.ui kiterjesztésű user interface fájlt adunk a projekthez. A fájl neve legyen invitemdia.ui, és származtassuk azt a QDialog osztályból. Új dialógusablak létrehozása A számlatétel dialógusablakát a Qt Designer segítségével készítjük el a szokásos módon. A cél az alábbi párbeszédablak létrehozása. 6. oldal
A dialógusablak felépítése A vezérlőelemek típusát és tulajdonságait az alábbi táblázat tartalmazza. A dialógusablak paraméterezése Vezérlő azonosító Class Properties Megjegyzés InvItemDia QDialog Caption: New Item A dialógusablakon elhelyezett elemek paraméterezése Vezérlő azonosító Class Properties Megjegyzés TextLabel* QLabel Text: Name:, Buddy: itemname TextLabel* QLabel Text: Unit:, Buddy: unit TextLabel* QLabel Text: Unit price::, Buddy: unitprice TextLabel* QLabel Text: Quantity:, Buddy: quantity TextLabel* QLabel Text: Vat %:, Buddy: vatpercent itemname unit unitprice quantity QLineEdit QLineEdit QLineEdit QLineEdit vatpercent QComboBox ** okpushbutton QPushButton Text: OK Az OkPushButton gomb clicked() signálját kössük össze az InvItemDia dialógusablak accept() slotjával. cancelpushbutton QPushButton Text: Cancel A cancelpushbutton gomb clicked() signálját kössük össze az InvItemDia dialógusablak reject() slotjával. * : A *-gal megjelölt feliratoknál nem kötelező egyedi azonosítót megadni. ** Az áfa kulcsot legördülő listából választjuk ki. A legördülő lista létrehozására a QComboBox osztályt választottuk. A lista szerkesztéséhez a vezérlőelem felett a jobb egérfülre kattintva a felkínált helyi menüből választhatja ki az Edit menüpontot. 7. oldal
Új menüpont elhelyezése az alkalmazásban (Items/New) Az egyes számlatételek kezeléséért felelős dialógusablak behívására bevezetünk egy új menüpontot, amit a főmenübe illesztünk be. Egészítsük ki alkalmazásunkat az Item/New menüponttal. File: New, Open, Save, SaveAs, Quit Item: New View: ToolBar, StatusBar Help: About Az új menüpont bevezetésével kapcsolatban az alábbiakat kell megtennünk: 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.) Összekapcsoljuk a tevékenységet és az őt kezelő slotot. Létrehozzuk az új menüpontot, majd ráhelyezzük az alkalmazás főablakára. Hozzárendeljük a tevékenységet a menüponhoz. Megadjuk a slot implementációját. Az itemsnew tevékenység és az azt kezelő slot definíciója class Invoicer : public QMainWindow private slots: void slotfilenew(); /* application specific slots*/ void slotitemsnew(); invoicer.h A tevékenységet implementáló slot deklarációja private: QAction *helpaboutapp; /* application specific actions */ QAction *itemsnew; A z Új tétel felvitele tevékenységet definiáló QAction deklarációja. ; Saját jegyzet 8. oldal
Az itemsnew tevékenység objektum létrehozása és inicializálása /** initializes all QActions of the application */ void Invoicer::initActions() filequit = new QAction(tr("Exit"), tr("e&xit"), 0, this); filequit >setstatustip(tr("quits the application")); filequit >setwhatsthis(tr("exit\n\nquits the application")); connect(filequit, SIGNAL(activated()), this, SLOT(slotFileQuit())); itemsnew = new QAction(tr("Insert new item"),tr("&new item"), 0, this); itemsnew >setstatustip(tr("insert a new item into the invoice")); itemsnew >setwhatsthis( tr("new Item\n\nEnables/Insert a new item into the invoice")); connect(itemsnew, SIGNAL(activated()), this, SLOT(slotItemsNew())); invoicer.cpp A Q Action objektum inicializálása, befűzése, összekötése. A QAction első paraméterében megadjuk az új menü szövegét, a második paraméterében a gyorsbillentyűt és az eszközgomb szöveget. A harmadik paraméter this értékével azt jelezzük, hogy a tevékenység a főablak gyereke. Beállítjuk a súgó szöveget (status tip), a What is this szöveget, majd összekötjük a tevékenységet az őt kezelő slottal (slotitemsnew()) Az itemsnew tevékenység beillesztése a menübe Létrehozzuk az itemsmenu legördülő menü példányt, majd hozzáadjuk az itemsnew tevékenységet, végül a menüt befűzzük a menüsorba. class Invoicer : public QmainWindow /* application specific slots*/ void slotitemsnew(); invoicer.h private: QPopupMenu *filemenu; QPopupMenu *itemsmenu; QPopupMenu *viewmenu; Az I tems menüpont deklarációja. /* application specific actions */ QAction *itemsnew; ; 9. oldal
void Invoicer::initMenuBar() // menubar entry itemsmenu itemsmenu=new QPopupMenu(); itemsnew >addto(itemsmenu); /////////////////////////////////////////////////////////////////// // MENUBAR CONFIGURATION menubar() >insertitem(tr("&file"), filemenu); menubar() >insertitem(tr("&items"), itemsmenu); menubar() >insertitem(tr("&view"), viewmenu); menubar() >insertseparator(); menubar() >insertitem(tr("&help"), helpmenu); A slotitemsnew() implementálása Az új számlatétel felvitelekor az alábbi tevékenységeket kell elvégezni: invoicer.cpp Létrehozzuk az I tem menüpontot, és beledobjuk az itemsne w tevékenységet. A z I tems menüpontot beillesztjük a menüsorba. dialógusablak létrehozása dialógusablak modális 1 megjelenítése ha a dialógust OK-val zárták: a bevitt adatok kinyerése a dialógusablakból új számlatétel (InvoiceItem) objektum hozzáadása a számlához a számlatételeket megjelenítő QListView (items) frissítése a view objektumban. #include "invitemdia.h" #include "qlineedit.h" #include "qcombobox.h" void Invoicer::slotItemsNew() statusbar() >message(tr("inserting a new invoice item...")); InvItemDia dlg(this,0,true); if (dlg.exec() == QDialog::Accepted) doc >insertitem(new InvoiceItem(dlg.itemName >text(), dlg.unit >text(), dlg.quantity >text().toint(), dlg.unitprice >text().toint(), dlg.vatpercent >currenttext().toint))); statusbar() >message (tr("item added. ")); else statusbar() >message(tr("cancelled")); invoicer.cpp Ne feledkezzen meg az include-okról!!! A z insert Item() függvényt még meg kell írni! 1 Modális megjelenítés: A párbeszédablak lesz az alkalmazás aktív ablaka mindaddig, amig be nem zárjuk azt. 10. oldal
A slotitemsnew() slot implementációjában létrehoztuk az InvItemDia dialógusablak egy példányát. A konstruktor első paramétere azt mondja meg, hogy a dialógusablak az Invoicer osztály gyermeke. A harmadik paraméter true értéke jelzi, hogy a dialógusablakot modálisan szeretnénk használni. Ha a felhasználó az OK gombra kattintva lépett ki a dialógusból, akkor az ott létrehozott tételt beszúrjuk a dokumentumba az insertitem() függvény segítségével. A státusz sorban megjelenik az Item added üzenet. Ha a felhasználó a Cancel gombra kattintott, akkor ezt a tényt a státuszsorban jelezzük, de ilyenkor nincs semmi tennivalónk. Új tétel beillesztése a számlába Amikor a számlatétel felbukkanó dialógusablakában megadtunk egy új tételt, és rákattintottunk az OK gombra, akkor egyrészt az új számlatétel adatait át kell adni az adatokért felelős doc-nak, másrészt a megjelenítésért felelős view-ban frissíteni kell a módosított sort. Először is a dokumentum osztályban bevezetünk egy új publikus függvényt (insertitem()), melyet majd meghívhatunk az Invoicer-ből az OK lenyomása után. (doc->insertitem()). Az insertitem() függvény egyrészt beilleszti az új számlatételt a dokumentumba, másrészt kibocsájtja az iteminserted() signalt (emit signal), jelezvén a külvilág számára, hogy ő beillesztett egy új számlatételt, azaz megváltoztak az adatai. Az InvoicerView osztályban elkészítjük a fenti signál fogadására alkalmas slotdocitemadded() slotot, és összekötjük azt az insertitem() függvényben kibocsájtott iteminserted() signállal. A slotdocitemadded() függvény feladata lesz az új számlatétel megjelenítése. Saját jegyzet 11. oldal
Új tétel hozzáadása a dokumentumhoz (számlához) class InvoicerDoc : public QObject Q_OBJECT public: const QPtrList<InvoiceItem>& items() const return _items; ; void insertitem(invoiceitem *i) _items.append(i); modified=true; emit iteminserted(i); signals: void documentchanged(); void iteminserted(invoiceitem *i); protected: QPtrList<InvoiceItem> _items; invoicerdoc.h A függvénydefiníciót inline módon adtuk meg. H a egy számlatételt beillesztettünk az _items listába, signált bocsájtunk ki. A signál a paraméterén keresztül átadja a számlatételre mutató pointert. Új számlatétel megjelenítése a nézet tétellistájában class InvoicerView : public InvoicerViewBase Q_OBJECT public: InvoicerView(QWidget *parent=0, InvoicerDoc* doc=0); ~InvoicerView(); protected slots: void slotdocumentchanged(); void slotdocitemadded(invoiceitem*); ; invoicerview.h Deklaráljuk a slot Doc ItemAdded() slotot, amelyre majd rákötjük az iteminserted() signalt. InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) connect(doc, SIGNAL(documentChanged()), this, SLOT(slotDocumentChanged())); connect( doc,signal(iteminserted(invoiceitem*)), this,slot(slotdocitemadded(invoiceitem*))); invoicerview.cpp Összekötjük a dokumentum osztály iteminserted() szignálját a nézet osztály (this) slot DocItemAdded() slotjával. 12. oldal
#include <qlistview.h> void InvoicerView::slotDocItemAdded(InvoiceItem* i) new QListViewItem(items, i >name(), i >unit(), QString::number(i >quantity()), QString::number(i >unitprice()), QString::number(i >netvalue()), QString::number(i >vatpercent()), QString::number(i >vatvalue()), QString::number(i >allvalue()) ); invoicerview.cpp Slot implementáció A dokumentum iteminserted() signáljától kapott számlatétel adatai alapján a QListViewItem konstruktora segítségével az items listához hozzávesszük az új számlatételt. A QListViewItem típus használata miatt az InvoicerView osztályba be kell illeszteni a QListView osztály definícióját. (#include <qlistview.h>) Fordítás/Futtatás Számlatétel módosítása Számlatétel módosításakor az alábbi teendőnk van: * a kiválasztott sorhoz tartozó számlatétel meghatározása dialógusablak létrehozása * a dialógusablak feltöltése a számlatételből dialógusablak modális megjelenítése ha a dialógust OK-val zárták: a bevitt adatok kinyerése a dialógusablakból * a számlatétel (InvoiceItem) objektum módosítása a számlában a számlatételeket megjelenítő QListView (items) frissítése a view objektumban. Vegye észre, hogy a számlatétel módosítása nagyon hasonlít az új számlatétel felvitele feladathoz, ezért csak a *-gal megjelölt lépéseket kell többletként megoldani. Saját jegyzet 13. oldal
Számlatétel felismerése A számlatételek módosításakor a nézet osztályban (InvoicerView) megjelenített listából kiválasztott sort (számlatételt) kell módosítani. Ehhez tudnunk kell, hogy a QListView (items) kiválasztott sora a ListViewItem lista melyik elemére (_items egy eleme) vonatkozik. Egy listában szereplő elem (sor) azonosítására általában többféle megoldás is kínálkozik. Azonosíthatjuk a sort a kijelölt sor tartalma alapján, de ez több egyforma sor esetén nem egyértelmű. Meghatározhatjuk a számlatételt a kijelölt sor sorszáma alapján. Ez azért nehézkes, mert egyrészt a ListView-ban az elemek sorrendje felcserélhető, másrészt egy-egy tétel törlése sok adminisztrációt kíván. Az előzőeknél általánosabb és elegánsabb megoldást kapunk, ha a QListView osztályból származtatunk egy saját sor típust, és ezt összekötjük a neki megfelelő InvoiceItem objektummal. Esetünkben a nézet osztályban kiválasztott sor (számlatétel) tartalma alapján nem tudjuk eldönteni, hogy az az _items lista melyik elemét jeleníti meg, ezért mi a harmadik megoldást választjuk. Új sor típus bevezetése származtatással (ListViewInvoiceItem) A ListViewInvoiceItem osztály felelősége a hozzá tartozó számlatétel megjelenítése. A ListViewInvoiceItem osztályt a QListViewItem osztályból származtatjuk. Az új osztályt kibővítjük egy új adattaggal (egy InvoiceItem-re mutató pointerrel), így minden ListViewInvoiceItem típusú példány tudja magáról, hogy a doc-ban tárolt lista mely adatát reprezentálja. Az új sor típust beágyazzuk az ImvoicerView osztályba!! Saját jegyzet 14. oldal
A ListViewInvoiceItem beágyazott osztály definíciója és implemetációja //include files for Qt #include <qlistview.h> invoicerview.h // application specific includes #include "invoicerdoc.h" #include "invoicerviewbase.h" class InvoicerView : public InvoicerViewBase Q_OBJECT public: InvoicerView(QWidget *parent=0, InvoicerDoc* doc=0); ~InvoicerView(); //Beágyazott osztály eleje class ListViewInvoiceItem: public QListViewItem public: ListViewInvoiceItem(QListView *parent, InvoiceItem *i): QListViewItem(parent, i >name(), i >unit(), QString::number(i >quantity()), QString::number(i >unitprice()), QString::number(i >netvalue()), QString::number(i >vatpercent()), QString::number(i >vatvalue()), QString::number(i >allvalue())), _i(i) Beágyazott osztály eleje. void update() settext(0, _i >name()); settext(1, _i >unit()); settext(2, QString::number(_i >quantity())); settext(3, QString::number(_i >unitprice())); settext(4, QString::number(_i >netvalue())); settext(5, QString::number(_i >vatpercent())); settext(6, QString::number(_i >vatvalue())); settext(7, QString::number(_i >allvalue())); InvoiceItem *_i; ; //Beágyazott osztály vége Beágyazott osztály vége. protected slots: void slotdocumentchanged(); void slotdocitemadded(invoiceitem*); ; 15. oldal
A ListViewInvoiceItem típus bevezetése után módosítani kell a slotdocitemadded() slotot is. void InvoicerView::slotDocItemAdded(InvoiceItem* i) new ListViewInvoiceItem(items, i); invoicerview.cpp Most pedig valósítsuk meg a számlatétel módosítása, illetve törlése funkciókat. Ehhez létre kell hozni a megfelelő QAction objektumokat, be kell őket fűzni a menübe és slotokat kell definiálnunk a tevékenységek elvégzésére. Új menüpontok elhelyezése az alkalmazásban (Items/Edit; Items/Remove) Az új menüpont bevezetésének lépései: 1. az almenü mező (adattag) deklarációja (invoicer.h) 2. a számlatétel módosítása / számlatétel törlése tevékenységeket definiáló QAction mezők deklarációja (invoicer.h) 3. a tevékenységeket implementáló slotok deklarációja (invoicer.h) 4. az almenük inicializálása és befűzése a főmenübe (invoicer.cpp) 5. a QAction objektumok inicializálása és befűzése a főmenübe (invoicer.cpp) 6. a slotok implementációja (invoicer.cpp) A itemsedit/itemsremove tevékenységek deklarációja class Invoicer : public QMainWindow invoicer.h private slots: /* application specific slots*/ void slotitemsnew(); /* Edit an item in the actual invoice */ void slotitemsedit(); /* Remove an item from the actual invoice */ void slotitemsremove(); private: /* application specific actions */ QAction *itemsnew; QAction *itemsedit; QAction *itemsremove; A tevékenységeket kezel ő slotok deklarációja. A Számlatétel módosítása és a Számlatétel törlése tevékenységek deklarációja. ; 16. oldal
Az itemsedit és itemsremove tevékenység objektumok létrehozása és inicializálása void Invoicer::initActions() itemsnew = new QAction(tr("Insert new item"),tr("&new item"), 0, this); itemsnew >setstatustip(tr("insert a new item into the invoice")); itemsnew >setwhatsthis( tr("new Item\n\nEnables/Insert a new item into the invoice")); connect(itemsnew, SIGNAL(activated()), this, SLOT(slotItemsNew())); invoicer.cpp itemsedit = new QAction(tr("Edit Item"), tr("&edit Item"), 0, this); itemsedit >setstatustip(tr("modifies an existing invoice item")); itemsedit >setwhatsthis( tr("edit Item\n\nModifies an existing invoice item")); connect(itemsedit, SIGNAL(activated()), this, SLOT(slotItemsEdit())); itemsremove = new QAction(tr("Remove Item"), tr("&remove Item"), 0, this); itemsremove >setstatustip(tr("removes an existing invoice item")); itemsremove >setwhatsthis( tr("remove Item\n\nRemoves an existing invoice item")); connect(itemsremove, SIGNAL(activated()), this, SLOT(slotItemsRemove())); Az itemsedit és itemsremove tevékenységek beillesztése a menübe void Invoicer::initMenuBar() // menubar entry itemsmenu itemsmenu=new QPopupMenu(); itemsnew >addto(itemsmenu); itemsedit >addto(itemsmenu); itemsremove >addto(itemsmenu); invoicer.cpp Az initmenubar() műveletben a már korábban létrehozott itemsmenu popup menühöz hozzáadjuk az itemsedit/itemsremove objektumokat, majd befűzzük azokat a menüsorba. Az itemsedit slot implementációja (slotitemsedit() ) Az új számlatétel módosításakor az alábbi tevékenységeket kell elvégezni: az aktuálisan kiválasztott sorhoz tartozó InvoiceItem objektum meghatározása a felvitelnél használt dialógus feltöltése a számlatétel alapján dialógusablak modális megjelenítése ha a dialógust OK-val zárták: a változtatások elmentése a kiválasztott InvoiceItem objektumba az aktuális sor adatainak frissítése 17. oldal
A slotitemsedit() slot implementációjában használhatjuk a felvitelhez létrehozott InvItemDia dialógusablakot. Ha azt OK-val zárták (QDialog::Accepted()), akkor módosítjuk a tételt a dokumentumban és a view objektumban. void Invoicer::slotItemsEdit() statusbar() >message(tr("modifying current item...")); if(view >items >currentitem()) InvItemDia dlg(this,0,true); InvoiceItem *ii = (dynamic_cast<invoicerview::listviewinvoiceitem *> (view >items >currentitem())) >_i; dlg.itemname >settext(ii >name()); dlg.unit >settext(ii >unit()); dlg.quantity >settext(qstring::number(ii >quantity())); dlg.unitprice >settext(qstring::number(ii >unitprice())); int cnt=dlg.vatpercent >count(); for(int i=0; i<cnt; ++i) if (dlg.vatpercent >text(i).toint()==ii >vatpercent()) dlg.vatpercent >setcurrentitem(i); break; if (dlg.exec() == QDialog::Accepted) ii >update( dlg.itemname >text(), dlg.unit >text(), dlg.quantity >text().toint(), dlg.unitprice >text().toint(), dlg.vatpercent >currenttext().toint()); (dynamic_cast<invoicerview::listviewinvoiceitem *> (view >items >currentitem())) >update(); doc >setmodified(); statusbar() >message(tr("item updated."), 2000); else statusbar() >message(tr("modification aborted."), 2000); statusbar() >message(tr("ready")); invoicer.cpp A set Modified() függvényt még meg kell adni a dokumentum osztályban. Ha a nézet osztály items listájában van kiválasztott elem, akkor létrehozunk egy modális, InvItemDia típusú párbeszédablakot, amelyet kitöltünk a kiválasztott listaelem adataival. Az adatok kitöltéséhez felhasználjuk az általunk létrehozott ListViewInvoiceItem típusban tárolt mutatót. Az ÁFA kulcs QComboBox-át úgy állítjuk be, hogy az az aktuális listaelemhez tartozó értéket mutassa. Ha az OK gombbal tértünk vissza, akkor aktualizáljuk a dokumentumot ( ii->update ()), majd a nézetben is frissítjük a módosított számlatételt. A view->items->currentitem() visszaadja az aktuális tételre mutató pointert, melynek típusa QListViewItem*. Ahhoz, hogy a ListViewInvoiceItem osztály update() metódusa hajtódjon végre el kell végeznünk egy dianamikus típuskonverziót. 18. oldal
Az itemsremove slot implementációja (slotitemsremove()) Egy számlatétel törlésekor az alábbi tevékenységeket kell elvégezni: az aktuálisan kiválasztott sorhoz tartozó InvoiceItem objektum meghatározása ha a dialógust OK-val zárták: a tétel törlése a dokumentumból a tétel törlése a view-ból void Invoicer::slotItemsRemove() statusbar() >message(tr("removing current item...")); if (view >items >currentitem()) InvoiceItem *ii = (dynamic_cast <InvoicerView::ListViewInvoiceItem *> (view >items >currentitem())) >_i; doc >removeitem(ii); delete view >items >currentitem(); statusbar() >message(tr("item removed."), 2000); statusbar() >message(tr("ready")); invoicer.cpp A removeitem() függvényt még meg kell adni a dokumentum osztályban. Új műveletek a dokumentum osztályban (setmodified(), removeitem()) A program hibátlan működéséhez még meg kell adnunk a dokumentum osztály hiányzó két metódusát. class InvoicerDoc : public QObject public: bool ismodified() const; void setmodified(bool val=true) modified = val; void removeitem(invoiceitem *i) _items.removeref(i); modified=true; ; invoicer.cpp Fordítás/Futtatás Ami még hátra van... Természetesen (sajnos ) ezzel még nem készült el a teljes alkalmazás. Hátra van még a számla mentése fájlba, a számla visszaolvasása fájlból, valamint az input adatok ellenőrzése. Ezeket a feladatokat a C++/Qt alapú SDI alkalmazás készítése III. munkafüzetben oldjuk meg. 19. oldal
Projekt összeállítása Qt parancsokkal 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: invoicer.h, invoicer.cpp, invoicerdoc.h,invoicerdoc.cpp, invoicerview.h,invoicerview.cpp, main.cpp, invitemdia.ui, 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 platform független projekt fájlt (invoicer.pro): qmake -project (Ha a Qt Designerrel hozta létre a projektet és úgy illesztette be a fájlokat, akkor ezt a lépést kihagyhatja.) 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.04a) Tue Apr 13 12:48:20 2004 ###################################################################### TEMPLATE = app INCLUDEPATH +=. # Input HEADERS += invoicer.h invoicerdoc.h invoicerview.h INTERFACES += invitemdia.ui invoicerviewbase.ui SOURCES += invoicer.cpp 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 munkafüzet programjai letölthetők a people.inf.elte.hu/nacsa/eaf3/projects/2005/invoicer2 címről. 20. oldal