Qt SDI alkalmazás készítése II...2 Feladat...2 A dokumentum típus módosítása...2 A fejlécet ábrázoló mezők bevezetése...3 A bevezetett mezők lekérdező műveletei...3 A bevezetett mezők beállító slotjai...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 Számlatétel lista a dokumentumban...6 Új számlatétel felvitele...6 Új dialógusablak létrehozása...6 A dialógusablak felépíté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 elhelyezése a menüsorban...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)...11 Ú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/itemsremove tevékenység objektumok létrehozása és inicializálása...17 Az itemsedit/itemsremove tevékenységek elhelyezése a menüsorban...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 projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa címről. 1. oldal
"!$#&% ')(*% ')+,%.-/01(&203-546 20879#6#6: Ebben a munkafüzetben feltételezzük, hogy Ön már feldolgozta az SDI alkalmazás készítése Qt-ben 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. ;=<>@?BAC?ED A számla típus (doc) és a hozzátartozó számlatétel típus megvalósítása A számla és a view összekötése Számlatétel felvitele, javítása, törlése Számla mentése, beolvasása FGA=HEIBJEKL<NM5DOJCKPDRQTSUJWV KYXEA=HWVZQODR[ZV\? Alkalmazásunk dokumentuma maga a számla, ezért az előző munkafüzetben elkészített általános dokumentum osztály módosításával készítjük el a számlát reprezentáló dokumentum típust. Ennek megfelelően 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 bevezetése class InvoicerDoc : public QObject protected: bool modified; QString _customer; QString _zip; QString _city; QString _street; QString _invno; QString _released; QString _fulfilled; QString _dueto; ; A bevezetett mezők lekérdező műveletei class InvoicerDoc : public QObject Q_OBJECT public: bool ismodified() const; invoicerdoc.h invoicerdoc.h 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; ; A bevezetett mezők beállító slotjai 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 3. oldal
]^ _a`c_ebdcfecgihoboej@hzkye^mlcnpoq _\^ _a`c_ebbr_rtscnvuxwwqzq\^memnawfboomqwe=y 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) : InvoicerViewBase(parent) connect(doc, SIGNAL(documentChanged()), this, SLOT(slotDocumentChanged())); 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&))); z ^ Bkj~_EbOoBbOemjdeNn nae^memjdomqwe //invoicerview.cpp invoicerview.cpp A connect-ben szereplő változók QLineEdit típusúak, így az ezt definiáló fájlt be kell illeszteni a forrásfájlunkba. 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
Rƒ C dẑ ŠO mœ WŽ\ \ŠR Z 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. Ennek megfelelően egészítse 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; invoicerdoc.h A konstruktorban inicializáljuk az InvoiceItem adattagjait. Valamennyi adattagnak van alapértelmezett kezdőértéke. Az update() tagfüggvénnyel a paraméterek alapján aktualizáljuk az adatokat. 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; A lekérdező műveletek olyan egyszerűek, hogy ezeket inline módon adjuk meg. 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
U B ~Ẽ OšB O m Z ~œ~ E R pž=ÿca C Y m E Z 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; 3 Nª «B ~ EŌ BŌ±m B²³±m íµoō±m d± 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álassza ki az Edit menüpontot. 7. oldal
Ý Elemi alkalmazások fejlesztése III. Ú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. 3 3ḑ¹Rº»½¼N¾Uºa À¹dº\Á ÂúÄ\ÅN¼mÂÇÆÂ ¼È ÉÈ ¹\Ãmºi º Ê~Ë ÌÍ~ÎCÏZÐBÑÒdÓÕÔBÖ~ Ó~ØÚÙÜÛ 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; Az Új tétel felvitele tevékenységet definiáló QAction deklarációja. ; Saját jegyzet 8. oldal
Þ3ß3àdáRâã½äNåUâaæÀádâ\ç èéâê\ënämèçìíbîðï âé\ádñzãóò@èmádô6âõaí\ßçöä øè ä àõêbà~ù àú mò àúßûömòúömä /** 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 QAction objektum inicializálása és 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()) ü3ý3þdÿ Àÿ ý! " # %$ &')( Létrehozzuk az itemsmenu popup menüt, majd hozzáadjuk az itemsnew tevékenységet, és 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 Items 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); invoicer.cpp Létrehozzuk az Item menüpontot, és beledobjuk az itemsnew tevékenységet. Az Items menüpontot beillesztjük a menüsorba. *,+-/.%0/10 2 3 + 4 257698;:3"<=->23?2@=0/A-BA+ C Az új számlatétel felvitelekor az alábbi tevékenységeket kell elvégezni: 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!!! Az insertitem() 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 gyereke. 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 orban megjelenik az Item added üzenet. Ha a felhasználó a Cancel semmi tennivalónk. Új tétel beillesztése a számlába gombra kattintott, akkor ezt a tényt a státuszsorban jelezzük, de ilyenkor nincs 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. D Saját jegyzet EGFIHJ H KLMNOGOPQ RPSQTQURNWV XY#K Z%H[XY\MNO!] S OGP Y L^P MNÒ _ 11. oldal
class InvoicerDoc : public QObject Q_OBJECT invoicerdoc.h 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; A függvénydefiníciót inline módon adtuk meg. Ha 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. agbdc egf g hbijk j lhg?lgmnbolh/l pwq jkcl!i"pkel jj k j lhbhrbcjfsb`f tip 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 slotdocitemadded() 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) slotdocitemadded() 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>) u Fordítás/Futtattás v wxwyz/= ~W ~zwy = ƒ ~ x 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
Elemi alkalmazások fejlesztése III. 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. Ĝ dš ŒŽ > 9 ; Š Š Š Œ)šœ W ŠŠ žÿbš s / / / š 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
ª «B ) /±² ³ µ / ±³ ± ¹»º±¼½%¾ À % ~ À /¼Á¾œÂ± à ẂÄ/ /ÅÇÆ` UÈ T ¹ É Á>±¹?± /¼ >ÅÊÆË //include files for Qt #include <qlistview.h> invoicer.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 Mostpedig 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: az almenü mező (adattag) deklarációja (invoicer.h) 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) a tevékenységeket implementáló slotok deklarációja (invoicer.h) az almenük inicializálása és befűzése a főmenübe (invoicer.cpp) a QAction objektumok inicializálása és befűzése a főmenübe (invoicer.cpp) a slotok implementációja (invoicer.cpp) Ì,Í ÎÏ Ð Ñ Ò ÓÍ Î ÔÇÍ Î Ï Ð Ñ ÕdÏÐ?Ö= Ï"ÎÏ Ø ÙÏ ÚÛ ÑØÜ Ï Ù ÓWÏ Ù Ý^Þßáà âí/ãçä`þ 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(); A tevékenységeket kezelő slotok deklarációja. private: ; /* application specific actions */ QAction *itemsnew; QAction *itemsedit; QAction *itemsremove; A Számlatétel módosítása és a Számlatétel törlése tevékenységek deklarációja. 16. oldal
åçæ,è éêë\ìí îè é ïêè éê ë ì ð ê ë#ñ òê"é êòóôê õöì ó ñwøçùoêôé[úë#ñwôüû/ó é ýsê þñæÿì UóìTèõWè è ûbè^æÿûbÿì 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()));! "#%$& ')(+*,)(-#./ //10 "32.!54760!" 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. 8 9 :;< =>?@:;>BA C3;:+='DA < =< EF;+G.H): IKJMLONP>BA C3;PQ;<)=R>!?@:;NTSUS 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 setmodified() 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
p Elemi alkalmazások fejlesztése III. V W XYZ [\]Z [^_`Za\Bb ^3YX+['cb Z [Z dfy+e.f)x gkhmiojp\bb ^3YPkYZ)[R\!]lZ)[m^_Z!jTnon 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/Futtattás q'rtsrvu/wyxfzf ~ `~U ƒpƒ ƒ Természetesen 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, és az input adatok ellenőrzése. Ezeket a feladatokat SDI alkalmazás készítése Qt-ben III. munkafüzetben dolgozzuk fel. 19. oldal
KˆŠ % Œ3 3Ž,.! B P., 7 U š!,ˆ3œœ 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 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.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 20. oldal