====== 1. Šachovnice ====== Cílem programu je vykreslení šachovnice o velikosti 8x8 dlaždic. Dlaždice budou různých barev (tak jako na standardní šachovnici), po jednom kliknutí dlaždice ztmavne, po dalším změní barvu zpět na původní. Pro stylování dlaždic budeme používat styly definované ve externím stylesheetu. Kompletní kód je ke stažení v git repozitáři nebo ve formě balíčku {{ :courses:b2b99ppc:solutions:01-chessboard.zip |}}. ===== Kontejner - Board ===== Řešení, které je zde představeno, využívá absolutního pozicování objektů v kontejneru. Tlačítka jsou vykreslena v konstruktoru. // board.h class Board : public QWidget { Q_OBJECT QPushButton *b; public: Board (QWidget *parent = 0); }; // board.cpp Board::Board(QWidget *parent) : QWidget(parent) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { b = new QPushButton(this); b->resize (50, 50); b->move (50*i, 50*j); } } } Řešení má nevýhodu - při změně velikosti nejsou tlačítka škálována. K přeškálování lze využít faktu, že při změně velikosti widgetu se automaticky volá metoda [[https://doc.qt.io/qt-5/qwidget.html#resizeEvent|resizeEvent]]. Tuto metodu lze v rámci vlastní třídy přepsat, např. takto: void Board::resizeEvent (QResizeEvent *event) { // zjisteni nove velikosti okna, lze vyuzit i event->size() int width = this->geometry().width(); int height = this->geometry().height(); // zjisteni vetsiho rozmeru int size = (width > height) ? width : height; // maximalni velikost je dana vyskou displeje - viz konstruktor if (size > maxsize) size = maxsize; // zmena velikosti okna se zachovanim pomeru stran this->resize(size, size); // nova velikost dlazdice int tsize = size/8; // vyhledani vsech potomku kontejneru typu QPushButton QList buttons = this->findChildren(); // zmena velikosti a pozice vsech dlazdic for (int k = 0; k < buttons.size(); k++) { int i = buttons.at(k)->x() / buttons.at(k)->width(); int j = buttons.at(k)->y() / buttons.at(k)->height(); buttons.at(k)->move (i*tsize, j*tsize); buttons.at(k)->resize(size/8, size/8); } } Maximalni velikost okna ''maxsize'' je privátním atributem třidy a je inicializována výškou displeje, sníženou o nějakou rozumnou hodnotu (taskbar ve Windows). #include #include ... maxsize = QApplication::desktop()->height() - 100; K obarvení dlaždic je použit následující stylesheet {{:courses:b2b99ppc:solutions:solutions_chess_01.png?300 |}} QAbstractButton { border-color: black; border-style: solid; border-width: 1px; } QAbstractButton[color=black] { background-color: #654321; } QAbstractButton[color=white] { background-color: #FFCC00; } Jednolivým tlačítkům, reprezentujícím dlaždice šachovnice, je pak přiřazen atribut, který je použit k vybrání správného stylu b = new QPushButton(this); b->setProperty("color", "white"); // pro nastaveni hodnoty atributu lze vyuzit vhodne pravidlo, napr. (i+j)%2 ===== Dlaždice - Tile ===== V této fázi by bylo možné více využít kombinace metod [[https://doc.qt.io/qt-5/qobject.html#setProperty|setProperty]] a [[https://doc.qt.io/qt-5/qmetaobject.html#property|property]] k aktualizaci a zjišťování stavu dlaždice (objektu). Z hlediska organizace kódu je ale lepší a přehlednější vytvořit vlastní třídu jako potomka třídy [[https://doc.qt.io/qt-5/qpushbutton.html|QPushButton]], která bude mít vnitřní stav jako atribut třídy a na základě tohoto atributu poté aktualizovat grafickou podobu instance. class Tile : public QPushButton { Q_OBJECT QString color; bool clicked; void updateStyle (); public: Tile (QString, QWidget *parent = 0); public slots: void changeState (); }; Parametrem konstruktoru je barva dlaždice. Třída má slot, který mění binární hodnotu atributu ''clicked''. Při změně stavu objektu je pak změněna i grafická podoba. Hodnoty atributů ve stylesheetu jsou pak dány kombinací barvy vnitřního stavu. Tile::Tile (QString c, QWidget *parent) : QPushButton(parent), color(c), clicked(false) { updateStyle(); } void Tile::changeState () { clicked = !clicked; updateStyle(); } void Tile::updateStyle () { setProperty("state", QVariant(QString("%1-%2").arg(color).arg(clicked))); // trik pro aktualizaci vlastnosti style()->unpolish(this); style()->polish(this); } V konstruktoru třídy ''Board'' je pak třeba vytvářet instance derivované třídy ''Tile'' b = new Tile((i+j)%2 ? "black" : "white"); connect (b, SIGNAL(clicked()), b, SLOT(changeState())); Poslední úpravou je vytvoření stylů pro tmavší dlaždice. {{:courses:b2b99ppc:solutions:solutions_chess_02.png?300 |}} QAbstractButton[state="black-0"] { background-color: #654321; } QAbstractButton[state="black-1"] { background-color: #FF5500; } QAbstractButton[state="white-0"] { background-color: #FFCC00; } QAbstractButton[state="white-1"] { background-color: #FF0000; }