Lekce 3 - Dokončení prvního okna v Qt a C++ - Tlačítko
V minulé lekci, První okno v Qt a C++, jsme si vytvořili svou první formulářovou aplikaci v Qt frameworku pro C++.
V dnešním Qt tutoriálu do našeho prázdného okna vložíme první komponentu, kterou bude tlačítko, které po kliknutí okno zavře.
Rozložení okna
Pro tento úkol si však musíme více povědět o QMainWindow
,
hlavně o jeho vnitřním grafickém rozložení. To demonstruje diagram
níže:

Všimněte si, že okno se dělí na pět základních oblastí:
- První a poslední je určena pro hlavní nabídku a stavový řádek.
- Mezi mini je oblast pro panely nástrojů, kde jeden toolbar můžete posouvat (myší nebo programově) dokola, případně čtyři panely umístit po všech stranách nebo různě experimentovat s jejich rozmístěním v této oblasti.
- Další část dock widgets je určena různé doplňující widgety, které mají být trvale součástí okna. Tuto možnost jsem zatím nijak moc nevyužil, snad jen pokusně. To ovšem neznamená, že se k ní podrobněji nedostaneme.
- Poslední součást Hlavního Okna je centrální widget. Zde se bude odehrávat vše podstatné, neboť právě tady je místo pro GUI, tedy grafické uživatelské rozhraní naší aplikace.
Widget a manažery rozložení
Abychom mohli do okna něco přidat, je třeba si vytvořit tedy
centrální pomocný widget. Použijeme naprosto základní QWidget
, od nějž
jsou odvozeny všechny ostatní grafické (a i další) části aplikace.
Manažery rozložení
Další důležitou informací je, že Qt využívá systém
manažerů rozložení - layouty, které vydají na samostatnou lekci.
Kdychom totiž komponenty ve formuláři umístili na absolutní souřadnice,
okno by nereagovalo na zvětšení/změnšení nebo dokonce na změnu
rozlišení nebo DPI. Layouty umožňují komponenty na formuláři automaticky
uspořádávat a každý to dělá různým způsobem (např. vedle sebe nebo do
tabulky). My dnes použijeme tzv. QHBoxLayout
, který komponenty
skládá vedle sebe a případně je zalomí na další řádek, pokud na
formuláři již na další není místo.
Přidání tlačítka do projektu
Otevřeme tedy minulý projekt s oknem, abychom nemuseli začínat odznovu, a trochu si jej poupravíme.
mainwindow.h
Do hlavičkového souboru přidáme pomocný widget, zmíněný layout a potom i samotné tlačítko:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QPushButton> #include <QHBoxLayout> #include <QWidget> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); QWidget * central; QHBoxLayout *layout; QPushButton *cudlik; };
Třídě jsme přidali následující atributy:
QPushButton
- Tlačítko.QHBoxLayout
- Jednoduchý layout, který jednotlivé prvky skládá vedle sebe do řádky a když je řádka plná, prostě přejde na další. Layouty jsou způsob, jakým komponenty na formuláře umisťujeme. V našem případě pouze jednoho tlačítka bychom mohli použít klidně i některý jiný.QWidget
- Komponenta nám poslouží jako obsah centrální části hlavního okna. Při rozsáhlejších programech bychom si pro něj vytvořili samostatnou třídu. Zatím to však není nutné.
mainwindow.cpp
Přejdeme do souboru mainwindow.cpp
a inicializujeme zde
ukazatele na všechny tři instance a ještě provedeme několik úprav, které
si hned popíšeme. Výsledný kód souboru vypadá takto:
#include "mainwindow.h" #include <QIcon> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { resize(640,480); setWindowTitle("Můj první program"); /* setToolTip("Toto okno nic nedělá"); */ setWindowIcon(QIcon(":/img/mainIcon")); central = new QWidget(this); layout = new QHBoxLayout(); central->setLayout(layout); cudlik = new QPushButton("Zavři mě"); cudlik->setToolTip("Zavřu celé okno!!!"); layout->addWidget(cudlik); setCentralWidget(central); } MainWindow::~MainWindow() { if (cudlik != NULL) { delete cudlik; } if (layout != NULL) { delete layout; } if (central != NULL) { delete central; } }
V kódu provádíme následující:
- Vytvoříme si instanci widgetu a layoutu:
central = new QWidget(this);
,layout = new QHBoxLayout();
- Našemu widgetu nastavíme daný layout:
central->setLayout(layout);
- Dále potřebujeme ono důležité tlačítko a zároveň mu přidělíme
text (lze třeba i ikonu):
cudlik = new QPushButton("Zavři mě");
Pokud chcete, můžete tlačítko doplnit i o rychlou nápovědu:cudlik->setToolTip("Zavřu celé okno!!!");
- Tlačítko umístíme do layoutu. Protože je jen jedno a nemá nastavenou
velikost, tak vyplní celou šířku okna:
layout->addWidget(cudlik);
- Poslední krok je náš widget umístit do centrální oblasti okna:
setCentralWidget(central);
Pozornost věnujte destruktoru okna - všechny objekty
vytvořené pomocí operátoru new
jsou po testu na jejich
existenci poctivě smazány operátorem delete
. Berme to jako
nutný zvyk, aby nedocházelo k zaplnění paměti, která sice nikomu již
nepatří, ale již se nedá alokovat. Prostě jakmile někde použijete
new
, raději okamžitě v destruktoru zapište příkaz pro
zrušení objektu. Osobně vím, že pokud to neudělám hned, může se stát,
že zapomenu.
Tak to je celé. Můžeme vyzkoušet:

Tlačítko ještě samozřejmě po kliknutí nic neudělá.
Reakce kliknutí na tlačítko
Naším přáním bylo, aby tlačítko po stisknutí zavřelo okno. Zde se
dostáváme k mimořádně silnému nástroji, který se nazývá
signály a sloty. O co kráčí? Každá třída odvozená od
QObject
může
posílat a přijímat zprávy (informace o událostech) z dalších tříd a
reagovat na ně. Dokonce je možný oboustranný přenos.
Signály
Pro naše tlačítko existuje již předdefinovaný signál v rodičovské
třídě QAbstractButton
.
Nás bude zajímat signál clicked(bool checked = false)
, který je
vyvolán pokud na komponentu bylo kliknuto. V jiných programovacích jazycích
se tomuto mechanismu často říká události.
Trochu problém je v tom, že signál se pouze zařadí do fronty událostí a pak už je mu jedno co se s ním stane. To je naše starost, aby byl správně zpracován.
Sloty
My potřebujeme, aby signál přijala aplikace. K tomu nám pomůže třída
QApplication
,
která je odvozena od QCoreApplication
a obsahuje slot (možný příjemce signálu) quit()
, který
aplikaci ukončí.
mainwindow.cpp
Nyní je nutné programu oznámit, že má tento signál i slot propojit. Myslím, že uvést jen dva dané řádky kódu bude stačit:
// mainwindow.cpp ... #include <QApplication> ... connect(cudlik, SIGNAL(clicked()), qApp, SLOT(quit()), Qt::QueuedConnection);
Co jsme to vlastně provedli?
- Vložením knihovny
QApplication
jsme získali možnost přístupu k unikátnímu ukazateli na celou aplikaci pomocí makraqApp
. - Metoda
connect
, která je definována v základní tříděQObject
, propojuje signály a sloty. Říká, že tlačítko spolu se signálemclicked()
chceme spojit s aplikací a jejím slotemquit()
. Qt::QueuedConnection
je taková dobrá praxe, jež umožní řadit události do fronty. Jinak by se mohlo stát, že aplikace ještě něco potřebuje dokončit a při ukončení by to nestihla. Pak třeba přijdete o nějaká data, uložení konfigurace atp.
Tak a máme to celé, stačí přeložit spustit a vyzkoušet, že aplikace opravdu funguje.
Příště, v lekci Řetězce v Qt - QString a QChar, si představíme třídu QString
,
která se nám bude v dalších lekcích hodit.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 94x (81.75 kB)
Aplikace je včetně zdrojových kódů v jazyce C++