10. Qt - kreslení

Cílem cvičení je ukázat, jak je možné v QT kreslit grafická primitiva. Využijeme k tomu zejména třídu QPainter, která umožňuje kreslení do jednotlivých GUI komponent.

Při práci s třídou QPainter využijeme skutečnosti, že při vykreslování komponent a takových změnách v aplikaci za běhu, které mohou ovlivňovat grafickou podobu (např. změna velikosti okna), je automaticky volána metoda paintEvent, kterou lze v derivované třídě přepsat 1). Kromě implicitního volání lze metodu paintEvent explicitně volat pomocí metod repaint a update.

class Canvas : public QWidget
{
    Q_OBJECT
 
public:
    Canvas (QWidget *parent=0);
    void paintEvent (QPaintEvent *event);
};

Canvas::Canvas (QWidget *parent) : QWidget (parent)
{
    resize(200, 200);
}

Aby mohl painter kreslit, musí vědět kam: k tomu slouží parametr konstruktor, tzv. painting device - může to být instance třídy QWidget, QPixmap nebo QImage. Zde pracujeme s třídou derivovanou z QWidget, předáme tedy ukazatel this. POkud by bylo potřeba mít z libovolného důvodu painter sdílený v rámci třídy, je třeba ho před začátkem vykreslování aktivovat metodou QPainter::begin() a ukončit metodou QPainter::end().

void Canvas::paintEvent(QPaintEvent *event)
{
    QPainter p(this);
    p.fillRect(20, 20, 160, 160, QColor(220,0,0));
}

Třída QPainter obsahuje řadu funkcí, pomocí který se do kreslit do painting device. Některé z nich vyžadují, aby bylo zvoleno pero, tj. vytvořena instance třídy QPen.

QPen pen(Qt::black, 2);
p.setPen(pen);
p.drawRect(40, 40, 30, 30);

Barvy lze používat buď předdefinované (statické atributy třídy QColor), nebo lze definovat libovolnou barvu pomocí souřadnic v některém z barevných modelů (např. defaultním RGB modelu). Součástí specifikace barvy může být i průhlednost, definovaná jako parametr instance QColor nebo pomocí metody QColor::setOpacity().

for (int i=0; i < 10; i++) {
    p.setOpacity((i+1)*0.1);
    p.fillRect(i*40, 0, 40, 40, Qt::darkGray);
}

Barevný prostor RGB, který je mainstreamem ve zpracování barevné informace, má celou řadu nevýhod. Díky tomu, že intenzita jednotlivých komponent modelu barvy ovlivňuje jas i barevnost, není možné např. jednoduše provádět porovnávání barev ve smyslu světlejší, tmavší a podobně. Výhodnější proto někdy mohou být barevné modely, ve kterých je jasová složka oddělena od barevné informace, např. barevný prostor HSV - Hue je barva (0-359), Saturation je sytost (0-255) a Value je jas (0-255).

for (int i=0; i < 10; i++) {
    QColor c;
    p.fillRect(i*40, 0, 40, 40, c.fromHsv(200, i*25, 255));
}

Pomocí třídy QPainter je možné i vytvářet texty. V následujícím příkladu je ukázáno, jak napsat text pomocí metody QPainter::drawText() a nastavit font instancí třídy QFont. Příklad je zajímavý tím, že ukazuje možnost rotace a posunu kreslící plochy (painteru) pomocí metod QPainter::rotate() a QPainter::translate(). Třešničkou je použití lineárního gradientu QLinearGradient při vykreslení písma.

QPainter q(this);
QLinearGradient gradient (0, 20, 200, 20);
gradient.setColorAt(1.0, Qt::red);
gradient.setColorAt(0.0, Qt::yellow);
q.setPen(QPen(gradient, 4));
q.setFont(QFont("Arial", 24, QFont::Bold));
q.rotate(90);
q.translate(200, -200);
for (int i = 0; i < 4; i++) {
    q.drawText(10, 10, tr("Ahoj PPC"));
    q.rotate(90);
}

Změna kreslící plochy (rotace, translace, transformace) je jednou dalších možností, jak kreslit pomocí https://doc.qt.io/qt-5/qpainter.html. Pro vytváření transformovaných objektů je vhodné vytvářet další instance této třídy, nebo uložit stav pomocí QPainter::save() do zásobníku, odkud může být vyzvednut po provedení transformace metodou QPainter::restore().

1)
Mimochodem to také znamená, že nelze kreslit přímo v konstruktoru, protože vykreslování komponenty začne až po vytvoření objektu.
courses/b2b99ppc/tutorials/10.txt · Last modified: 2024/02/26 13:53 by nentvond