Guietta – sposób na proste GUI w Pythonie

W swoim programistycznym życiu napisałem przy użyciu frameworka Qt tysiące linii kodu. Przygodę z nim zacząłem od jego naturalnego środowiska, jakim jest język C++. Później zaś, gdy przerzuciłem się na Pythona, miałem okazję stworzyć całkiem sporo aplikacji, wykorzystując do tego PyQt. Używając zwrotu „napisałem w Qt” mam na myśli nie tylko posługiwanie się najróżniejszymi klasami, dostarczającymi funkcjonalności przydatne do programowania sieciowego czy obsługi multimediów, ale przede wszystkim tworzenie interfejsu graficznego. Zawsze bowiem wolałem samodzielnie zaprogramować GUI, niż korzystać z Qt Designera i na zasadzie drag&drop kreować wygląd swojej aplikacji.

Podobieństwo do Giulietty to nie tylko kwestia nazwy, bowiem Guietta również stara się być szybka i elegancka (źródło ilustracji: Alfa Romeo)

Generowany przez Designera kod zdecydowanie odbiegał od moich oczekiwań co do jego jakości (mam na myśli chociażby nazewnictwo zmiennych), a poprawianie go było w moim wykonaniu po prostu wolniejsze niż manualne kodowanie interfejsu od zera. Będąc przyzwyczajonym do stylu tworzenia GUI w Qt zupełnie nie przeszkadzało mi, że wiąże się ono z dość sporą ilością powtarzalnego kodu (tzw. boilerplate’u), wymaganego, by wszystkie elementy interfejsu zostały osadzone na właściwym miejscu. Nawet jeśli projektujemy dość prosty, jednookienkowy program, to kod odpowiadający za GUI może już taki trywialny nie być.

Jeśli zatem potrzebujesz stworzyć nieskomplikowane GUI, ale do użycia Qt zniechęca Cię konieczność wgłębiania się w dokumentację żeby wiedzieć jakiego LayoutManagera użyć, aby przycisk znajdował się tam, gdzie chcesz, a nie gdzie mu się podoba, to warto zwrócić uwagę na rozwiązania, które w znaczny sposób upraszczają tworzenie interfejsu użytkownika. Taką właśnie biblioteką jest między innymi Guietta, którą specjalnie na potrzeby niniejszego artykułu postanowiłem przetestować.

Guietta w akcji

Główny pomysł polega na umożliwieniu definiowania layoutu aplikacji w bardzo intuicyjny sposób, w którym m.in. typy poszczególnych elementów są wnioskowane przez Guiettę, a docelowy wygląd interfejsu ma swoje odwzorowanie w kodzie źródłowym. Na przyklad, chcąc uzyskać prosty interfejs, składający się z trzech etykiet, pola edycji oraz przycisku, możemy użyć takiego oto kodu:

Jak widać, ciąg znaków rozpoczynający się i kończący się podwójnym podkreśleniem (__value__) został zamieniony na obiekt typu QLineEditstring tworzący jednoelementową listę (['Convert']) został przetransformowany na instancję klasy QPushButton, a wszystkie pozostałe teksty stały się zwykłymi etykietami (QLabel).  W dokumentacji Guietty można znaleźć informacje o pozostałych zasadach konwersji na inne elementy UI, ale niestety nie jest ich zbyt dużo. Cóż, w końcu to tylko biblioteka do tworzenia prostych, a nawet bardzo prostych interfejsów. 

Randomowe koty

Postanowiłem sprawdzić jak Guietta spisze się w przypadku czegoś nieco bardziej skomplikowanego i z tej okazji przygotowałem niewielki programik, wyświetlający losowe obrazki kotów oraz psów. Składa się on z trzech okien, które wyświetlane są kolejno po sobie, tj. dopiero po zamknięciu wcześniejszego, otwierane jest kolejne.

W ramach uzupełnienia przedstawiam również kod odpowiedzialny za pobieranie obrazków, który wprawdzie nie ma nic wspólnego z samą Guiettą, ale stanowi ważną logikę biznesową związaną ze śmiesznymi obrazkami kotów (i psów), a to przecież bardzo poważna sprawa.

Żeby całość zadziałała jak należy, to oprócz wrzucenia obu plików do jednego katalogu, trzeba również umieścić tam plik img.png , do którego odnosimy się w kodzie. Pozwoli nam to uzyskać niezwykły efekt tajemniczości w postaci enigmatycznego znaku zapytania widniejącego przed dokonaniem pierwszego losowania.

Jeśli chodzi o ciekawsze fragmenty w powyższym kodzie, to:

  • Okazuje się, że aby wymusić stworzenie etykiety z ustawionym QPixmap(obrazkiem), nie wystarczyć użyć w nazwie elementu rozszerzenia przypisanego do któregoś z popularnych formatów graficznych. Musi być to istniejący plik z obrazkiem, stąd pomysł wrzucenia początkowej grafiki z pytajnikiem. Oczywiście równie dobrze można zacząć od pobrania losowego zdjęcia i zastosowania jego ścieżki przy definiowaniu UI drugiego okna, ale jeśli nie dokonamy wcześniej zmiany nazwy ściągniętej ilustracji, to domyślnie nazwa elementu będzie taka jak nazwa losowego zdjęcia.
  • Używając Guietty można bezpośrednio korzystać z Qt-owych metod poszczególnych obiektów. Na przykład w celu dynamicznej podmiany grafiki:
  • Istnieje kilka sposobów łączenia eventów wysyłanych przez obiekty z funkcjami, które mają zostać wykonane po ich otrzymaniu. Jeden z nich, którego użyłem w kodzie, to macierz zbudowana analogicznie jak sama definicja layoutu:

  • Zdefiniowane UI (okno) możemy powołać do życia poprzez wywołanie na nim metody .run() bądź .get(). Pierwsza z nich zakończy swoje działanie w chwili bezpośredniego zamknięcia okna np. poprzez przycisk krzyżyka, natomiast druga zwróci pierwsze zdarzenie wysłane przez dowolny z elementów znajdujących się w środku. Mając okno z dwoma przyciskami można zatem spodziewać się, że otrzymany event będzie pochodził od którego z buttonów lub zwrócone zostanie None jeżeli zamiast kliknąć przycisk, użytkownik brutalnie zamknie okno

Podsumowanie

Czy po zapoznaniu się z biblioteką Guietta skorzystam z niej jeszcze w przyszłości? Chociaż jest to bardzo proste narzędzie o dość ograniczonych możliwościach, to nie wykluczam, że może się przydać. Wprawdzie tworząc różne niewielkie programy narzędziowe będące pomocą przy doraźnych zadaniach zazwyczaj ograniczam się do środowiska konsolowego, ale nigdy nie wiadomo jakie wymagania przyniesie przyszłość i jak szybko będzie trzeba z nich wybrnąć. 😉

Linki

  1. Oficjalna strona projektu
.