Hlavní navigace

Make up pro vaše aplikace: Qt vazba

14. 3. 2003
Doba čtení: 6 minut

Sdílet

Další pokračování seriálu věnujícího se jednotlivým modulům jazyka Python umožnujícím práci s uživatelským rozhraním. Po prvním dílu popisujícím GTK+ následuje ukázka Qt vazby PyQt.

Instalace

Začneme instalací modulu. Přestože některé distribuce obsahují moduly PyQt již v binární podobě, popíšeme si zde postup jejich kompilace ze zdrojových souborů. Důvody, které mě k tomu vedly, byly zcela prozaické: můj Woody nemá přeložené PyQt pro Python 2.2.

Nejprve si stáhneme zdrojové tarbally modulů PyQt 3.5 a SIP 3.5. Zde pozor, je opravdu třeba mít nainstalovaný SIP ve verzi, která je předepsána PyQt. Na tento požadavek jsem se „nachytal“, myslel jsem si, že bude stačit ten z Woodyho. Nestačil. Jako další přídavek si můžete stáhnout sadu modulů PyKDE a případně i integrované prostředí eric3.

Začneme instalací knihovny SIP. Tato knihovna pracuje jako generátor kódu, který dokáže zpracovat hlavičkové soubory Qt a vygenerovat z nich pythonovský modul v C++. README z distribučního tarballu se zmiňuje o nutnosti odstranit starší verze SIPu ze systému, můj SIP 2.5 z Woodyho nijak nepřekážel, proto jsem ho v systému ponechal. Překlad balíčku je dělán pomocí vlastního skriptu build.py, ne pomocí standardizovaných a stabilních distutils.

Před překladem budete ještě potřebovat mít nainstalovaný program ‚tmake‘ nebo ‚qmake‘, který je standardně dodávaný s Qt nebo jej naleznete ve své distribuci (ač je uvedeno, že SIP vyžaduje tmake 1.8, pracuje i s verzí 1.7 z Woodyho).

Nyní začneme se samotným překladem. Nejprve musíme vygenerovat správné soubory Makefile. To za nás učiní příkaz ‚python build.py‘. V případě, že budete chtít SIP zkompilovat pro jinou než implicitní verzi Pythonu, nahraďte příkaz python odpovídajícím jménem binárky (já použil python2.2). Skript umožňuje nastavení mnoha voleb týkajících se umístění jednotlivých Qt knihoven atd. Dávejte pozor na správné nastavení proměnné prostředí TMAKEPATH, jíž se řídí program tmake, bez něj nebude správně pracovat a Makefile se nevytvoří. Ve Woodym jsem použil ‚export TMAKEPATH=/et­c/tmake‘.

Po úspěšném dokončení fáze generování získáte v adresáři, kde máte umístěny zdrojové soubory SIPu, soubor Makefile. Můžete přistoupit k samotnému překladu pomocí příkazu ‚make‘. Další nectnost SIPu: vyžaduje, aby se již samotný překlad prováděl pod rootem. Nakonec spustíte ‚make install‘ a SIP by měl být nainstalován.

U mě se však při překladu objevil problém. Překladač se neustále snažil přistupovat k hlavičkovým souborům v adresáři /usr/share/qt/in­clude/qt/, což je chybně, poslední adresář qt/ je tam jaksi „navíc“, nepomohly šachy s přepínači, překladač stále nemohl načíst hlavičkové soubory. Pomohlo až dočasné vytvoření symbolického odkazu /usr/share/qt/in­clude/qt, který již ukazoval na správný adresář.

Instalace PyQt je již obdobná instalaci SIPu. Opět nejdříve ‚python build.py‘ a následně pod rootem překlad a instalace pomocí ‚make; make install‘. Symbolický odkaz jsem musel ponechat i při instalaci PyQt. Skript build.py si osahá váš systém a podle toho nainstaluje vazby pro správnou verzi knihovny Qt (podporováno je množství verzí od 1.43 až po 3.1.1 nebo Qtopii). Podle rozsahu modulů Qt se vyberou odpovídající vazby (nabízeny jsou moduly qt, qtcanvas, qtgl, qtnetwork, qtpe, qtsql, qttable, qtxml a qtext).

PyQt

Nejprve si probereme základní vlastnosti PyQt (mnoho z předností PyQt umožňuje generátor SIP):

  • umožňuje napojit signály qt na pythonovské funkce
  • z pythonu lze snadno vytvářet signály a napojit je na qt sloty
  • lze předefinovat virtuální metody c++ objektů, což ve skutečnosti znamená opravdovou výhodu při implementaci nových widgetů
  • zpřístupňuje statické metody c++ objektů v pythonu
  • podporuje unicode, pythonovský garbage collector
  • podpora qt technologií, jako je qt designer a qt linguist

