A slotfilequit() módosítása...18 Ami még hátra van...18 Projekt összeállítása Qt parancsokkal...19

Hasonló dokumentumok
Elemi alkalmazások fejlesztése III

Elemi alkalmazások fejlesztése III

Elemi alkalmazások fejlesztése III

Elemi alkalmazások fejlesztése III

C++/Qt alapú SDI alkalmazás készítése II...2

ELTE Informatikai Kar

Elemi alkalmazások fejlesztése III. SDI alkalmazás készítése Qt-ben I.

Elemi alkalmazások fejlesztése III.

Alkalmazások fejlesztése III. Qt 4 /C++ alapú MDI alkalmazás: Számlakészítő program 1/3

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése III.

Elemi alkalmazások fejlesztése

Felhasználó által definiált adattípus

3. Osztályok II. Programozás II

Programozás II. 2. Dr. Iványi Péter

Alkalmazások fejlesztése III. Qt 4 /C++ alapú MDI alkalmazás: Számlakészítő program 3/3

Programozás C++ -ban

Elemi alkalmazások fejlesztése III. A Qt assistant elindítása. Ajánlott ir odalom. A Qt assistant nyitó ablaka

4. Öröklődés. Programozás II

Elemi alkalmazások fejlesztése IV. Adatbázis-kezelő GUI alkalmazás készítése 3. Összetett tábla karbantartása

Elemi alkalmazások fejlesztése III

Alkalmazások fejlesztése III. Qt 4 /C++ alapú MDI alkalmazás: Számlakészítő program 2/3

OAF Gregorics Tibor: Minta dokumentáció a 3. házi feladathoz 1.

Programozás II gyakorlat. 6. Polimorfizmus

Egységes és objektumközpontú adatbázis-kezelés (2. rész)

3D-s számítógépes geometria és alakzatrekonstrukció

Statikus adattagok. Statikus adattag inicializálása. Speciális adattagok és tagfüggvények. Általános Informatikai Tanszék

A gyakorlat során az alábbi ábrán látható négy entitáshoz kapcsolódó adatbevitelt fogjuk megoldani.

Programozás II gyakorlat. 4. Öröklődés

Alkalmazások fejlesztése III. Qt 4 /C++ alapú grafikus alkalmazás Bevezetés I.

ISA szimulátor objektum-orientált modell (C++)

1. Alapok. Programozás II

SDI ALKALMAZÁS I. Workspace / ResourceView / Toolbar / IDR_MAINFRAME. Workspace / ResourceView / Menu / IDR_MAINFRAME

Maximum kiválasztás tömbben

C++ programozási nyelv Konstruktorok-destruktorok

Elemi alkalmazások fejlesztése III.

OOP: Java 4.Gy: Java osztályok

117. AA Megoldó Alfréd AA 117.

Objektumok inicializálása

Elemi alkalmazások fejlesztése IV.

MySql elindítása. Elemi alkalmazások fejlesztése IV. Feladat. Az alkalmazás adatbázisa

STL gyakorlat C++ Izsó Tamás május 9. Izsó Tamás STL gyakorlat/ 1

Programozás II gyakorlat. 8. Operátor túlterhelés

Java Programozás 4. Gy: Java GUI. Tipper, MVC kalkulátor

Programozás C++ -ban 2007/7

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

Bevezetés Kiíratás Beolvasás Formázás Fájlkezelés Gyakorló feladatok C++ I/O. Bevezetés. Izsó Tamás február 20. Izsó Tamás C++ I/O / 1

Programozási alapismeretek :: beadandó feladat. Felhasználói dokumentáció. Molnár Tamás MOTIABT.ELTE

1. Öröklés Rétegelés Nyilvános öröklés - isa reláció Korlátozó öröklődés - has-a reláció

Access adatbázis elérése OLE DB-n keresztül

WCF, Entity Framework, ASP.NET, WPF 1. WCF service-t (adatbázissal Entity Framework) 2. ASP.NET kliens 3. WPF kliens

Java Programozás 9. Gy: Java alapok. Adatkezelő 5.rész

osztályok kapcsolata Származtatatás C++ Izsó Tamás március 19. Izsó Tamás Származtatatás/ 1

Programozás alapjai II. (9. ea) C++ többszörös öröklés, cast, perzisztencia

A jobboldalon a pnlright egy Stacked Widget Állítsuk be az első lapot és nevezzük el pnldraw-ra:

Programozás II. 4. Dr. Iványi Péter

Programozás C++ -ban

Adatbázis-kezelés API hívásokkal. Adatbázis-kezelés ODBC-vel. Adatbázis-kezelés SQL parancsokkal. Adatbázis-kezelés ODBC-vel.

