Hlavní navigace

Programování pro X Window System (9)

27. 5. 2004
Doba čtení: 7 minut

Sdílet

Dnešním článkem zakončíme seznámení s toolkitem Qt. Stručně vyjmenujeme základní widgety a kontejnerové třídy. Pak probereme časovače, vstupy a výstupy (práci se soubory a síťovými sokety), podporu pro čtení a zápis konfiguračních souborů a podporu pro komunikaci mezi programy prostřednictvím clipboardu a drag&drop. Skončíme návodem na lokalizaci textů zobrazovaných programem do různých jazyků.

Přehled widgetů

V toolkitu Qt jsou k dispozici obdobné widgety jako v GTK+. Proto zde jen velmi stručně vyjmenuji ty nejdůležitější. Všechny widgety jsou odvozené z bázové třídy QWidget. Pro tlačítka existují třídy QPushButton, QCheckBox a QRadioButton. Přepínatelné tlačítko nemá samostatnou třídu. Místo toho je v QPushButton

definovaná property toggleButton. Statický text QLabel může obsahovat prostý text, rich text (formátovaný text, který vypadá jako zjednodušené HTML), číslo, obrázek nebo animaci. Pro vkládání jednořádkových textových hodnot slouží QLineEdit. Numerické hodnoty lze zadávat pomocí QSlider, QDial a QSpinButton. Jestliže chceme uživateli nabídnout výběr ze seznamu možností, máme k dispozici widgety QListBox a QComboBox. Widget QScrollView funguje jako obecná posuvná oblast spolupracující se scrollbary QScrollBar. Ze třídy QScrollView jsou odvozeny widgety pro vícesloupcový seznam/strom (QListView), editaci textu (QTextEdit) a zobrazení formátovaného hypertextu (QTextBrowser). Qt obsahuje také widgety na zobrazení a editaci dat v SQL databázích: QDataTable,

QDataBrowser a QDataView.

Pro vizuální sloučení logicky souvisejících widgetů do rámečku s nadpisem se – především v dialozích – používají QGroupBox aQButtonGroup. Třída QSplitter je okno s několika panely oddělenými uživatelem posouvatelnými přepážkami. Kolekce stránek pro dialogy obsahující velké množství widgetů se v Qt jmenuje QTabWidget. Hlavní okno aplikace je QMainWindow. Obsahuje předpřipravený pruh menu QMenuBar, dokovací oblasti QDockArea pro toolbary (QToolBar) a stavový řádek QStatusBar. Pro rozbalovací menu existuje třída QPopupMenu.

Dialogová okna se v Qt realizují pomocí třídy QDialog. Dialog může být zobrazen ve dvou režimech. V základním režimu jsou zobrazeny pouze nejčastěji používané položky. Navíc je v dialogu tlačítko napojené na slot QDialog::showEx­tension. Tím se zobrazí další položky dialogu, nastavené předtím voláním QDialog::setEx­tension. Nemodální dialog se zobrazí stejně jako libovolné jiné okno metodou show. Zpracování událostí v aplikaci probíhá normálně dál a v reakci na signál clicked po stisku některého tlačítka v dialogu dojde k přečtení nastavených hodnot a zavření dialogu. Modální dialog se spustí metodou QDialog::exec. Ukončení dialogu a nastavení návratové hodnoty pro exec zajistí slotyQDialog::ac­cept, reject a done. Obvykle se připojují k signálu clicked tlačítek „OK“ a „Cancel“.

Datové struktury

V knihovně Qt je definována i řada tříd, které nejsou widgety. Některé datové typy poskytují podobné funkce jako třídy ze standardní knihovny C++. Jedná se o kontejnerové třídy QMap, QValueList a QValueVector, které odpovídají STL kontejnerům map, list a vector. K těmto kontejnerovým třídám jsou definovány i příslušné iterátory a algoritmy. Toolkit Qt pro své vlastní potřeby používá datové struktury definované v Qt, nicméně jinde v programu je lze kombinovat s kontejnery z STL.

