Elemi alkalmazások fejlesztése III C++/ Qt alapú SDI alkalmazás készítése III. Készítette: Szabóné Nacsa Rozália Steingart Ferenc 1
Ami már kész van: Készítettünk egy Qt SDI alkalmazást. 2
Ami már kész van: Megterveztük a view osztály felhasználói felületét. 3
Ami már kész van: Megvalósítottuk a számla típust. 4
Ami már kész van: Megvalósítottuk a számlatétel típust. 5
Ami már kész van: #include "invoicerview.h" #include <qlineedit.h> #include <qlistview.h> InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) /** connect doc with the view*/ connect(doc, SIGNAL(documentChanged()), this, SLOT(slotDocumentChanged())); connect(customer, SIGNAL(textChanged(const QString&)), doc, SLOT(setCustomer(const QString&))); connect(zip, SIGNAL(textChanged(const QString&)), Összekapcsoltuk számlát (doc) doc, SLOT(setZip(const QString&))); és a view osztályt.... connect(fulfilled, SIGNAL(textChanged(const QString&)), doc, SLOT(setFulfilled(const QString&))); connect(dueto, SIGNAL(textChanged(const QString&)), doc, SLOT(setDueTo(const Qstring&))); 6
Ami már kész van: Megvalósítottuk a számlatétel felvitele, módosítása, törlése funkciókat. 7
Az alkalmazás osztálydiagramja QListViewItem InvoicItem InvoicerDoc ListViewInvoice Item InvoiceItem* _i; QDialog InvoicerView InvItemDia Invoicer 8
Ami még hátra van: (Számlafejléc tartalmának megadása) (Számlatétel hozzáadása) (Számlatétel módosítása) (Számlatétel törlése) Beviteli mezők ellenőr zése Számla mentése fájlba Számla betöltése fájlból 9
Beviteli mez ő k ellen ő r zése View osztály irányítószám (négyelem ű, reguláris) számlaszám (csak számjegy) dátumok (illeszkedés egy mintára+dátum ellenő rzés) Számlatétel dialógus darabszám (numerikus) egységár (numerikus) 10
Ellen ő r z ő objektumok: validátor ok Cél: adatbevitel korlátozása QObject QValidator QIntValidator QDoubleValidator Beépített validátorok. 11
QValidator: validate(), fixup() tiszta virtuális függvény virtual State validate (QString &txt, int &pos) const = 0; A txt szöveget ellenőrzi. Visszatérési értéke lehet: Invalid: a szöveg nem elfogadható Intermediate: a szöveg még jó lehet (közbüls ő állapot) Acceptable: a szöveg elfogadható virtual void fixup (QString &txt) const; Kijavítja a nem elfogadható szöveget. 12
Adatellen ő rzés lépései Ellenőrz ő objektum létr ehozása Ellenőrz ő objektum viselkedésének beállítása Ellenőrz ő objektum és az adatbeviteli mez ő összer endelése Példa (vázlat) invoicerview.h :... QIntvalidator* invnov;... //deklaráció invoicerview.cpp:... invnov = new QIntValidator(this)... //létrehozás... invno->setvalidator(invnov)... //összerendelés 13
Dátum ellen ő rzéséhez nincs beépített osztály. 14
QValidator osztály: State minta: 1111.11.11 abc 2003.04.06: 2003.04.06 Invalid Intermadiate Acceptable State 15
Ellen ő rz ő objektumok: validátorok Cél: adatbevitel korlátozása QObject QValidator QIntValidator QDoubleValidator DateValidator Beépített validátorok. Saját validátor 16
Az alkalmazás osztálydiagramja QListViewItem QValidator InvoicItem InvoicerDoc ListViewInvoice Item InvoiceItem* _i; DatumValidator QDialog InvoicerView InvItemDia Invoicer 17
Dátum ellen ő r z ő osztály létr ehozása 18
19
A DateValidator osztály deklaráció datevalidator.h A szül ő konstruktor hívása #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) //üres törzs A dátum validátort a QValidator osztályból származtatjuk. Adattag inicializálása virtual State validate(qstring &, int &) const; virtual void fixup(qstring &) const; private: bool match(const QChar &ch, int p) const; QString _pattern; Minta ; Mintaillesztés 20
A match() privát függvény implementációja bool DateValidator::match(const QChar &ch, int p) const if (p>=_pattern.length()) return false; if (_pattern[p]=='1') return ch.isdigit(); else return (ch == _pattern[p]); datevalidator.cpp minta: 1111.11.11 2003.04.06: 21
Avalidate() implementációja #include <qdatetime.h> #include "datevalidator.h" datevalidator.cpp 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) _pattern: 1111.11 11.11 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())) 2004.04 04.20 return Acceptable; else return Intermediate; else return Invalid; 22
A fixup() m ű velet implementációja void DateValidator::fixup (QString &txt) const QDateTime day = QDateTime::currentDateTime(); txt = day.tostring("yyyy") + "." + day.tostring("mm") + "." + day.tostring("dd"); datevalidator.cpp Ez a függvény az Enter leütésekor, hibás adat esetén kerül végrehajtásra. 23
Ellen ő r z ő objektumok létr ehozása A view osztályban létrehozunk két numerikus validátor adattagot az irányítószám és a számlaszám mezőkhöz, valamint egy dátum validátor adattagot a dátum típusú mezők ellenőrzésére. irányítószám: egy QRegExpValidator objektum az 1000..9999 értékek elfogadására (zipv) számlaszám: egy QIntValidator objektum tetszőleges egész értékek fogadására (invnov) dátumok: egy közös DateValidator objektum a default mintával és dátum ellenőrzéssel ( dv) 24
A módosított view osztály #include "datevalidator.h" invoicerview.h class InvoicerView : public InvoicerViewBase private: void initvalidators(); protected: DateValidator* dv; QRegExpValidator* zipv; QIntValidator* invnov; ; InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) : InvoicerViewBase(parent) initvalidators();... invoicerview.cpp 25
Validátorok inicializálása 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); invoicerview.cpp DateValidator* dv; QRegExpValidator* zipv; QIntValidator* invnov; dv=new DateValidator("1111.11.11",this); released->setvalidator(dv); fulfilled->setvalidator(dv); dueto->setvalidator(dv); 26
Ellen ő rzés adatbevitel végén class InvoicerView : public InvoicerViewBase... protected slots: void slotdocumentchanged(); void slotdocitemadded(invoiceitem*); void checkreleaseddate(); void checkfulfilleddate(); void checkduetodate(); invoicerview.cpp Csak akkor léphetünk ki az adatbeviteli mez ő b ő l, ha helyes az adat. ; 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())); connect( doc,signal(iteminserted(invoiceitem*)), this,slot(slotdocitemadded(invoiceitem*))); 27
InvoicerView:: checkreleaseddate() void InvoicerView::checkReleasedDate() invoicerview.cpp if (released->text()=="") QDateTime day = QDateTime::currentDateTime(); QString str = day.tostring("yyyy") + "." + Ha a kibocsátás dátuma üres, day.tostring("mm") + "." + akkor legyen ez a mai dátum. 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(); Ha a kibocsátás dátuma nem üres, de hibás, adjunk figyelmeztet ő üzenetet. 28
InvoicerView:: checkfulfilleddate() void InvoicerView::checkFulfilledDate() invoicerview.cpp QString str = fulfilled->text(); int p = 0; if(fulfilled->validator()->validate(str,p)!= QValidator::Acceptable && str!= "") QMessageBox::information( this, "InvoicerView", "Invalid date! \ndate format: \"yyyy.mm.dd\" "); fulfilled->setfocus(); A teljesítés dátuma lehet üres. 29
InvoicerView:: checkduetodate() void InvoicerView::checkDueToDate() invoicerview.cpp if (dueto->text()=="") QDateTime day = QDateTime::currentDateTime().addDays(8); QString str = day.tostring("yyyy") + "." + Ha day.tostring("mm") + "." + a kiegyenlítés day.tostring("dd"); dátuma üres, akkor 8 dueto->settext(str); napos fizetési határid ő t return; állítunk be. 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(); 30
Fordítás / Futtatás A számlán megvalósítottuk az ellen ő rzött adatbevitelt. A számlántételen még nincs adatellen ő rzés. 31
Számlatétel ellen ő rzése Qt designer invitemdia.ui UIC invitemdia.h Írás, olvasás Olvasás Generálás #includes Eszköz (tool) Generált forráskód Felhasználó forráskódja invitemdia. cpp A generált osztályba nem tudjuk az adatellen ő rzést betenni. invoicer.h invoicer.cpp 32
Modulszerkezet Qt designer invitemdia.ui UIC invitemdia.h Örökl ő dés cheked itmdia.h Írás, olvasás Olvasás Generálás #includes Eszköz (tool) Generált forráskód Felhasználó forráskódja invitemdia. cpp checked itemdia.cpp Az ellen ő rzést a származtatott osztályban valósítjuk meg. invoicer.h invoicer.cpp 33
Az alkalmazás osztálydiagramja QListViewItem QValidator InvoicItem ListViewInvoice Item DatumValidator QDialog InvoicerDoc InvoiceItem* _i; InvoicerView InvItemDia Invoicer Checked ItemDia 34
A CheckedItemDia osztály létrehozása 1 35
A CheckedItemDia osztály létrehozása 2 36
A CheckedItemDia osztály #ifndef CHECKEDITEMDIA_H #define CHECKEDITEMDIA_H checkeditemdia.h #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; ; A konstruktor törzsét is itt adjuk meg, ezért a konstruktor definícióját a checkeditemdia.cpp fájlból törölni kell. #endif 37
Az InvItemDia példányok lecser élése 38
Az InvItemDia példányok lecser élése #include "checkeditemdia.h" invoicer.cpp void InvoicerApp::slotItemsNew() statusbar()->message(tr("inserting a new invoice item...")); //InvItemDia dlg(this,0,true); CheckedItemDia dlg(this,0); if (dlg.exec() == QDialog::Accepted)... Ügyeljen arra, hogy a paraméterek száma is megváltozott!! void InvoicerApp::slotItemsEdit() statusbar()->message(tr("modifying current item...")); if (view->items->currentitem()) //InvItemDia dlg(this,0,true); CheckedItemDia dlg(this,0); InvoiceItem *ii =... 39
Fordítás / Futtatás A számlán megvalósítottuk az ellen ő rzött adatbevitelt. A számlántételen megvalósítottuk az adatellen ő rzés. 40
Doc/View technika: adatátvitel invoicerdoc.h class InvoicerDoc : public QObject... signals: void documentchanged(invoicerdoc* doc); public: const QString customer() const return _customer;... protected: QString _customer; ; Hozzáveszünk egy paramétert a documentchanged() szignálhoz. bool InvoicerDoc::load(const QString &filename) emit documentchanged(this); return true; invoicerdoc.cpp Azokon a helyeken, ahol hivatkozás történik a módosított függvényre, elvégezzük a szükséges módosítást. 41
Doc/View technika: adat lekérése class InvoicerDoc : public QObject... signals: void documentchanged(invoicerdoc* doc); public: const QString customer() const return _customer;... protected: QString _customer; ; invoicerdoc.h A dokumentumra mutató pointert a signal/slot mechanizmust kihasználva adjuk át a slotdocumentchanged() slotnak. InvoicerView::InvoicerView(QWidget *parent, InvoicerDoc *doc) :... connect(doc, SIGNAL(documentChanged(InvoicerDoc*)), this, SLOT(slotDocumentChanged(InvoicerDoc*)));...... void InvoicerView::slotDocumentChanged(InvoicerDoc* doc) customer->settext( doc->customer() );... invoicerview.cpp A dokumentumra mutató pointer segítségével lekérdezhetjük a számla (doc) adatait. 42
Az adatbeviteli mez ő k aktualizálása void InvoicerView::slotDocumentChanged(InvoicerDoc* doc) 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 43
Fájl m ű veletek 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 ( InvoicerApp) slotfilenew slotfilesave slotfilesaveas slotfileopen 44
A dokumentum osztály fájlkezel ő m ű veleteit már el ő készítettük. 45
Ezeket a m ű veleteket nekünk kell implementálni. 46
Új adattag: _filename invoicerdoc.h class InvoicerDoc : public QObject... public:... const QString dueto() const return _dueto; const QString filename() const return _filename; protected:... QString _dueto; QString _filename; A dokumentum osztályt kib ő vítjük egy új ; adattaggal, amelyben az aktuális számlát tartalmazó fájl nevét tároljuk. 47
A newdoc() implementációja 1 2 3 void InvoicerDoc::newDoc() _customer = _zip = _city = _street = _invno= _released = _fulfilled = _dueto = ""; _items.clear(); _filename=""; modified = false; emit documentchanged(this); invoicerdoc.h Kiüríti a dokumentumot, és a módosításról értesíti a view osztályt. 48
A save() implementációja 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; #include <fstream> return false; using namespace std; invoicerdoc.h Bendegúz Gyümölcsfeldolgozó Kft. 1234 Budapest Cseresznyefa utca 13. 67890 2004.05.06 2004.05.06 2004.05.14 2 Alma kg 5 10 12 Körte doboz 4 120 25 49
A saveas() implementációja invoicerdoc.h bool InvoicerDoc::saveAs(const QString &filename) _filename=filename; return save(); 50
A load() függvény implementációja 1 bool InvoicerDoc::load(const QString &filename) ifstream f; char buf[1024], buf2[1024]; f.open(filename); invoicerdoc.cpp A számla-fejléc adatok beolvasása 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);... Bendegúz Gyümölcsfeldolgozó Kft. 1234 Budapest Cseresznyefa utca 13. 67890 2004.05.06 2004.05.06 2004.05.14... 51
A load() függvény implementációja 2... //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; Üzenetet küldünk a külvilág számára arról, hogy a számla megváltozott. invoicerdoc.cpp Számlatételek beolvasása... 2 Alma kg 5 10 12 Körte doboz 4 120 25 52
Adatellen ő rzés: check() invoicerdoc.cpp 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; 53
A querysave() privát függvény 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) // "Save" invoicer.cpp... Lásd következ ő dia else if (r==1) // "Discard" return true; else // "Cancel" return false; else return true; // Nincs változás 54
A querysave() privát függvény - folytatás bool Invoicer::querySave()... if (r==0) Kitöltöttük a const char* err=doc->check(); kötelez ő adatokat? 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)... invoicerdoc.cpp 55
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.")); invoicerdoc.cpp 56
A slotfileopen() módosítása void Invoicer::slotFileOpen() if (!querysave()) return; statusbar()->message(tr("opening file...")); invoicerdoc.cpp 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); 57
A slotfilesave() módosítása void Invoicer::slotFileSave() statusbar()->message(tr("saving file...")); doc->save(); statusbar()->message(tr("ready.")); invoicerdoc.cpp 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.")); 58
A slotfilesaveas() módosítása void Invoicer::slotFileSaveAs() statusbar()->message(tr("saving file under new filename...")); QString fn = QFileDialog::getSaveFileName(0, 0, this); if (!fn.isempty()) doc->saveas(fn); else statusbar()->message(tr("saving aborted"), 2000); statusbar()->message(tr("ready.")); invoicerdoc.cpp const char* err=doc->check(); if (err==0) doc->saveas(fn); setcaption(doc->filename()); else QMessageBox::information(this,"Missing information",err,1); 59
A slotfilequit() módosítása void Invoicer::slotFileQuit() if (!querysave()) return; statusbar()->message(tr("exiting application...")); qapp->quit(); statusbar()->message(tr("ready.")); invoicerdoc.cpp 60
Ami (biztosan) kimaradt... számlatételek összegzése a view sum mezőjében a tételműveletek engedélyezése/tiltása fájlkezelési hibák figyelése 61
Vége 62