AWK programozás, minták, vezérlési szerkezetek

Szoftvertechnolo gia gyakorlat

Java. Perzisztencia. ANTAL Margit. Java Persistence API. Object Relational Mapping. Perzisztencia. Entity components. ANTAL Margit.

OOP: Java 11.Gy: Enumok, beágyazott osztályok. 13/1 B ITv: MAN

3D-s számítógépes geometria és alakzatrekonstrukció

Grafikus Qt programok írása segédeszközök nélkül

Entity Framework alapú adatbáziselérés

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

Objektum elvű alkalmazások fejlesztése Kifejezés lengyel formára hozása és kiértékelése

Osztály és objektum fogalma

INFORMATIKAI ALAPISMERETEK

7. Laboratóriumi gyakorlat: Vezérlési szerkezetek II.

Programozási nyelvek Java

A lista eleme. mutató rész. adat rész. Listaelem létrehozása. Node Deklarálás. Létrehozás. Az elemet nekünk kell bef zni a listába

és az instanceof operátor

Pénzügyi algoritmusok

Adabáziselérés ODBC-n keresztül utasításokkal C#-ban

Budapest, március. ELTE Informatikai Kar

Java VIII. Az interfacei. és az instanceof operátor. Az interfészről általában. Interfészek JAVA-ban. Krizsán Zoltán

Programozás II. ATM példa Dr. Iványi Péter

Java Programozás 11. Ea: MVC modell

munkafüzet open eseményéhez

Adatbázis Rendszerek II. 5. PLSQL Csomagok 16/1B IT MAN

Programozás Minta programterv a 1. házi feladathoz 1.

11. gyakorlat Sturktúrák használata. 1. Definiáljon dátum típust. Olvasson be két dátumot, és határozza meg melyik a régebbi.

Bevezetés a programozásba Előadás: Objektumszintű és osztályszintű elemek, hibakezelés

Programozás alapjai 9.Gy: Struktúra 2.

Pénzügyi algoritmusok

Informatika terméktervezőknek

Programozási nyelvek Java

BME MOGI Gépészeti informatika 7.

500. AA Megoldó Alfréd AA 500.

Tartalomjegyzék. Általános Információ! 2. Felhasználói dokumentáció! 3. Feladat! 3. Környezet! 3. Használat! 3. Bemenet! 3. Példa!

AWK programozás, minták, vezérlési szerkezetek

Adatbázis-kezelés ODBC-vel

QLabel *label = new Qlabel("Hello Qt!",0);

Programozási Nyelvek: C++

Bevezetés a programozásba I 10. gyakorlat. C++: alprogramok deklarációja és paraméterátadása

OOP: Java 8.Gy: Abstract osztályok, interfészek

Szövegek C++ -ban, a string osztály

Sorosítás (szerializáció) és helyreállítás. 1. Bináris sorosítás és helyreállítás Szükséges névterek Attribútumok. 1.3.

Átírás:

...2 Feladat...2 Beviteli mezők ellenőrzése...2 Ellenőrző objektumok (Validátorok)...3 QValidator::State...3 QValidator::validate()...3 QValidator::fixup()...3 Az adatbevitel ellenőrzésének lépései...3 Saját dátumvalidátor létrehozása...4 A DateValidator típus definíciója...4 Az illesztő privát művelet implementációja(match())...4 Az ellenőrző művelet implementációja (validate())...5 Alapértelmezett értéket visszaadó függvény implementációja (fixup())...5 Ellenőrzések a view osztályban...6 Ellenőrző objektumok létrehozása...6 Fordítás/Futtatás...7 Ellenőrzés az adatbevitel végén...7 Dátumellenőrző slotok implementációja...8 Ellenőrzések a számlatétel dialógusban...9 A CheckedItemDia osztály definíciója és implementációja...10 Fordítás/Futtatás...10 A documentchanged()/slotdocumentchanged() módosítása...11 Mentés fájlba, olvasás fájlból...12 A dokumentum osztály fájlkezelő műveletei...13 Új adattag a dokumentum osztályban (_filename)...13 A dokumentum objektum inicializálása (newdoc())...13 A save() művelet implementációja...13 A saveas() művelet implementációja...14 A load() művelet implementációja...14 A dokumetum osztály adatellenőrző függvénye (check())...15 A nézet osztály fájlkezelő slotjainak módosítása...15 A querysave() saját függfény...15 A slotfilenew() módosítása...17 A slotfileopen() módosítása...17 A slotfilesave() módosítása...17 A slotfilesaveas() módosítása...17 A slotfilequit() módosítása...18 Ami még hátra van...18 Projekt összeállítása Qt parancsokkal...19 A projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa címről. 1. oldal

