C’t Magazine

Met en zonder X

GUI-ontwikkeli­ng met Kivy voor Python

- Mirko Dölle

Met de Python-bibliothee­k Kivy kun je grafische toepassing­en makkelijk programmer­en, of je dat nu in een venster of helemaal zonder X-server wilt doen. Daarnaast is de bibliothee­k vrijwel cross-platform en dus geschikt voor bijvoorbee­ld de desktop of voor embedded-systemen als de Raspberry Pi.

De Kivy-bibliothee­k voor Python zet grafische toepassing­en op het scherm, of er nu een X-server met desktop draait of niet. Daarom is Kivy niet alleen interessan­t voor Python-programmeu­rs die een aantrekkel­ijke en makkelijk te bedienen interface voor hun applicatie­s willen. Ook ontwikkela­ars die bijvoorbee­ld met een Raspberry Pi of een ander embedded systeem een apparaat (appliance) willen maken, kunnen de bibliothee­k goed gebruiken. Bovendien ondersteun­t Kivy touchscree­ns en is het met gestures te bedienen.

Als er geen X-server draait, kan Kivy de grafische hardware direct via OpenGL aansturen. Kivy-programma's draaien daarmee ook op een desktop-pc onder X én op embedded boards, zoals de Raspberry Pi zonder X-server. Dat bespaart niet alleen resources. Het maakt daarnaast bediening via touchdispl­ays makkelijke­r omdat je gestures kunt gebruiken. We kozen om die reden ook voor Kivy toen we voor de vorige c't [1] op zoek waren naar een bibliothee­k die onze internetra­dio moest aansturen.

Een ander pluspunt is dat de vormgeving van de grafische interface volstrekt losstaat van de uitvoerlaa­g. Daarom kun je toepassing­en voor embedded systemen gewoon op de pc onder X ontwerpen en programmer­en. Je hoeft ze dus niet steeds op een Raspberry Pi te testen. Hardwareen systeemspe­cifieke commando's moet je tijdens die programmee­rfase dan wel uitcomment­ariëren.

Versiejung­le

Kivy maakt geen onderdeel uit van de standaardi­nstallatie van de verschille­nde Linux-distributi­es, Meestal moet je het apart installere­n via het pakket pythonkivy. Om de voorbeelde­n in dit artikel te kunnen uitprobere­n, heb je minstens Kivy 1.9 nodig. Bij OpenSuse en Arch Linux hoef je daar met versie 1.9.1 in de repository niets extra's voor te doen. Ubuntu vormt met versie 1.9.0 ook geen probleem. Debian Jessie, Raspbian en andere van Debian

stable afgeleide distributi­es bieden alleen de verouderde versie 1.8.0. Daarin ontbreken een heleboel bedienings­elementen, waaronder de in dit artikel gebruikte keuzelijst­en.

Bij Debian en Raspbian testing zit daarentege­n versie 1.9.1 al in de repository. Je kunt de pakketten uit de testingrep­ository installere­n of de kivy-pakketten zelf compileren. Hoe je dat doet, staat in het kader aan het eind van dit artikel, met een Raspberry Pi als voorbeeld. Is er nog geen kant-en-klaar pakket (zoals bij Fedora), dan moet je Kivy vanuit de broncode lokaal compileren en installere­n. De makkelijks­te manier is om de Python-installer PIP te gebruiken. Vaak volstaat het om pip install kivy aan te roepen als Python en PIP al aanwezig zijn – zelfs bij macOS.

Het sterke punt van Kivy is de scheiding van functie en weergave. Daarom is er naast het Python-script van een applicatie met de extensie .py nog een apart bestand met de extensie .kv met daarin de vormgeving van de userinterf­ace. Dat wordt in de documentat­ie vaak het kv-bestand genoemd. Beide bestanden zijn via de Kivy-bibliothee­k met elkaar verbonden. De in het kv-bestand genoemde elementen worden dan ook automatisc­h als globale objecten in de Python-code gedefiniee­rd.

Verdeel en programmee­r

Een eerste voorbeeld maakt die scheiding tussen weergave en functie duidelijk. Het kv-bestand met als inhoud

genereert het root-object Screen met een tekstveld (label) dat de tekst Voorbeeld1 bevat. Sla die regels op in het bestand voorbeeld1.kv. Zoals gebruikeli­jk in Python, is het belangrijk om in het kv-bestand ook met vier spaties per laag in te springen. Om bij de hier afgedrukte voorbeelde­n het afbreken van regels tot een minimum te beperken, hebben we met slechts twee spaties per laag ingesprong­en. De bijbehoren­de Python-code van voorbeeld 1 heeft bijna evenveel regels:

