Search
Cílem programu je vykreslení šachovnice o velikosti 8×8 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.
Program je rozšířením příkladu z 10. cvičení (gitlab).
Kompletní kód je ke stažení v gitlab repozitáři.
Ř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 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<QPushButton *> buttons = this->findChildren<QPushButton *>(); // 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).
maxsize
maxsize = QGuiApplication::primaryScreen()->geometry().height() - 100;
K obarvení dlaždic je použit následující stylesheet
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
V této fázi by bylo možné více využít kombinace metod setProperty a 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 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 active. 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.
active
Tile::Tile (QString c, QWidget *parent) : QPushButton(parent), color(c), active(false) { updateStyle(); QObject::connect (this, QPushButton::clicked, this, Tile::changeState); } void Tile::changeState () { active = !active; updateStyle(); } void Tile::updateStyle () { setProperty("state", QVariant(QString("%1-%2").arg(color).arg(active))); // 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
Board
Tile
b = new Tile((i+j)%2 ? "black" : "white");
Poslední úpravou je vytvoření stylů pro tmavší dlaždice.
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; }