"! #%$&! #%'(!*)+,-$&.,/)1032.,547682 9;:*4<=3>@? Ebben a munkafüzetben feltételezzük, hogy Ön már feldolgozta az SDI alkalmazás készítése Qt-ben I. és II, munkafüzeteket. A Qt SDI alkalmazás készítése I. és II.-ben elkészítettünk egy Qt SDI alkalmazást, felépítettük a view osztály felhasználói felületét, megvalósítottuk a számla típust, valamint a hozzátartozó számlatétel típust, megoldottuk a számla és a view összekapcsolását, és lehetővé tettük új számlatétel felvitelét, módosítását és javítását. ACBDFEHGIEKJ Biztosítsuk alkalmazásunban az ellenőrzött adatbevitelt, és tegyük lehetővé az egyes számlák mentését fájlba, illetve azok beolvasását fájlból. L BIMONPJQBDFNSRTBUWVIXYBDFDZB\[]V_^@UW`abB Az adatbevitelt az alábbiak szerint szeretnénk korlátozni: View osztály irányítószám (négy elemű, reguláris kifejezés) számlaszám (csak számjegy) dátumok (illeszkedés a megadott mintára+dátum ellenőrzés) Számlatétel dialógusablak darabszám (numerikus) egységár (numerikus) 2. oldal

c1dfdze\f]g_h@iwgkjilnmoewpiqqristjiputwvyxsdz I~KqQj_hwjIpO A Qvalidator osztállyal biztosíthatjuk alkalmazásunkban az input adatok ellenőrzött bevitelét. AQvalidator osztály egy absztrakt osztály. A belőle származtatottqintvalidator ésqdoublevalidator segítségével az egyszerűbb numerikus ellenőrzéseket oldhatjuk meg. A QRegExpValidator reguláris kifejezéseket használ, mellyel egy általánosabb adatellenőrzést valósíthatunk meg. Ha a beépített ellenőrző objektumok nem elegendőek, akkor származtatással előállíthatunk saját ellenőrző objektumokat is. Az osztálynak két virtuális függvénye van: validate() és fixup(). A validate() függvényt kötelező implementálni. A függvény visszatérési értéke Invalid (nem elfogadható), Intermediate (esetleg még jó lehet) vagy Acceptable (elfogadható), attól függően, hogy az ellenőrzött objektum milyen állapotban van. (Például, ha a megengedett szöveg 0 és 99 közé eső szám, akkor 444 státusza Intermediate, 55 státusza Acceptable, abc státusza Invalid.) A QValidator osztály publikus tagjai a következők: QValidator::State Felsorolás (enum) típusú adattag, mely jelzi, hogy az ellenőrzött input szöveg éppen milyen állapotban van. enum State Invalid, Intermediate, Valid = Intermediate, Acceptable QValidator::validate() virtual State validate ( QString & input, int & pos ) const = 0 A validate() függvény egy tiszta virtuális függvény, ezért a származtatott osztályokban kötelező definiálni. Ellenőrzi az input szöveg tartalmát, és visszaad egy State típusú értéket. Szükség esetén megváltoztathatjuk mind az input szöveg tartalmát, mind pedig a pos (a kurzor pillanatnyi helye) paraméter értékét is. QValidator::fixup() virtual void fixup ( QString & input ) const A fixup() függvény lehetővé teszi, hogy magunk is kijavíthassunk bizonyos adatbeviteli hibákat. Például a QLineEdit adatbeviteli mező esetén az Enter leütésekor a fixup() függvény kapja meg a vezérlést, ha az ellenőrző objektum State értéke nem Acceptable. i xy IxKqZl]eI ;zqqqedbewddze\f]g_h@iw Wƒy \f]e\p dz ; Wƒbez Ellenőrző objektum létrehozása Ellenőrző objektum viselkedésének beállítása Ellenőrző objektum és az adatbeviteli mező összerendelése Megjegyzés: Ellenőrző objektumok (validátorok) használatára már mutattunk egy egyszerű példát az Egyablakos alkalmazás készítése II. munkafüzet (Milliomos2) Numerikus input kezelése c. fejezetében. 3. oldal

