Elemi alkalmazások fejlesztése III. Egy ablakos alkalmazás készítése II. C++ / Qt / KDevelop felhasználásával készítette: Szabóné Nacsa Rozália lektorálta: Párniczky Krisztina 1
Fájlkezelés Olvasás 2
A Form osztály deklarációja class Form: public QVBox { Q_OBJECT form.h public: Form(QWidget *parent=0, const char *name=0); private: QHBox *hbox; QPushButton *quitbutton; QPushButton *loadbutton; QTextEdit * textedit; QFile *file; QTextStream *stream; public slots: void load(); ; #include <qwidget.h> #include <qvbox.h> class QHBox; class QTextEdit; class QPushButton; class QFile; class QTextStream; form.h 3
A Form osztály implementációja Form::Form(QWidget *parent, const char *name):qvbox(parent,name) { setmargin(6); setspacing(6); textedit = new QTextEdit(this); textedit->setreadonly( TRUE ); form.cpp #include <qhbox.h> #include <qtextedit.h> #include <qpushbutton.h> hbox = new QHBox(this); hbox->setmargin(6); hbox->setspacing(6); quitbutton = new QPushButton("Quit",hbox); loadbutton = new QPushButton("Load",hbox); connect(quitbutton,signal(clicked()),this,slot(quit())); connect(loadbutton,signal(clicked()),this,slot(load())); #include <qfile.h> #include <qtextstream.h> #include <qstring.h> #include <qfiledialog.h> #include "form.h" 4
A Form osztály implementációja void Form::load() { form.cpp qwarning("not implemented yet!"); textedit->clear(); QString filename = QFileDialog::getOpenFileName(QString::null, "Text (*.txt)", this, "file open", "Read - File open"); if (!filename.isempty()) { file = new QFile(filename); if (file->open(io_readonly)) { stream = new QTextStream(file); while (!stream->eof()) { textedit->insert(stream->readline() + "\n"); 5
Legyen Legyen Ön is milliomos példa Szerkeszthet ő szöveg Gomb + kép LCD kijelző Gomb csoport Gomb + szöveg Radio Button 6
Állapotdiagram KOV Válaszoló Tovább megy PASSZ JVAL RVAL VEG Befejezte Bezár ZAR 7
Új projekt létrehozása Qt Designerrel File/New/C++ Project:mill File/New/Widget: MillMain 8
F ő program beillesztése 9
A QtDesigner ablakai Távtartó 10
Az ablak felépítése endbutton text moneyvalue questionlabel ansgroup nextbutton 11
A generált f ő program #include <qapplication.h> #include "millmain.h" main.cpp int main( int argc, char ** argv ) { QApplication a( argc, argv ); MillMain w; w.show(); a.connect( &a, SIGNAL( lastwindowclosed() ), &a, SLOT( quit() ) ); return a.exec(); 12
Signál/Slot kötések this::endgame() this::checkanswer(int) this::nextquestion() 13
Saját slotok beillesztése - Edit/Slots Function: CheckAnswer(int) Return Type: void Specifier: virtual Function: endgame() Access: public Return Type: void Specifier: virtual Access: public Function: nextquestion() Return Type: void Specifier: virtual Access: public 14
Edit/Connections Sender: nextbutton Signal: clicked() Receiver: MillMain Slot: nextquestion() Sender: ansgroup Signal: clicked(int) Receiver: MillMain Slot: checkanswer(int) Sender: endbutton Signal: clicked() Receiver: MillMain Slot: endgame() connect( nextbutton, SIGNAL( clicked() ), this, SLOT( nextquestion() ) ); connect( ansgroup, SIGNAL( clicked(int) ), this, SLOT( checkanswer(int) ) ); connect( endbutton, SIGNAL( clicked() ), this, SLOT( endgame() ) ); 15
Qt designer millmain.ui.h millmain.ui form.ui Itt adjuk meg az eseménykezelők implemenációját. UIC millmain.h Írás, olvasás Olvasás Generálás #includes Eszköz (tool) Generált forráskód Felhasználó forráskódja millmain.cpp main.cpp 16
Fordítás/Futtatás TEMPLATE = app INCLUDEPATH +=. mill.pro # Input HEADERS += millmain.ui.h INTERFACES += millmain.ui SOURCES += main.cpp 1. qmake project 2. qmake mill.pro 3. make 4../mill 17
A Qt Designer és a KDevelop összekapcsolása 18
Project/New project... 19
Vegyük ki a projektből a mill.cpp programot. 20
main.cpp millmain.ui millmain.ui.h home.png Másoljuk át a projekt alá a Qt Designer-ben elkészített programokat. 21
A projektbe fel kell venni a fájlokat. Az itt található fájlok nem feltétlenül részei a projektnek. 22
Fordítás: Build/ Rebuild project...(f8) 23
Futtatás: Build/ Execute Main program( Shift F9) 24
Új osztály bevezetése QApplication QuestionIterator MillMain Bevezetünk egy új osztályt a kérdések kezelésére. 25
Question típus (struct) question: a kérdés szövege answers: a lehetséges válaszokat tartalmazó négyelem ű tömb good: a helyes válasz indexe value: a kérdés értéke explanation: további információ a kérdéssel kapcsolatban struct Question { string question; string answers[4]; int good; int value; string explanation; ; 26
QuestionIterator típus Bejáró műveletek first(): Az els ő kérdésre áll. next(): A következ ő kérdésre áll. end(): Visszaadja, hogy a kérdéssor végére értünk-e. current(): Az aktuális kérdést adja vissza. Segédfüggvények: fallbackvalue: Hibás válasz esetén visszaadja a nyeremény összegét. previousvalue: Megállás esetén visszaadja a nyeremény összegét. 27
A QuestionIterator beillesztése a projektbe 28
Qt designer ui.h -s modulszerkezet millmain.ui.h millmain.ui form.ui questioniterator.h Az alkalmazásspecifius funkciókat a millmain.ui.h implementációs fájlban adjuk meg. UIC millmain.h questioniterator.cpp Írás, olvasás Olvasás Generálás #includes Eszköz (tool) Generált forráskód Felhasználó forráskódja millmain.cpp main.cpp 29
30
class QFile; class QTextStream; QuestionIterator: definíció questioniterator.h class QuestionIterator { public: QuestionIterator(const QString& fn); ~QuestionIterator(); void first(); void next(); bool end(); const Question& current(); int fallbackvalue(); int previousvalue(); private: Question _current; QFile *file; QTextStream *stream; int _level; #include <qstring.h> #include <qtextstream.h> using namespace std; struct Question { QString question; QString answers[4]; int good; int value; QString explanation; ; ; static const int _maxlevels=16; static const int money[ _maxlevels ]; void readnext(); 31
Kifizethet ő összegek tömbje questioniterator.cpp const int QuestionIterator::money[_maxlevels]= {0,5000,10000,25000,50000,100000, 200000,300000,500000,800000,1500000, 3000000,5000000,10000000,20000000,40000000; QuestionIterator: konstruktor QuestionIterator::QuestionIterator(const QString& fn):_level(0){ file = new QFile(fn); questioniterator.cpp QuestionIterator: destruktor QuestionIterator::~QuestionIterator(){ if(stream) delete stream; if (file){ file->close(); delete file; questioniterator.cpp 32
void QuestionIterator::first() { if (!file) return; if(!file->open(io_readonly)){ qwarning(qstring("warning: Failed to open '%1'").arg(file->name())); file->close(); return; _level=0; if (file) { stream = new QTextStream(file); readnext(); void QuestionIterator::next(){ readnext(); bool QuestionIterator::end() { return (_level == _maxlevels); QuestionIterator: Bejárók questioniterator.cpp const Question& QuestionIterator::current(){ return _current; 33
QuestionIterator: segédfüggvények int QuestionIterator::fallBackValue() { return money[(_level/5)*5]; questioniterator.cpp int QuestionIterator::previousValue() { return money[_level-1]; const int QuestionIterator::money[_maxlevels]= {0,5000,10000,25000,50000,100000, 200000,300000,500000,800000,1500000, 3000000,5000000,10000000,20000000,40000000; 34
<kérdés szövege> <els ő válasz> <második válasz> <harmadik válasz> <negyedik válasz> <helyes válasz indexe (0..3)> <magyarázat> Kérdések fájlja Melyik Andrew Lloyd Webber legújabb műve? Whistle down the Window The Beautiful Game Evita Les Miserables 1 A Les Mis nem Webber, hanem Schönberg-Boublil musical. A B.G. bemutatója 2000. szeptemberében volt. < Mennyi ideig tartott a harminc éves háború?... 35
Beolvasó m ű velet void QuestionIterator::rednext() { if (!file) return; if (_level!= _maxlevels) { _current.question=stream->readline(); for (int i=0; i<4; i++) { _current.answers[i]= stream->readline(); _current.good = stream->readline().toint(); _current.explanation=""; QString line = stream->readline(); while(line[0]!= '<') { _current.explanation+='\n'; _current.explanation+=line; line = stream->readline() _level++; _current.value=money[_level]; questioniterator.cpp 36
Eseménykezel ő k implementálása 37
Adattagok és függvények beillesztése class MillMain : public QWidget { Q_OBJECT public: MillMain(QWidget *parent=0, const char *name=0); ~MillMain(); public slots: void newquestion(); void endgame(); void checkanswer(int); millmain.h protected: QuestionIterator* _qi; bool canclose; private: void displayquestion(); ; Ezt a fájlt az uic generálja 38
Qt Designer: függvény megadása Edit/Slots... 39
Qt Designer: Változó megadása 40
41
Konstruktor - MillMain::init() void MillMain::init() { QString filename =QFileDialog::getOpenFileName(QString::null, tr(qstring::fromutf8("questions (*.txt)")),this, tr(qstring::fromutf8("file Open")), tr(qstring::fromutf8( "Milliomos1: Kérdés fájl kiválasztása"))); if (!filename.isempty()) { _qi = new QuestionIterator(filename); _qi->first(); displayquestion(); else { questionlabel->settext("nincs kérdés!"); for (int i=0; i<4; i++) { ((QRadioButton*)ansGroup->find(i))->setText(""); ((QRadioButton*)ansGroup->find(i))->setChecked(false); moneyvalue->display(_qi->current().value); text->settext(""); nextbutton->setenabled(false); ansgroup->setenabled(false); endbutton->setenabled(false); canclose =false; millmain.ui.h Ez a program automatikusan lefut a konstruktor után. 42
MillMain::displayQuestion() - tervezés ha még nem értünk a kérdés iterátor végére az aktuális kérdés adatainak megjelenítése a megfelel ő widgetekben a next nyomógomb letiltása az ansgroup rádiógomb-csoport engedélyezése az endbutton nyomógomb engedélyezése ha a kérdésiterártor végére értünk a nextbutton letiltása az ansgroup rádiógomb-csoport engedélyezése a vége üzenet kiírása 43
MillMain::displayQuestion() - kódolás void MillMain::displayQuestion() { if (!_qi->end()) { questionlabel->settext(_qi->current().question); for (int i=0; i<4; i++) { ((QRadioButton*)ansGroup->find(i))->setText(_qi->current().answers[i]); ((QRadioButton*)ansGroup->find(i))->setChecked(false); moneyvalue->display(_qi->current().value); text->settext(""); nextbutton->setenabled(false); ansgroup->setenabled(true); endbutton->setenabled(true); else { nextbutton->setenabled(false); moneyvalue->setsegmentstyle(qlcdnumber::filled); text->settext("\n GAME OVER \n"); millmain.ui.h 44
MillMain::nextQuestion() connect( nextbutton, SIGNAL( clicked() ), this, SLOT( nextquestion() ) ); void MillMain::nextQuestion() { _qi->next(); displayquestion(); millmain.ui.h 1. Ráállunk a következ ő kérdésre 2. Megjelenítjük a kérdést 45
MillMain::checkAnswer(int) - tervezés connect( ansgroup, SIGNAL( clicked(int) ), this, SLOT( checkanswer(int) ) ); az aktuális kérdéshez tartozó magyarázat megjelenítése a válasz ellenőrzése jó válasz esetén: a nextbutton gomb engedélyezése rossz válasz esetén: a nyeremény megjelenítése a vége üzenet kiírása az ansgroup rádiógomb-csoport letiltása az endbutton nyomógomb letiltása 46
MillMain::checkAnswer(int) - kódolás void MillMain::checkAnswer( int sel ) { text->settext(_qi->current().explanation); ansgroup->setenabled(false); endbutton->setenabled(false); if (sel ==_qi->current().good) { nextbutton->setenabled(true); else { moneyvalue->display(_qi->fallbackvalue()); moneyvalue->setsegmentstyle(qlcdnumber::filled); text->append("\n GAME OVER\n"); millmain.ui.h 47
MillMain::endGame() - tervezés connect( endbutton, SIGNAL( clicked() ), this, SLOT( endgame() ) ); a nyeremény megjelenítése a nextbutton gomb letiltása az ansgroup rádiógomb-csoport letiltása az endbutton nyomógomb letiltása az aktuális kérdéshez tartozó magyarázat megjelenítése a vége üzenet kiírása 48
MillMain::endGame() - kódolás millmain.ui.h void MillMain::endGame(){ moneyvalue->display(_qi->previousvalue()); moneyvalue->setsegmentstyle(qlcdnumber::filled); nextbutton->setenabled(false); ansgroup->setenabled(false); endbutton->setenabled(false); text->settext(_qi->current().explanation); text->append("\n GAME OVER"); canclose = true; 49
closeevent() felüldefiniálása void MillMain::closeEvent( QCloseEvent *event ) { if(canclose) emit close(); millmain.ui.h 50
Fordítás/Futtatás 51
Ellen ő rzött adatkezelés 52
Ellen ő rzött adatkezelés Csak számot lehet begépelni. Nulla osztó esetén letiltjuk a számol gombot. A szám legyen 1000- nél kisebb. 53
Validátorok QValidator QIntValidator QDoubleValidator QRegExpValidator 54
Vezérl ő k op1 op2 result calcbutton endbutton 55
Signál/slot kapcsolatok... // signals and slots connections connect( calcbutton, SIGNAL( clicked() ), this, SLOT( calculate() ) ); connect( endbutton, SIGNAL( clicked() ), this, SLOT( close() ) ); connect( op1, SIGNAL( textchanged(const QString&) ), this, SLOT( enablecalcbutton(const QString&) ) ); connect( op2, SIGNAL( textchanged(const QString&) ), this, SLOT( enablecalcbutton(const QString&) ) );... 56
NumMain osztály #ifndef NUMMAIN_H #define NUMMAIN_H nummain.h #include <nummainbase.h> #include <qvalidator.h> class NumMain : public NumMainBase { public: NumMain(QWidget *parent=0,const char *name=0); public slots: void calculate(); void enablecalcbutton(const QString &); private: QIntValidator *v; ; #endif 57
NumMain konstruktor A konstruktor feladatai: validátor objektum létrehozása a validátor hozzárendelése a soreditorhoz NumMain::NumMain(QWidget *parent,const char *name): NumMainBase(parent,name) { v=new QIntValidator(this); op1->setvalidator(v); op2->setvalidator(v); nummain.cpp 58
calculate() slot A calc nyomógomb clicked() szignáljához kötött slot feladatai: Számmá konvertálja a soreditor szövegét. Kiszámítja az összeget. Megjeleníti az eredményt a képernyőn. void NumMain::calculate() { result->display(op1->text().toint() / op2->text().toint()); cnummain.cpp 59
enablecalcbutton() Az op1 op2 soreditorok textchanged() szignáljához kötött slot feladatai: Számmá konvertálja a soreditor szövegét. A Számol gombot engedélyezi / letiltja void NumMain::enableCalcButton(const QString &) { calcbutton->setenabled(op2->text().toint() > 0 && op2->text().toint() < 1000 && op1->text().toint() >= 0 && op1->text().toint() < 1000); nummain.cpp 60
F ő program #include <qapplication.h> #include "nummain.h" main.cpp int main( int argc, char ** argv ) { QApplication a( argc, argv ); NumMain *w = new NumMain; w->show(); a.connect( &a, SIGNAL( lastwindowclosed() ), &a, SLOT( quit() ) ); return a.exec(); 61
Vége 62