Vzhledem k délce ukázkového souboru v C++ pouze přiložím odkaz na zdrojový tarball (příklad byl převzat z ukázkových příkladů dodávaných s Qt). Výsledek našeho snažení v Pythonu pak může vypadat třeba takto: hello.py

Jak vidíme, programovací styl používaný společně jak v C++, tak v Pythonu se téměř neliší. Používají se (téměř) shodné názvy funkcí a metod, pracuje se se signály a sloty, můžeme předefinovávat virtuální metody widgetů a tak dále.

Přesto existuje několik zásadních rozdílů. Prvním z nich, na který určitě narazíte, když budete přepisovat zdrojový kód z C++ do Pythonu, je nutnost kvalifikovat atributy všech objektů. V C++, pokud se pohybujeme v metodě určité třídy, máme automaticky přímý přístup ke všem jejím členům. V Pythonu však musíte všechny takové atributy kvalifikovat pomocí self. Proto člověk musí neustále přemýšlet, zda jde o globální funkci, nebo metodu téhož objektu.

Se signály a sloty se pracuje obdobným způsobem jako v C++, signály můžeme připojit na odpovídající sloty a nebo, což je dobrou vlastností PyQt, i na libovolnou metodu či funkci. Vezmeme-li si jako ukázku helloworld, jenž jsme si uvedli výše, pak si všimněte že parametry funkcí SIGNAL, PYSIGNAL a SLOT jsou předávány jako řetězce, narozdíl od C++, kde se „signálové“ funkce předávají jako argumenty makrům, tudíž nemusí být označeny jako funkce.

Pokud budeme připojovat signál na slot, můžeme použít dva ekvivalentní zápisy:

QObject.connect(h, PYSIGNAL('clicked()'), a, SLOT('quit()'))
QObject.connect(h, PYSIGNAL('clicked()'), a.quit)

Chceme-li nadefinovat nový signál, budeme postupovat také jiným způsobem. Nutno dodat, že o hodně jednodušším než v C++. Tam nejprve v hlavičkovém souboru musíte uvést deklaraci signálu včetně jeho typů a následně pomocí MOC (Meta Object Compiler) vygenerovat soubor, jenž tento signál zpřístupní. V Pythonu takový signál vznikne zcela automaticky při pouhém volání funkce PYSIGNAL(). Tím vytvoříme „pythonovský“ signál, na který již můžeme bez problémů napojit i C++ slot.

Dalším výrazným plusem PyQt (ve srovnání s PyGTK) je výborná dokumentace, kde člověk najde popsány všechny rozdíly mezi programováním s Qt v jazyce C++ a Pythonu. Zjistíte zde, jak se PyQt vyrovnává třeba s existencí ukazatelů, či které třídy jsou úplně implementovány, kterých metod implementace chybí a zda se s ní vůbec počítá.

Najdete zde i rozdíly v pojmenování některých metod, jejichž základní výčet uvedeme v tomto odstavci. Nejdůležitější metoda celé aplikace se nejmenuje exec(), ale exec_loop(), obdobně tak metody pro zasunutí widgetu pod ostatní nebo pro jeho vyzdvižení se jmenují lowerW() a raiseW(). To jsou ty nejzásadnější rozdíly, další najdete většinou u metod, které provádějí nějaké nízkoúrovňové manipulace s daty (používají ukazatele atd.).

Pokud pomineme tyto rozdíly, lze s PyQt pracovat naprosto shodným způsobem jako v C++, skvělou pomůckou pro začátečníky může být tutorial dodávaný s Qt a množství ukázkových příkladů jak u Qt, tak u PyQt. Integrace s Pythonem je udělána velmi nenásilně a intuitivně, programátor, který již má s Qt nějaké zkušenosti, se bude cítit jako ryba ve vodě.

Zápory

Balíčku PyQt nelze nic moc vytýkat, snad jen jeho rozsáhlost. Mnoho tříd jsou defacto duplikáty jejich Pythonovských protějšků. Například QString či třídy z balíčku qtnetwork. Obdobně se Qt snaží programátorovi nabízet svoji vlastní implementaci XML rozhraní DOM. Osobně bych raději použil nativní moduly Pythonu, ale proti gustu žádný dišputát.

skoleni

Na závěr poslední upozornění – veškerá funkcionalita, tak, jak jsme ukázali výše, se týká widgetů vytvořených z Pythonu, pokud získáte odkaz na objekt, jenž byl vytvořen z C++ kódu a pouze „přemapován“ do Pythonu, přijdete o možnost předefinovávat virtuální metody a o další výhody. Stejně tak nelze ve spojení s Qt objekty používat vícenásobnou dědičnost.

Příště

Třetí díl naší GUI exkurze bude věnován téměř standardnímu, mnohdy zatracovanému modulu Tkinter.