Elemi alkalmazások fejlesztése III. ˆ%ŠŒ K bži K Q I ;ˆ F ŽI K Q _ 1 Z y Q % \ ] bš œsˆ A dátum típusú mezők ellenőrzésére létrehozunk egy saját DateValidator osztályt, melyet a a QValidator osztályból származtatunk. A DateValidator típus definíciója #include <qvalidator.h> class DateValidator : public QValidator Q_OBJECT public: DateValidator(QString pattern = "1111.11.11", QObject *parent=0,const char *name=0): QValidator(parent,name), _pattern(pattern) virtual State validate(qstring &, int &) const; virtual void fixup(qstring &) const; private: bool match(const QChar &ch, int p) const; QString _pattern; ; datevalidator.h A Q_OBJECT makrót mindig meg kell adni, ha signal/slot mechanizmust használunk. A konstruktor egy üres törzsű függvény, ezért a datevalidaor.cpp-ben nem szerepel! Érdemes a Help-et használva bepillantani a QValidator osztályba. Az illesztő privát művelet implementációja(match()) A match() privát művelet vizsgálja az adott minta szerinti illeszkedést egy adott pozíción. bool DateValidator::match(const QChar &ch, int p) const if(p>=(int)_pattern.length()) return false; if(_pattern[p]=='1') return ch.isdigit(); else return (ch == _pattern[p]); datevalidator.cpp Saját jegyzet 4. oldal

ž Elemi alkalmazások fejlesztése III. Az ellenőrző művelet implementációja (validate()) A validáló művelet a kapott szöveget az eltárolt mintához illeszti. #include <qdatetime.h> #include "datevalidator.h" QValidator::State DateValidator::validate(QString &txt, int &pos) const int l=txt.length(); int i=0; for(;i<l && match(txt[i],i);++i); //empty body if(i<l) pos=i; //txt.truncate(i); return Intermediate; else if (i==l) if(l==(int)_pattern.length() && QDate::isValid(txt.mid(0,4).toInt(), txt.mid(5,2).toint(), txt.mid(8,2).toint())) return Acceptable; else return Intermediate; else return Invalid; datevalidator.cpp Ha jó a mintaillesztés, nézzük meg, valóban dátum-e. Alapértelmezett értéket visszaadó függvény implementációja (fixup()) A fixup() művelet hibás adat esetén kicseréli a szerkesztőmező tartalmát. void DateValidator::fixup (QString &txt) const QDateTime day = QDateTime::currentDateTime(); txt = day.tostring("yyyy") + "." + day.tostring("mm") + "." + day.tostring("dd"); datevalidator.cpp Legyen a mai dátum az alapértelmezés. Saját jegyzet 5. oldal

Ÿ1FZ \ ] _ @ W b \ «ªO K b ±² ³yµ_ S A view osztályban deklarálunk egy numerikus validatort a számlaszám ellenőrzésére (invnov), egy reguláris kifejezéseket ellenőrző validátort az irányítószám ellenőrzésére (zipv), valamint egy dátumvalidátort a dátum típusú mezők (dv) ellenőrzésére, majd a számla megfelelő mezőihez hozzárendeljük ezeket a validátorokat. Ellenőrző objektumok létrehozása #include "datevalidator.h" class InvoicerView : public InvoicerViewBase private: void initvalidators(); protected: DateValidator* dv; QRegExpValidator* zipv; QIntValidator* invnov; ; invoicerview.h InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) initvalidators(); invoicerview.cpp A validátorokat létrehozó privát függvényt a konstruktorban hívjuk meg. void InvoicerView::initValidators() QRegExp regexp("[1-9][0-9]3,3"); zipv = new QRegExpValidator(regExp,this); zip->setvalidator(zipv); invnov=new QIntValidator(this); invno->setvalidator(invnov); dv=new DateValidator("1111.11.11",this); released->setvalidator(dv); fulfilled->setvalidator(dv); dueto->setvalidator(dv); invoicerview.cpp A regexp-ben megadott minta szerint az irányítószám első számjegye 1 és 9 közötti számjegy, melyet pontosan három darab 0 és 9 közé eső szám követ. A setvalidator() függvénnyel rendeltük hozzá az ellenőrző objektumokat az ellenőrizendő adatbeviteli mezőkhöz. 6. oldal