Asi nejdůležitější datový typ v Qt je QString. Toolkit jej používá prakticky všude, kde se pracuje s textem. Objekt třídy QString reprezentuje textový řetězec v kódování Unicode. Používá implicitní sdílení dat, takže kopírování řetězců je relativně nenáročná operace a ke skutečnému zkopírování dat řetězce dojde až při změně originálu nebo kopie. Místo alokované pro řetězec se automaticky zvětšuje podle potřeby. Podporována je konverze z a do řetězců ve stylu C (char *) včetně překódování mezi Unicode a ASCII, resp. jinými 8bitovými kódováními. Dále jsou v QString definovány metody pro porovnání řetězců, změny, hledání podle regulárních výrazů apod. Alternativně Qt poskytuje i abstrakci klasických nulou ukončených řetězců: QCString. Tato třída používá explicitní sdílení dat a nabízí podobnou množinu operací jakoQString, ale tyto operace jsou často méně efektivní.

Časovače, I/O, procesy

Podobně jako v GTK+, i aplikace v Qt někdy potřebují provést nějakou akci periodicky a nezávisle na událostech přicházejících od X serveru. Pro tyto účely existuje třída QTimer. Časovač je třeba nejprve vytvořit.

QTimer *t = new QTimer(parent);

Vždy při vypršení času se vygeneruje signál timeout, který lze napojit na slot implementující požadovanou periodickou akci.

connect(t, SIGNAL(timeout()), parent, SLOT(timeoutExpired())); 

Pak už můžeme nastartovat periodický

t->start(2000);

nebo jednorázový časovač.

t->start(2000, TRUE);

Čas se zadává v milisekundách. Speciální hodnota 0 funguje obdobně jako idle funkce v GTK+ – signál timeout se emituje, pokud je prázdná fronta událostí.

Pro síťové aplikace, jež potřebují zároveň zpracovávat události a čekat na data na soketu, existuje QSocketNotifier. V konstruktoru se nastavuje deskriptor soketu a typ událostí, na které se bude čekat (Read, Write, Exception). Když nastane požadovaná událost, QSocketNotifier emituje signál activated.

Qt obsahuje i třídy pro na platformě nezávislé čtení a zápis souborů (QFile), procházení adresářů (QDir), zjišťování informací o souborech (QFileInfo) a síťové funkce (QSocket, QFtp, QHttp a QDns). Na čtení a zápis textu do souboru nebo soketu slouží třída QTextStream, která poskytuje obvyklé streamové přetížené operátory operator<< aoperator>>. Třída QProcess umí spustit externí program s argumenty, asynchronně psát na jeho standardní vstup, číst jeho standardní a chybový výstup, zjistit jeho PID, detekovat ukončení, přečíst návratový kód a násilně běh programu ukončit.

Konfigurace programů

Qt poskytuje platformně nezávislé API pro ukládání konfigurace aplikací – třídu QSettings. Ve Windows se používá systémový registr. Na unixových systémech se konfigurační hodnoty ukládají do textových souborů v adresáři $HOME/.qt. Seznam adresářů, ve kterých se hledají konfigurační soubory, lze upravovat pomocí metodQSettings::in­sertSearchPath a QSettings::re­moveSearchPat­h.

Každá položka konfigurace je dvojice klíč, hodnota. Klíč je posloupnost dvou nebo více částí oddělených lomítky: /Program/Sekce/klic1/kli­c2. Takto pojmenovaná položka bude uložena jako klic1/klic2 v sekci [Sekce] v souboru $HOME/.qt/program. Pokud má klíč jen dvě části /Program/klic, uloží se do sekce [General] v souboru$HOME/­.qt/program.

Hodnoty jsou typu boolean, integer, double, řetězec nebo seznam řetězců. Pro uložení hodnoty slouží přetížená metoda writeEntry. Metod pro čtení je několik, pro každý podporovaný typ jedna: readBoolEntry, readNumEntry, readDoubleEntry, readEntry a readListEntry. Klíč spolu s přiřazenou hodnotou zruší metodaremoveEntry. Jednotlivé části jmen klíčů definují stromovou strukturu konfiguračních hodnot, podobně jako cesty k souborům definují stromovou hierarchii adresářů ve file systému. Pro určitý uzel konfiguračního stromu lze získat seznam synovských uzlů pomocí entryList (klíče, které obsahují hodnoty) a subkeyList (klíče obsahující podklíče nižší úrovně).

