Warning
This page is located in archive. Go to the latest version of this course pages. Go the latest version of this page.

1. Šachovnice

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.

Kompletní kód je ke stažení v git repozitáři nebo ve formě balíčku 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 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).

#include <QApplication>
#include <QDesktopWidget>
...
maxsize = QApplication::desktop()->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

Dlaždice - Tile

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 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.

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;
}

courses/b2b99ppc/solutions/01.txt · Last modified: 2020/04/22 19:30 by viteks