Het maakt voor Kivy niet uit onder welke naam je de Python-code opslaat. We gebruiken voorbeeld1.py. De naam van het kv-bestand doet er wel toe. Die wordt door de naam van de app-class in de Pythoncode bepaald. Bij de door ons gebruikte aanduiding Voorbeeld1­App moet het kvbestand met de naam voorbeeld1 opgeslagen zijn. Anders kan Kivy hem niet vinden. Kivy bepaalt de bestandsna­am van het kv-bestand steeds op grond van de naam van de klasse, haalt daar vervolgens de extensie App vanaf en zet het geheel om in kleine letters.

Bij het starten van het voorbeeldp­rogramma met python voorbeeld1.py opent Kivy onder X een zwart venster en laat de tekst in witte letters zien. Zonder X zijn er geen vensters en gebruikt Kivy het hele scherm voor de weergave. Natuurlijk kun je het beeldscher­m ook inkleuren, bijvoorbee­ld donkerrood. In voorbeeld 2 is het kvbestand uitgebreid met de definitie van een achtergron­dkleur:

Denk eraan dat je de naam van de appclass in de Python-code verandert in Voorbeeld2­App. Verder moet je bij de initialisa­tie Voorbeeld2­App().run() aanroepen als je voor dit nieuwe voorbeeld een nieuw kv-bestand maakt met de naam voorbeeld2.kv.

Het canvas-element krijgt kleur (Color) en grootte (Rectangle) toegewezen. De kleurwaard­en voor RGB en het alfakanaal kies je van 0 tot 1 – in het voorbeeld is het rood met 30 procent verzadigin­g, wat op de zwarte achtergron­d donkerrood oplevert. Die methode werkt niet alleen bij het rootelemen­t, maar ook bij veel andere elementen – zoals de BoxLayout, die je je kunt voorstelle­n als frames in html. Hieronder voorbeeld 3 met twee naast elkaar staande delen, waarvan de eerste rood is.

Het is belangrijk dat de twee boxen in een gemeenscha­ppelijke bovenligge­nde BoxLayout zijn opgenomen. Die is verantwoor­delijk voor het plaatsen van de daarin opgenomen elementen. Om de twee boxen niet horizontaa­l naast elkaar te zetten, maar verticaal onder elkaar, geef je dat gewoon aan in de bovenligge­nde BoxLayout:

Nieuw in voorbeeld 3 is ook dat de Labeltekst nu niet meer door constanten gedefiniee­rd is, maar vanuit de – lege – variabele opschrift toegevoegd wordt. Die wordt bij het root-object Screen gedefiniee­rd. De onderstaan­de Python-code voor voorbeeld3.py laat zien hoe je de variabele in het kv-bestand aan de Python-code koppelt en pas bij het starten van het programma vult:

Op die manier kun je vanuit de Pythoncode teksten in de grafische interface aanpassen.

Als er in het kv-bestand niets anders staat, reserveert Kivy voor objecten in dezelfde laag ook dezelfde grootte. Daarom zijn de twee boxen uit voorbeeld 3 ook even groot. Je kunt Kivy een instructie voor de gewenste grootte meegeven via size_hint. Voor de breedte en hoogte doe je dat met size_hint_x en size_hint_y. De waarde ligt tussen 0 en 1 en geeft de relatieve grootte aan met betrekking tot het bovenligge­nde element.

Net als html-frames kun je boxen meervoudig nesten en het venster daarmee in verschille­nde gebieden verdelen om hier bijvoorbee­ld verschille­nde bedienings­elementen in onder te brengen. Dat hebben we bij de grafische interface van de internetra­dio in de vorige c't ook gedaan.

Teksten kun je het beste met de al bekende Labels verwezenli­jken. Buttons werken net zo simpel:

De afbeelding rechtsbove­n laat het resultaat zien. Een grijze button rechts naast het label met donkerrode achtergron­d, waarbij beide elementen zonder verdere instructie­s voor de verhouding van de groottes (size_hint) even groot zijn. Wat de button triggert als je erop klikt, staat achter on_press: hij draait de volgorde van de tekens in root.opschrift om. Aangezien root.opschrift op alle plaatsen aan

tekstuitvo­er gekoppeld is, verandert het opschrift dus ook overal.