C _ >¹KºQ»¼S½n¾ _À]»»ÁK»¼ ½ Fordítsa le, majd futtassa a programot. Figyelje meg, hogy az ellenőrzött adatbeviteli mezőknél helyesen működik-e az adatbevitel. Mi történik, ha az adatbevitelt félbe hagyva átmegy egy másik mezőre? Â1ÃFÃZÄ\Å]Æ_Ç@ÈWÉÊ Ë È ËyÌIËKÍZÎ]ÏIÐOÑPÍQÏÒCÐÉOÓÔÉWÕ Alkalmazásunkban azt is szeretnénk biztosítani, hogy a dátumokat tartalmazó mezőkről csak akkor lehessen továbblépni, ha a mezőt teljesen és helyesen töltötték ki. Ehhez a vizsgálandó mezők lostfocus() signáljaitt összekötjük a vizsgálatot végző slotokkal, majd megadjuk a slotok implementációját. class InvoicerView : public InvoicerViewBase protected slots: void slotdocumentchanged(); void slotdocitemadded(invoiceitem*); void checkreleaseddate(); void checkfulfilleddate(); void checkduetodate(); invoicerview.h Alkalmazásunkban három dátum típusú mezőt szeretnénk ellenőrizni. ; InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) initvalidators(); connect(released, SIGNAL(lostFocus()), this, SLOT(checkReleasedDate())); connect(fulfilled, SIGNAL(lostFocus()), this, SLOT(checkFulfilledDate())); connect(dueto, SIGNAL(lostFocus()), this, SLOT(checkDueToDate())); invoicerview.cpp connect( doc,signal(iteminserted(invoiceitem*)), this,slot(slotdocitemadded(invoiceitem*))); Amikor egy adatbeviteli mezőt elhagyunk (Tab-bal kiléptünk, vagy egérrel kikattintottunk a mezőből), akkor az adott vezérlő lostfocus() signált küld. A view osztály konstruktorában összekapcsoljuk a dátum típusú adatbeviteli mezők lostfocus() signálját és a dátumot ellenőrző slotokat, majd a slotokban elvégezzük az adatok ellenőrzését. 7. oldal

Dátumellenőrző slotok implementációja Számla kibocsájtás dátuma A számla kibocsájtás dátuma legyen az adott napi dátum, ha a mezőt üresen hagyták. Ha a mezőt csak részben töltötték ki, akkor írjunk ki fegyelmeztetést, és ne engedjük elhagyni ezt a mezőt. void InvoicerView::checkReleasedDate() if (released->text()=="") QDateTime day = QDateTime::currentDateTime(); QString str = day.tostring("yyyy") + "." + day.tostring("mm") + "." + day.tostring("dd"); released->settext(str); return; QString str = released->text(); int p = 0; if(released->validator()->validate(str,p)!= QValidator::Acceptable) QMessageBox::information( this, "InvoicerView", "Invalid date! \ndate format: \"yyyy.mm.dd\" "); released->setfocus(); invoicerview.cpp Számla kiegyenlítés dátuma void InvoicerView::checkFulfilledDate() QString str = fulfilled->text(); int p = 0; if(fulfilled->validator()->validate(str,p)!= QValidator::Acceptable && str!= "") qdebug(qstring::number(p)); QMessageBox::information( this, "InvoicerView", "Invalid date! \ndate format: \"yyyy.mm.dd\" "); fulfilled->setfocus(); invoicerview.cpp A számla kiegyenlítésének dátuma lehet üres is. 8. oldal

Számla esedékesség dátuma Ha a számla kifizetésének határideje üres, akkor 8 napos határidőt szabunk meg a számla kifizetésére. void InvoicerView::checkDueToDate() if (dueto->text()=="") QDateTime day = QDateTime::currentDateTime().addDays(8); QString str = day.tostring("yyyy") + "." + day.tostring("mm") + "." + day.tostring("dd"); dueto->settext(str); return; else QString str = dueto->text(); int p = 0; if(dueto->validator()->validate(str,p)!= QValidator::Acceptable) QMessageBox::information( this, "InvoicerView", "Invalid date! \ndate format: \"yyyy.mm.dd\" "); dueto->setfocus(); invoicerview.cpp Mához nyolc napra kell fizetni. Ö1 F ZØ\Ù]Ú_Û@ÜWÝÞbß\à á Þ\Ü âhãkäákåqýhåqßwäyæiçásäzè é êiþsë_ásì A számlatétel dialógus egy generált osztály (invitemdia.ui). Ha új funkciót akarunk hozzárendelni, akkor a generált osztályból származtatással létre kell hoznunk egy új osztályt, és ezt tudjuk kibővíteni a kívánt új funkciókkal. Legyen az InvItemDia osztályból származtatott ellenőrzött új osztály neve CheckedItemDia. Az osztály nagyon egyszerű, ezért a konstruktor feladatát inline módon adjuk meg, így nincs is szükségünk az osztály implementációs fájljára. Illesszen be egy új fájlt a projektjébe checkeditemdia.h néven. í Saját jegyzet 9. oldal