Komunikace mezi programy

Ukážeme si dva způsoby realizace meziprocesové komunikace v Qt. Oba využívají standardní Xové mechanismy. To znamená, že se data přenášejí prostřednictvím X serveru a komunikující procesy nemusejí mít mezi sebou přímé spojení. Navíc se dá komunikovat i s programy nepoužívajícími Qt.

Třída QClipboard se používá pro operace cut&paste. V aplikaci existuje pouze jedna její instance QApplication::clip­board. Podporovány jsou operace vložení dat do clipboardu a přečtení dat z clipboardu. Přenášejí se buď texty (metody text a setText), obrázky (image,pixmap, setImage a setPixmap), nebo data v libovolném formátu identifikovaném MIME typem (data, setData).

Operace drag&drop začíná typicky tak, že uživatel začne táhnout myší nějaký objekt na obrazovce. V handleru pro tuto událost (mouseMoveEvent) program vytvoří instanci některé třídy odvozené z QDragObject a zavolá její metodu drag. Widget, který může být cílem drag&drop, to musí povolit pomocí setAcceptDrop­s(TRUE). Dále je v něm třeba předefinovat minimálně dva handlery událostí. V metodědragEn­terEvent se testuje, zda přenášená data mohou být konvertována do požadovaného formátu, a podle toho se akceptuje událost, např.

event->accept(QTextDrag::canDecode(event));

Metoda dropEvent pak zajistí přečtení dat:

if(QTextDrag::decode(event, text))
    insertTextAt(text, event->pos());

Internacionalizace a lokalizace

Internacionalizace programu (často se zkracuje jako i18n) je přidání základní podpory pro různé jazykové a místní zvyklosti. Lokalizace (l10n) je pak např. přidání databáze přeložených textů, nastavení znakové sady a pravidel lexikografického třídění pro konkrétní jazyk nebo definování pravidel pro zápis čísel a peněžních částek používaných v určité zemi. My se zaměříme na překlad textů, tedy různých hlášení programu, položek menu, popisek prvků dialogu apod.

Základní pravidlo je používat typ QString pro všechny texty, jež se budou zobrazovat uživateli. Každý takový řetězec se obalí voláním funkce tr:

QWidget *w = new QLabel(tr("Full file path:"), dlg);

Při definici akcelerátorů je vhodné používat třídu QKeySequence, která dovoluje zadat akcelerátor pomocí řetězce, a tudíž na něj použít tr. Pokud nějaký text vzniká doplňováním hodnot do základního řetězce, doporučuje dokumentace Qt používat funkci QString::arg, protože ta umožňuje měnit pořadí, v jakém se budou hodnoty do řetězce vkládat. Např. hlášení „5 files deleted in directory /tmp“ vygenerované pomocí

QString s(tr("%1 files deleted in directory %2"));
s = s.arg(5).arg("/tmp");

se dá přeložit „V adresáři /tmp bylo smazáno 5 souborů“ tím, že definujeme jako český ekvivalent řetězce „%1 files deleted in directory %2“ text "V adresáři %2 bylo smazáno %1 souborů.

root_podpora

Když máme texty v programu připraveny k překladu tím, že jsme k nim přidali volání funkce tr, extrahujeme je utilitou lupdate do souboru s příponou .ts. Pak už v programu Qt Linguist překládáme jednotlivé řetězce. Soubor .ts je ve formátu XML, takže kdo nechce používat Linguist, může se souborem pracovat v libovolném textovém editoru. Nakonec příkazem lrelease vytvoříme výsledné soubory řetězců (s příponou.qm) pro jednotlivé jazyky.

V aplikaci, typicky ve funkci main, musíme vytvořit objekt QTranslator a načíst do něj soubor řetězců pomocí QTranslator::load. Používání přeložených textů aktivujeme voláním QApplication::in­stallTranslator. Soubory .qm se obvykle pojmenovávají tak, že součástí jména souboru je i kód jazyka. Aktuální jazyk nastavený v environmentové proměnné LANG (např. cs_CZ pro češtinu) zjistíme metodou QTextCodec::locale.

Byl pro vás článek přínosný?