IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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:

Grafické rozložení QMainWindow - Qt - Okenní/formulářové aplikace v C++

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:

Qt Tlačítko v C++ - Qt - Okenní/formulářové aplikace v C++

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í makra qApp.
  • Metoda connect, která je definována v základní třídě QObject, propojuje signály a sloty. Říká, že tlačítko spolu se signálem clicked() chceme spojit s aplikací a jejím slotem quit().
  • 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 87x (81.75 kB)
Aplikace je včetně zdrojových kódů v jazyce C++

 

Předchozí článek
První okno v Qt a C++
Všechny články v sekci
Qt - Okenní/formulářové aplikace v C++
Přeskočit článek
(nedoporučujeme)
Řetězce v Qt - QString a QChar
Článek pro vás napsal Virlupus
Avatar
Uživatelské hodnocení:
20 hlasů
Autor se věnuje webovým aplikacím, skladově-účetnímu softwaru, 3D grafice, lexiální analýze a parserování. Studuje fyziku na MFF UK. Učil IT na střední škole.
Aktivity