====== 7. QT - úvod ====== Vzorové příklady najdete v repozitáři ''tutorials'' v adresáři tut07 git pull cd tut07 Alternativně lze najít kódy také v archivu: {{ :courses:b2b99ppc:tutorials:ppc-tut07.zip |}} --- //**Aktualizace** 2020/04/14 22:44 - opraveny chyby, dodány chybějící soubory// ===== Aplikace s jednou komponentou ===== QApplication app(argc, argv); QPushButton b1("Button 1"); b1.show(); return app.exec(); ===== Vložení více komponent ===== Mohlo by se zdát, že další komponentu lze přidat vytvořením nového objektu. QPushButton b1("Button 1"); QPushButton b2("Button 2"); b1.show(); b2.show(); Chování výsledného programu je ale jiné: vytvořila se dvě okna (každé s voláním ''.show()'') a okna se vzájemně překrývají. Řešením je umístit komponenty na jinou vhodnou komponentu, která pak bude zobrazena. Pro tento účel se hodí instance třídy ''QWidget'', která sama o sobě nemá žádnou grafickou podobu, ale může být rodičovským kontejnerem pro jiné objekty. Příslušnost komponenty k rodičovském kontejneru se vytváří vložením ukazatele na rodičovský objekt do konstruktoru komponenty. QWidget w; QPushButton b1("Button 1", &w); QPushButton b2("Button 2", &w); w.show(); Po spuštění přeloženého programu to na první pohled vypadá, že nedošlo k žádné změně. Okno je sice pouze jedno, komponenty (tlačítka) jsou ale přes sebe. Komponenty (widgety) lze absolutně pozicovat metodou ''move()'' a měnit jejich velikost metodou ''resize()''. QWidget w; w.resize(100,100); QPushButton b1("Button 1", &w); QPushButton b2("Button 2", &w); b2.move(0, 50); w.show(); === Úkoly === - Doplňte do aplikace další potomky abstraktní třídy [[https://doc.qt.io/qt-5/qabstractbutton.html|QAbstractButton]] - [[https://doc.qt.io/qt-5/qcheckbox.html|QCheckBox]] a [[https://doc.qt.io/qt-5/qradiobutton.html|QRadioButton]] - Nakreslete šachovnici 8x8 tlačítek ===== Stylování komponent ===== Qt umožňuje pro stylování komponent využívat styly podobné [[https://www.w3schools.com/css/|kaskádovým stylům]] známým z HTML. Komponenty, které budeme používat, podporují [[https://doc.qt.io/qt-5/stylesheet-customizing.html#box-model|box model]]. QPushButton b1("Button 1", &w); b1.setStyleSheet("background-color: red;" "border-style: outset;" "border-width: 2px;" "border-radius: 10px;" "border-color: beige;" "font: bold 14px;" "min-width: 10em;" "padding: 6px;"); === Úkol === - Upravte šachovnici z tlačítek tak, aby vypadala jako opravdová šachovnice ===== Layouty ===== Absolutní pozicování widgetů je pochopitelně velmi nešikovné. Umožňuje sice mít absolutní kontrolu nad polohou komponent, ale i malé v podobě aplikace změny mohou znamenat velké změny v programu. Qt pro pozicování komponent zavádí tzv. [[https://doc.qt.io/qt-5/layout.html|layouty]], kontejnery, ve kterých je pozice vloženého widgetu řízena pravidlem. Následující příklad vykreslí 10 tlačítek uspořádaných horizontálně v komponentě [[https://doc.qt.io/qt-5/qhboxlayout.html|QHBoxLayout]]. Opět je použita instance třídy [[https://doc.qt.io/qt-5/qwidget.html|QWidget]] jako rodičovský kontejner, jednotlivé komponenty jsou ale vkládány do layoutu a ten je pak kontejneru funkcí [[https://doc.qt.io/qt-5/qwidget.html#setLayout|setLayout()]] přiřazen. Na rozdíl od absolutního pozicování je velikost rodičovského widgetu určena automaticky. QWidget w; QHBoxLayout l; for (int i = 0; i < 10; i++) { QString name = QString("%1 %2").arg("button").arg(i); l.addWidget (new QPushButton (name)); } w.setLayout (&l); w.show(); ===== Správa zdrojů ===== V odstavci o [[courses:b2b99ppc:tutorials:07#stylovani_komponent|stylování komponent]] jsme si ukázali, jak v kódu měnit styl GUI prvků. Pro skutečné programy je vhodné oddělit grafickou podobu aplikace a implementaci algoritmu. To je možné v případě stylování komponent v QT možné provést v ''styleSheet'' souboru, který je před spuštěním aplikace načten. Díky tomuto přístupu je možné hromadně stylovat celé třídy komponent (tj. instance tříd), specifické prvky podle názvu nebo podle atributu. Aby ''qmake'' neměl problémy s hledánim souborů, které jsou v aplikaci použity (styly, obrázky, ...), používá QT systém [[https://doc.qt.io/qt-5/resources.html|zdrojů]]. Cesty k použitým zdrojům jsou zapsány v ''.qrc'' souboru, který používá syntaxi založenou na ''XML''. Příklad takové souboru: images/fig.png images/img.png styles/app.qss Soubor specifikuje, že zdroje aplikace jsou ve dvou adresářích, ''images'' a ''styles''. Pokud chceme v aplikaci používat zdroje, je třeba je aktivovat voláním makra Q_INIT_RESOURCE(style); // cesta ke qrc souboru, bez přípony K jednotlivým zdrojům lze pak přistupovat pomocí následující syntaxe // načení stylesheetu ze souboru QFile styleSheet(":/styles/app.qss"); // aplikace stylesheetu app.setStyleSheet(styleSheet.readAll()); Základním způsobem, jak stylovat, je vytvoření stylu pro celou třídu QAbstractButton { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(173,216,230,60%), stop:1 rgba(0,0,139,60%)); border-color: black; border-style: solid; border-width: 3px; border-radius: 6px; height: 50px; width: 50px; } Tento styl zajistí, že všechny instance všech tříd, derivovaných ze třídy [[https://doc.qt.io/qt-5/qabstractbutton.html|QAbstractButton]] budou vypadat stejně bez toho, aby bylo třeba v ''cpp'' kódu něco dalšího psát. {{ :courses:b2b99ppc:tutorials:tut07_04_stylesheet.png?150 |}} Pomocí [[https://doc.qt.io/qt-5/stylesheet-reference.html#list-of-pseudo-states|pseudo stavů]] je možné zachytávat aktuální stav objektu a přizpůsobit mu grafickou podobou, zde např. změnit barvu při najetí myší na objekt: QAbstractButton:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230,216,173,60%), stop:1 rgba(139,0,0,60%)); } {{ :courses:b2b99ppc:tutorials:tut07_04_stylesheet_2.png?150 |}} Pokud je třeba nastavit vlastnosti konkrétního prvku, lze využít selektoru jména QAbstractButton#plus { background-color: none; background-image: url(:/files/add.png); } QAbstractButton#minus { background-color: none; background-image: url(:/files/remove.png); } V ''cpp'' souboru pak přiřadíme jméno objektu QPushButton b1; b1.setObjectName("minus"); {{ :courses:b2b99ppc:tutorials:tut07_04_stylesheet_3.png?150 |}} Další možností je vytvoření atributu, který bude použit v metodě [[https://doc.qt.io/qt-5/qobject.html#setProperty|setProperty]] objektu. Přiřazení vlastnosti pak probíhá na základě hodnoty atributu. QAbstractButton[odd=true] { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(173,216,230,60%), stop:1 rgba(0,0,139,60%)); } QAbstractButton[odd=false] { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230,216,173,60%), stop:1 rgba(130,0,0,60%)); } for (int i = 0; i < 12; i++) { QPushButton *b = new QPushButton; // ... b->setProperty("odd", (i%2) ? true : false); } {{ :courses:b2b99ppc:tutorials:tut07_05_clock.png?300 |}}