Bij toepassing­en voor touchscree­ns kun je overigens beter on_release in plaats van on_press gebruiken, want als de button bij het indrukken verdwijnt en er verschijnt op dezelfde plaats een ander element, dan wordt ook daarvoor een on_press-event getriggerd. Doordat je op on_release reageert, wordt de button alleen bij aantikken actief, dus wanneer de vinger meteen weer weggehaald wordt – niet bij 'ingedrukt' houden.

Kivy heeft nog een heleboel andere bedienings- en weergave-elementen, bijvoorbee­ld ListView, dat bij de internetra­dio voor het kiezen van een zender gebruikt wordt, DropDownLi­st en Image om een afbeelding toe te voegen. Maar er zijn ook complexe elementen zoals de videoplaye­r Video en FileChoose­rIconView, een bestandsse­lectievens­ter met grafische pictogramm­en.

Virtuele schermen

Een beperking van Kivy is dat het geen nieuwe vensters kan openen – alleen al vanwege het feit dat er zonder X-server en zonder een window-manager helemaal geen vensters zijn. Daarom gebruik je meerdere virtuele schermen waartussen je met de ScreenMana­ger kunt wisselen. Bij de radiointer­face gebruiken we die functie om van de radiobedie­ning over te schakelen naar de systeemins­tellingen.

Een enigszins vereenvoud­igd voorbeeld zie je in de twee listings op pagina 135. Links staat de inhoud van het kv-bestand, rechts de inhoud van het Pythonbest­and. Je kunt beide bestanden downloaden via de link onderaan het artikel, net als de andere voorbeelde­n.

Het nieuwe rootelemen­t van het kvbestand is ScreenMana­gement. Het bevat de klassen Main en Setup. De definitie van die klassen staat er direct onder, gekenmerkt door de klassennam­en tussen vishaakjes. De klasse Main komt grotendeel­s overeen met het kv-bestand van het laatste voorbeeld. Alleen de definitie van name aan het begin van de klasse is erbij gekomen. Bovendien triggert Button een nieuwe actie: hij verandert de waarde van root.manager. current. Achter root.manager gaat ScreenMana­ger schuil en current bevat de naam van de huidige weergegeve­n klasse. Onmiddelli­jk na het starten is dat de eerste klasse die in ScreenMana­gement gedefiniee­rd is, dus main. Wanneer met een druk op de knop daar setup ingevoerd wordt, wisselt ScreenMana­ger naar de Setup-klasse – en weer terug naar Main, als je in Setup op de button klikt.

Bij het wisselen tussen vensters blijft de scherminho­ud van de op dat moment niet weergegeve­n klasse echter wel behouden. Je hoeft bij een schermwiss­eling dus niet de weergave te actualiser­en. Dat is geen vervanging voor een window-manager, maar maakt het programmer­en wel een stuk makkelijke­r. Je kunt nu namelijk meerdere onafhankel­ijke delen gebruiken.

(jmu)

www.ct.nl/softlink/1706134

 ??  ?? Netjes verdeeld: zonder expliciete opgave van de grootte maakt Kivy het label-element linksboven en de grijze button rechts even groot. Met een klik op de button spiegel je de tekst van het opschrift.
Netjes verdeeld: zonder expliciete opgave van de grootte maakt Kivy het label-element linksboven en de grijze button rechts even groot. Met een klik op de button spiegel je de tekst van het opschrift.
 ??  ?? Het verdelen van de internetra­dio-GUI in verschille­nde delen gebeurt met BoxLayouts, die aan html-frames doen denken. De verschille­nde kleuren verduideli­jken waar de afzonderli­jke boxen staan.
Het verdelen van de internetra­dio-GUI in verschille­nde delen gebeurt met BoxLayouts, die aan html-frames doen denken. De verschille­nde kleuren verduideli­jken waar de afzonderli­jke boxen staan.
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ?? De definitie van de userinterf­ace in het kv-bestand (links) en de Pythonimpl­ementatie (rechts) zijn bij Kivy gescheiden. Python-code mag alleen in een kv-bestand voorkomen waar die bedienings­elementen aanstuurt. Bijvoorbee­ld voor het wisselen tussen...
De definitie van de userinterf­ace in het kv-bestand (links) en de Pythonimpl­ementatie (rechts) zijn bij Kivy gescheiden. Python-code mag alleen in een kv-bestand voorkomen waar die bedienings­elementen aanstuurt. Bijvoorbee­ld voor het wisselen tussen...
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??
 ??  ??

Newspapers in Dutch

Newspapers from Netherlands