A CheckedItemDia osztály definíciója és implementációja #include <invitemdia.h> #include <qvalidator.h> #include <qlineedit.h> class CheckedItemDia : public InvItemDia Q_OBJECT public: CheckedItemDia(QWidget *parent,const char *name): InvItemDia(parent,name,true), v(this) unitprice->setvalidator(&v); quantity->setvalidator(&v); protected: QIntValidator v; ; checkeditemdia.h Ne feledkezzen meg az include - okról! A CheckedItemDia típus beillesztése az InvoicerView osztályba Cserélje le az alkalmazás InvItemDia példányait a most létrehozott, ellenőrzött CheckedItemDia példányokra. #include "checkeditemdia.h" void Invoicer::slotItemsNew() //invocer.cpp statusbar()->message(tr("inserting a new invoice item...")); //InvItemDia dlg(this,0,true); CheckedItemDia dlg(this,0); if (dlg.exec() == QDialog::Accepted) invoicer.cpp Ügyeljen arra, hogy a paraméterek száma is megváltozott!! void Invoicer::slotItemsEdit() statusbar()->message(tr("modifying current item...")); if(view->items->currentitem()) //InvItemDia dlg(this,0,true); CheckedItemDia dlg(this,0); InvoiceItem *ii = //invoicer.cpp Ügyeljen arra, hogy a paraméterek száma is megváltozott!! Fordítás/Futtatás Ellenőrizze munkáját. Készítsen el egy számlát, vigyen fel néhány számlatételt, majd módosítsa ill. törölje azokat. 10. oldal

îðïcñcò ókôöõ\ 1øù&úKûH Hü õ ï]ýÿþ Zñ]ø ñ_òsóiôtõw øù úkûh HüÔõ\ï ý þ ô _ïcñ Qø û Projektünket úgy készítettük el, hogy adatainkat a dokumentum osztályban, a felhasználói felületeket a view osztályban kezeljük. A dokumentum osztály adatainak megváltozásakor documentchanged() szignált küld. Ez a szignál a view osztály slotdocumentchanged() slotjára van rákötve. Ahhoz, hogy a view osztály megszerezze az adatokat, biztosítanunk kell a view osztály számára, hogy meghívhassa a dokumentum osztály adatlekérdező függvényeit. Ehhez a slotdocumentchanged() függvénynek rendelkeznie kell a dokumentum osztályra mutató pointerrel. Ezt a pointert a signal/slot kapcsolat paramétereként adjuk át. A fenti megfontolásokat figyelembe véve egészítsük ki az InvoicerDoc osztály documentchanged() és a InvoicerView osztály slotdocumentchanged() függvényeit egy, a dokumentum osztályra mutató pointert tartalmazó argumentummal. class InvoicerDoc : public QObject signals: void documentchanged(invoicerdoc* doc); void iteminserted(invoiceitem *i); ; invoicerdoc.h bool InvoicerDoc::load(const QString &filename) emit documentchanged(this); return true; invoicerdoc.cpp this: a dokumentum osztályra mutató pointer. class InvoicerView : public InvoicerViewBase Q_OBJECT protected slots: void slotdocumentchanged(invoicerdoc*); void slotdocitemadded(invoiceitem*); ; invoicerview.h InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) initvalidators(); //connect(doc, SIGNAL(documentChanged()), // this, SLOT(slotDocumentChanged())); connect(doc, SIGNAL(documentChanged(InvoicerDoc*)), this, SLOT(slotDocumentChanged(InvoicerDoc*))); invoicerview.cpp Csak a paraméter típusát kell megadni, paramétert (változót) nem szabad!! 11. oldal

0 Elemi alkalmazások fejlesztése III. void InvoicerView::slotDocumentChanged(InvoicerDoc* doc) //TODO update the view customer->settext(doc->customer()); zip->settext(doc->zip()); city->settext(doc->city()); street->settext(doc->street()); invno->settext(doc->invno()); released->settext(doc->released()); fulfilled->settext(doc->fulfilled()); dueto->settext(doc->dueto()); QListIterator<InvoiceItem> it (doc->items()); items->clear(); for (; it.current(); ++it) InvoiceItem *ii = it.current(); new ListViewInvoiceItem(items,ii); invoicerview.cpp "!$#&%')(*!+,- /. A fájlkezelés két osztályt érint: az alkalmazás főablakát (Invoicer) és a dokumentum osztályt (InvoicerDoc). Fájlkezelő műveletek a dokumentumban (InvoicerDoc) newdoc: a dokumetum objektum kiürítése save: a dokumentum objektum elmentése az aktuális fájlba saveas: a dokumentum objektum elmentése a megadott nevű fájlba load: a dokumentum objektum beolvasása a megadott nevű fájlból Fájlkezelő slotok a főablakban (Invoicer) slotfilenew() slotfilesave() slotfilesaveas() slotfileopen() Saját jegyzet 12. oldal

