Tartalomjegyzék FELADAT...2 Elvárások...2 TERVEZÉS ÉS IMPLEMENTÁLÁS...2 Megjelenési terv...2 Grafikus felület készítése...3 Modulszerkezet...3 Osztály diagram...3 MillMain form...4 Vezérlő k elrendezése...4 Vezérl ő elemek és kezdeti beállításaik...4 Állapot diagram...5 Állapotok...6 A MillMain konstruktora - init()...7 A MillMain close() eseményének felüldefiniálása...7 A main program kódja...7 MillMain form esemény-kezelő i...8 A nextbutton nyomógomb esemény-kezelése...8 Az ansgroup rádiógomb-csoport esemény-kezelése...8 Az endbutton nyomógomb esemény-kezelése...9 QuestionIterator osztály...10 questioniterator.h...10 questioniterator.cpp...11 A milmmain.ui.h implementációs fájl kódja...11 Az alkalmazás projekt-leíró fájlja: mill.pro...14 A milmmain.ui interface fájl kódja...15
Feladat Készítsünk egy olyan alkalmazást, amely szimulálja a Legyen ön is milliomos! játékot! Az els ő kérdés helyes megválaszolása esetén 5.000.-Ft, az ötödiknél 100.000.-Ft, a tizedik helyes válasz után pedig 1.500.000-Ft a játékos nyereménye. A milliomos-jelöltek egymás után válaszolnak a kérdésekre, de arra is lehetőség van, hogy valaki a körben passzoljon, azaz lemondjon a válaszadás lehetőségéről. Ebben az esetben, az addigi nyereménye megmarad, és a következ ő játékos kerül sorra. A kérdések nehézségi szintje egyre emelkedik, de ezzel arányban a nyereményösszeg is, a következőképpen: 1. 5.000 2. 10.000 3. 25.000 4. 50.000 5. 100.000 (garantált) 6. 200.000 7. 300.000 8. 500.000 9. 800.000 10. 1.500.000 (garantált) 11. 3.000.000 12. 5.000.000 13. 10.000.000 14. 20.000.000 15. 40.000.000 (garantált) A nyeremények bruttó összegben értendők. Elvárások A dialógus ablak elemeinek helyes beállításával biztosítsa a játékszabályok betartását. A Következ ő gombra csak helyes válasz után lehessen kattintani. Az alkalmazás automatikusan számolja ki a nyereményt, figyelembe véve, hogy a játékos passzolt, hibázott, vagy helyesen válaszolt. A kérdés megválaszolása után jelenjen meg egy kis magyarázat. ( Vágó szimulátor ). Helyes válasz után mindenképpen kell kérni egy új kérdést. (ha van). Egy-egy kérdés feltétele után a játékosnak vagy válaszolni, vagy kilépni szabad. Kilépéskor ne záródjon be azonnal az alkalmazás, a játékosnak legyen módja tetszőleges ideig nézegetni az eredményt. Tervezés és implementálás Megjelenési terv A feladatot egy ablakos alkalmazással oldjuk meg.
Grafikus felület készítése Készítünk egy, a Qt osztályainak kezelésére alkalmas projektet. A projekt készítését a Qt Designerrel és a qmake eszköz használatával oldjuk meg. A feladat megoldásánál az alkalmazásspecifikus feladatokat az un. ui.h -s technika alkalmazásával valósítjuk meg. (A másik technika a származtatásos technika lenne.) Modulszerkezet Osztály diagram
MillMain form Vezérlők elrendezése Vezérl ő elemek és kezdeti beállításaik Név Funkció Típus Felirat Egyéb nextbutton tovább lépés QPushButton Következ ő endbutton kilépés QPushButton home.png moneyvalue nyeremény QLCDNumber 0 numdigits:9 questionlabel kérdés QTextEdit ans1 1. válasz QRadioButton 1 Els ő válasz ans2 2. válasz QRadioButton Második válasz ans3 3. válasz QRadioButton Harmadik válasz ans4 4. válasz QRadioButton Negyedik válasz ansgroup rádiógomb csoport QButtonGroup Kattintson a megfelel ő válaszra MillMainBaseLayout elrendezés QVBoxLayout Layoutxx elrendezés QHBoxLayout Layoutxx elrendezés QVBoxLayout ansgrouplayout elrendezés QGridLayout Layoutxx elrendezés QGridLayout 1 Figyelni kell, hogy az ans1, ans2, ans3, ans4 indexei az ansgroup-ban rendre 0,1,2,3 legyenek.
Állapot diagram Név Röv Kiváltó Feltétel vezérlő Jól Válaszol JVAL ansgroup in: ansgroup out: explanation out: moneyvalue Rosszul válaszol RVAL ansgroup in: ansgroup out: explanation out: moneyvalue Passzol PASSZ endbutton in: endbutton out: explanation out: moneyvalue Bezárás ZÁR x in: Close File/Close (Alt+F4) Következ ő kérdés bekérése KÖV nextbutton in: nextbutton out: explanation out: moneyvalue Elfogyott VEG endbutton in: endbutton out: explanation out: moneyvalue
Állapotok 1. név: megj: leírás: invariáns: 2. név: megj: leírás: invariáns: 4. név: megj: leírás: invariáns: Válaszoló állapot Válaszolás előtti állapot Az ansgroup és az endbutton aktív. Az ansgroup közül egyik sincs bejelölve. Az összes többi vezérl ő inaktív. Csak egyszer lehet rákattintani az ansgroup-ra, utána azonnal inaktív lesz. (A válaszadó nem gondolhatja meg magát.) Tovább mehet állapot A következ ő kérdés bekérése előtti állapot A játékos megtekintheti az előő z kérdésre adott magyarázatot és a nyeremény eddigi állását. Mindenképpen meg kell néznie a következ ő kérdést, ezért csak a nextbutton aktív, az összes többi vezérl ő inaktív. Bezár állapot A játék befejezése utáni, az alkalmazásból való kilépés előtti állapot. A játékos akkor kerül ebbe az állapotba, amikor passzolás, rossz válasz vagy az összes kérdés megválaszolása után megtekintette (és tudomásul vette) a nyeremény összeget, kielemezték a magyarázatot, s már csak az maradt hátra, hogy jelezze, kiléphetünk az alkalmazásból. Ebben az állapotban csak a bezárás tevékenységet lehet valamelyik erre alkalmas vezérlővel (x, File/Close; Alt+F4) kiválasztani.
A MillMain konstruktora - 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); qdebug("set can close false"); canclose =false; A MillMain close() eseményének felüldefiniálása void MillMain::closeEvent( QCloseEvent *event ) if(canclose) emit close(); A main program kódja #include <qapplication.h> #include "millmain.h" int main( int argc, char ** argv ) QApplication a( argc, argv ); MillMain *main = new MillMain(); QObject::connect(main,SIGNAL(close()),&a,SLOT(quit())); a.setmainwidget(main); main->show(); return a.exec();
MillMain form esemény-kezelői A nextbutton nyomógomb esemény-kezelése Kiváltó vezérl ő és esemény: nextbutton, Click Bemen ő adatok: Kimen ő adatok: Rövid leírás: Elkéri a QuestionIterator következ ő elemét és egy megjeleníti azt. A kérdés megjelenítéséért felelős displayquestion() privát függvény feladatai. ha van még kérdés az aktuális kérdés adatainak megjelenítése a megfelel ő widgetekben a nextbutton letiltása az ansgroup rádiógomb-csoport engedélyezése az endbutton nyomógomb engedélyezése ha nincs több kérdés a nextbutton letiltása az ansgroup rádiógomb-csoport engedélyezése a vége üzenet kiírása void MillMain::nextQuestion() _qi->next(); displayquestion(); 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"); Az ansgroup rádiógomb-csoport esemény-kezelése Kiváltó vezérl ő és esemény: Kattintás a gomb csoportra Bemen ő adatok: Kimen ő adatok: Rövid leírás: A válasz megjelenítése után a játékos eldöntheti, hogy válaszol a kérdésre, vagy passzol. Ha válaszol, akkor csak egyszer kattinthat a gomb csoportra. A válasz alapján eldöntend ő, mely vezérlők lsznek aktívak. ill. inaktívak. A válasz ellenőrzése
az aktuális kérdéshez tartozó magyarázat (explanation) megjelenítése az ansgroup rádiógomb-csoport letiltása az endbutton nyomógomb letiltása jó válasz esetén: a nextbutton gomb engedélyezése rossz válasz esetén: a nyeremény (moneyvalue) megjelenítése a vége üzenet kiírása 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"); Az endbutton nyomógomb esemény-kezelése Kiváltó vezérl ő és esemény: Kattintás az endbutton-ra Bemen ő adatok: Kimen ő adatok: Rövid leírás: Ezt a slotot akkor hajtjuk végre, ha elfogyott a kérdés, a játékos rosszul válaszol, vagy passzolt. Az három esetnek megfelelően kiszámoljuk és megkjelenítjük az eredményt. A close kivételével minden vezérlőt inaktívra állítunk. a nyeremény kiszámítása, 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 alkalmazás bezárás engedélyezése 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;
QuestionIterator osztály questioniterator.h #ifndef QUESTIONITERATOR_H #define QUESTIONITERATOR_H #include <qstring.h> #include <qtextstream.h> using namespace std; struct Question QString question; QString answers[4]; int good; int value; QString explanation; ; class QFile; class QTextStream; 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; ; #endif static const int _maxlevels=16; static const int money[ _maxlevels ]; void readnext();
questioniterator.cpp #include "questioniterator.h" #include <qfile.h> #include <qtextstream.h> const int QuestionIterator::money[_maxlevels]= 0,5000,10000,25000,50000,100000, 200000,300000,500000,800000,1500000, 3000000,5000000,10000000,20000000,40000000; QuestionIterator::QuestionIterator(const QString& fn): _level(0) file = new QFile(fn); QuestionIterator::~QuestionIterator() if(stream) delete stream; if (file) file->close(); delete file; 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(); A milmmain.ui.h implementációs fájl kódja /**************************************************************************** ** ui.h extension file, included from the uic-generated form implementation. ** ** If you wish to add, delete or rename functions or slots use ** Qt Designer which will update this file, preserving your code. Create an ** init() function in place of a constructor, and a destroy() function in ** place of a destructor. *****************************************************************************/ void MillMain::nextQuestion() _qi->next();
displayquestion(); void MillMain::checkAnswer( int sel ) text->settext(_qi->current().explanation); if (sel ==_qi->current().good) nextbutton->setenabled(true); endbutton->setenabled(false); else moneyvalue->display(_qi->fallbackvalue()); moneyvalue->setsegmentstyle(qlcdnumber::filled); text->append("\n GAME OVER\n"); ansgroup->setenabled(false); endbutton->setenabled(false); 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"); qdebug("set can close true"); canclose = true; 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"); 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); qdebug("set can close false"); canclose =false; void MillMain::closeEvent( QCloseEvent *event ) if(canclose) emit close();
bool QuestionIterator::end() return (_level == _maxlevels); const Question& QuestionIterator::current() return _current; int QuestionIterator::fallBackValue() return money[(_level/5)*5]; int QuestionIterator::previousValue() return money[_level-1]; void QuestionIterator::readnext() 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]; Az alkalmazás projekt-leíró fájlja: mill.pro TEMPLATE = app DEPENDPATH += src INCLUDEPATH +=. src # Input HEADERS += src/millmain.ui.h src/questioniterator.h INTERFACES += src/millmain.ui SOURCES += src/main.cpp src/questioniterator.cpp
A milmmain.ui interface fájl kódja <!DOCTYPE UI><UI version="3.3" stdsetdef="1"> <class>millmain</class> <widget class="qwidget"> <cstring>millmain</cstring> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>382</width> <height>371</height> </rect> <property name="caption"> <string>legyen Ön is milliomos</string> <grid> <cstring>unnamed</cstring> <widget class="qlayoutwidget" row="0" column="0"> <cstring>layout4</cstring> <hbox> <cstring>unnamed</cstring> <widget class="qtextedit"> <cstring>text</cstring> <property name="readonly"> <bool>true</bool> <widget class="qlayoutwidget"> <cstring>layout3</cstring> <vbox> <cstring>unnamed</cstring> <widget class="qpushbutton"> <cstring>endbutton</cstring> <property name="text"> <string></string> <property name="pixmap"> <pixmap>home.png</pixmap>
<spacer> <cstring>spacer1</cstring> <property name="orientation"> <enum>vertical</enum> <property name="sizetype"> <enum>expanding</enum> <property name="sizehint"> <size> <width>20</width> <height>31</height> </size> </spacer> <widget class="qlcdnumber"> <cstring>moneyvalue</cstring> <property name="minimumsize"> <size> <width>0</width> <height>40</height> </size> <property name="font"> <font> <pointsize>28</pointsize> </font> <property name="numdigits"> <number>9</number> </vbox> </hbox> <widget class="qlabel" row="1" column="0"> <cstring>questionlabel</cstring> <property name="frameshape"> <enum>box</enum> <property name="frameshadow"> <enum>sunken</enum> <property name="text"> <string></string> <property name="alignment"> <set>aligncenter</set> <widget class="qlayoutwidget" row="3" column="0">
<cstring>layout6</cstring> <hbox> <cstring>unnamed</cstring> <spacer> <cstring>spacer2</cstring> <property name="orientation"> <enum>horizontal</enum> <property name="sizetype"> <enum>expanding</enum> <property name="sizehint"> <size> <width>181</width> <height>20</height> </size> </spacer> <widget class="qpushbutton"> <cstring>nextbutton</cstring> <property name="text"> <string>következ </string> </hbox> <widget class="qbuttongroup" row="2" column="0"> <cstring>ansgroup</cstring> <property name="title"> <string>kattintson a megfelel válaszra!</string> <grid> <cstring>unnamed</cstring> <widget class="qlayoutwidget" row="0" column="0"> <cstring>layout5</cstring> <grid> <cstring>unnamed</cstring> <widget class="qradiobutton" row="0" column="0"> <cstring>ans1</cstring> <property name="text">
<string>els válasz</string> <widget class="qradiobutton" row="0" column="1"> <cstring>ans2</cstring> <property name="text"> <string>második válasz</string> <widget class="qradiobutton" row="1" column="0"> <cstring>ans3</cstring> <property name="text"> <string>harmadik válasz</string> <widget class="qradiobutton" row="1" column="1"> <cstring>ans4</cstring> <property name="text"> <string>negyedik válasz</string> </grid> </grid> </grid> <connections> <connection> <sender>nextbutton</sender> <signal>clicked()</signal> <receiver>millmain</receiver> <slot>nextquestion()</slot> </connection> <connection> <sender>ansgroup</sender> <signal>clicked(int)</signal> <receiver>millmain</receiver> <slot>checkanswer(int)</slot> </connection> <connection> <sender>endbutton</sender> <signal>clicked()</signal> <receiver>millmain</receiver> <slot>endgame()</slot> </connection> </connections> <includes> <include location="local" impldecl="in implementation">questioniterator.h</include> <include location="global" impldecl="in implementation">qstring.h</include> <include location="global" impldecl="in implementation">qfiledialog.h</include> <include location="global" impldecl="in implementation">qradiobutton.h</include>
<include location="local" impldecl="in implementation">millmain.ui.h</include> </includes> <forwards> <forward>class QuestionIterator;</forward> </forwards> <variables> <variable>questioniterator* _qi;</variable> <variable>bool canclose;</variable> </variables> <signals> <signal>close()</signal> </signals> <slots> <slot>nextquestion()</slot> <slot>checkanswer( int sel )</slot> <slot>endgame()</slot> </slots> <functions> <function access="private" specifier="non virtual">displayquestion()</function> <function access="private">init()</function> <function access="protected">closeevent( QCloseEvent * event )</function> </functions> <pixmapinproject/> <layoutdefaults spacing="6" margin="11"/> </UI>