13254"687"9 :;< 7'9=4>+?+<@ ACBED @FA 6G:$?:$AIHEJLKM$N$OIN8P NQ Új adattag a dokumentum osztályban (_filename) class InvoicerDoc : public QObject public: const QString dueto() const return _dueto; const QString filename() const return _filename; protected: QString _dueto; QString _filename; ; A dokumentum objektum inicializálása (newdoc()) void InvoicerDoc::newDoc() _customer = _zip = _city = _street = _invno= _released = _fulfilled = _dueto = ""; _items.clear(); _filename=""; modified = false; emit documentchanged(this); invoicerdoc.h A dokumentum osztályt kiegészítjük egy, a fájl nevét tartalmazó adattaggal és az adattag értékét visszaadó függvénnyel. invoicerdoc.cpp A save() művelet implementációja A save() függvénnyel elmentjük a számla tartalmát a tárolt fájlba szöveges (txt) formában. #include <fstream> using namespace std; bool InvoicerDoc::save() ofstream f(_filename); if (f) f << _customer.utf8() << endl << _zip.utf8() << endl << _city.utf8() << endl << _street.utf8() << endl << _invno.utf8() << endl << _released.utf8() << endl << _fulfilled.utf8() << endl << _dueto.utf8() << endl << _items.count() << endl; for (InvoiceItem *ii= _items.first(); ii; ii=_items.next()) f << ii->name().utf8() << endl << ii->unit().utf8() << endl << ii->quantity() << endl << ii->unitprice() << endl << ii->vatpercent() << endl; modified=false; return true; return false; invoicerdoc.cpp Ne feledkezzen meg az include-okról sem!!! Létrehozunk egy ofstream adatfolyamot, majd ide kiírjuk a számla fejlécét, és rendre a számlatételeket. A szöveget az ékezetek kezelése miatt utf8 típusú karakterekre konvertáljuk. 13. oldal

A saveas() művelet implementációja A saveas() művelet eltárolja a paraméterként kapott fájlnevet és meghívja a save műveletet. bool InvoicerDoc::saveAs(const QString &filename) _filename=filename; return save(); invoicerdoc.cpp A load() művelet implementációja Az adatokat betöltjük egy fájlból. A fájl nevét elmentjük a dokumentumosztály _filename adattagjába. Ezt a nevet használjuk majd annak eldöntésére, hogy mi történjen mentés, vagy mentés másként esetén az adatainkkal. bool InvoicerDoc::load(const QString & filename) ifstream f; char buf[1024], buf2[1024]; f.open(filename); if (f) f.getline(buf,1024); _customer = QString::fromUtf8(buf); f.getline(buf,1024); _zip = QString::fromUtf8(buf); f.getline(buf,1024); _city = QString::fromUtf8(buf); f.getline(buf,1024); _street = QString::fromUtf8(buf); f.getline(buf,1024); _invno = QString::fromUtf8(buf); f.getline(buf,1024); _released = QString::fromUtf8(buf); f.getline(buf,1024); _fulfilled = QString::fromUtf8(buf); f.getline(buf,1024); _dueto = QString::fromUtf8(buf); //load items _items.clear(); int ic, q, u, v; //quantity, unit price, vat f >> ic; f.getline(buf,1024); //skip rest of line while (ic>0) f.getline(buf,1024); //name f.getline(buf2,1024); //unit f >> q >> u >> v; InvoiceItem *ii=new InvoiceItem(QString::fromUtf8(buf), QString::fromUtf8(buf2), q, u, v); f.getline(buf,1024); //skip rest of line _items.append(ii); --ic; _filename=filename; emit documentchanged(this); modified=false; return true; return false; invoicerdoc.cpp 14. oldal

A dokumetum osztály adatellenőrző függvénye (check()) A dokumentum osztály ellenőrző függvénye egy hibaüzenetet ad vissza, ha hibásan töltötték ki a számlát. A nézet osztály ezt a függvényt hívja meg annak eldöntésére, hogy helyes-e a számla, azaz menthető-e. class InvoicerDoc : public QObject public: const QString filename() const return _filename; const char* check(); ; invoicerdoc.h const char* InvoicerDoc::check() if (_customer.isempty()) return "The invoice cannot be saved \n until a customer is specified."; if (_zip.isempty() _city.isempty() _street.isempty()) return "The invoice cannot be saved \n until the address is specified."; if (_invno.isempty()) return "The invoice cannot be saved \n until an invoice number is specified."; if (_items.count() ==0) return "The invoice cannot be saved \n without any item added."; return 0; invoicerdoc.cpp RTS/U$VWGX'YZ+V+X[ \C]E^ [_\ `GW$VW$\baEc dbe/fgh i j"h8kllm"n5ec o fp c h A querysave() saját függfény Ha az aktuális számlánkat még nem mentettük el, akkor új számla létrehozásakor (New), létező számla betöltésekor (Open), illetve kilépéskor (Quit) illik megkérdezni, mi legyen a nem mentett adatokkal. Ezt a kérdést a programban több helyen is fel kell tenni, ezért e kérdés felvetésére bevezetünk egy segédfüggvényt (querysave()) 15. oldal

class Invoicer : public QMainWindow Q_OBJECT invoicer.h /** overloaded for Message box on last window exit */ bool queryexit(); bool querysave(); ; bool Invoicer::querySave() if(doc->ismodified()) int r = QMessageBox::warning(0, "Warning", "There are unsaved changes\n Save them?", "Save", "Discard", "Cancel"); if (r==0) const char* err=doc->check(); if (err!=0) return false; if(doc->filename().isempty()) QString fn = QFileDialog::getSaveFileName(0, "*.inv", this); if(!fn.isempty()) return doc->saveas(fn); else return false; else return doc->save(); else if (r==1) return true; else return false; else return true; invoicer.cpp A querysave() visszatérési értéke hamis, ha nem engedélyezett a mentés. Ha a dokumentumot módosítottuk, akkor rákérdezünk, mi legyen a módosításokkal. Ha menteni szeretnénk a számlát, akkor először a dokumentum osztályban megvizsgáljuk, hogy a számla tartalma helyes-e. Hibás számla esetén nem engedélyezzük a mentést. Ha a számla hibátlan, akkor attól függően, hogy új számlát hoztunk-e létre, vagy létező számlát módosítottunk (van-e név a dokumentum osztály _filename adattagjában), meghívjuk a saveas((), vagy a save() függvények valamelyikét. A querysave() segédfüggvény elkészülte után módosítsuk a nézet osztályunkban a fájlkezelő slotokat. 16. oldal

A slotfilenew() módosítása void Invoicer::slotFileNew() if (!querysave()) return; statusbar()->message(tr("creating new file...")); doc->newdoc(); setcaption(doc->filename()); statusbar()->message(tr("ready.")); invoicer.cpp Ha a querysave() segédfüggvény értéke hamis, nem mentjük a fájlt. A főablak címe legyen az aktuális fájl neve. A slotfileopen() módosítása void Invoicer::slotFileOpen() //invoicer.cpp if (!querysave()) return; 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); invoicer.cpp A slotfilesave() módosítása void Invoicer::slotFileSave() if(doc->filename().isempty()) slotfilesaveas(); return; statusbar()->message(tr("saving file...")); const char* err=doc->check(); if(err==0) doc->save(); else QMessageBox::information(this,"Missing information", err, 1); statusbar()->message(tr("ready.")); invoicer.cpp Ha nincs betöltött fájl, akkor saveas(). Ha a doc nem találta hibásnak a számlát, akkor save(), egyébként hibaüzenet. A slotfilesaveas() módosítása 17. oldal

void Invoicer::slotFileSaveAs() statusbar()->message(tr("saving file under new filename...")); QString fn = QFileDialog::getSaveFileName(0, 0, this); if (!fn.isempty()) const char* err=doc->check(); if(err==0) doc->saveas(fn); setcaption(doc->filename()); else QMessageBox::information(this,"Missing information",err,1); else statusbar()->message(tr("saving aborted"), 2000); statusbar()->message(tr("ready.")); invoicer.cpp A slotfilequit() módosítása Ha az alkalmazásunk dokumentuma egy nem mentett számla, akkor mielőtt bezárnánk az alkalmazásunkat kérdezzünk rá, mi legyen ezzel a számlával. void Invoicer::slotFileQuit() statusbar()->message(tr("exiting application...")); if (!querysave()) return; statusbar()->message(tr("exiting application...")); qapp->quit(); statusbar()->message(tr("ready.")); invoicer.cpp qsrut rlv*wyx"z" ~ 8 ƒ ƒ ƒ Önálló feldogozásra javasoljuk az alábbi feladatok megoldását: számlatételek összegzése a view sum mezőjében tételműveletek engedélyezése/tiltása a listview tartalmának függvényében fájlkezelés során előforduló hibák kezelése 18. oldal

ˆ Š Œ Ž ' ' + $ + š 8œ/ ' 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, datevalidator.h, datevalidator.cpp, checkeditemdia.h, 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 15:56:41 2004 ###################################################################### TEMPLATE = app INCLUDEPATH +=. # Input HEADERS += checkeditemdia.h \ datevalidator.h \ invoicer.h \ invoicerdoc.h \ invoicerview.h INTERFACES += invitemdia.ui invoicerviewbase.ui SOURCES += datevalidator.cpp \ invoicer.cpp \ invoicerdoc.cpp \ invoicerview.cpp \ main.cpp IMAGES += images/new.png \ images/open.png \ images/save.png A projektet alkotó összetevők forrása letölthető a people.inf.elte.hu/nacsa honlapról. 19. oldal