Skip to main content
Spring naar inhoud

Kirigami met Python

Maak uw eerste Kirigami toepassing met PySide

Vereisten vooraf

Alvorens te beginnen moeten we Kirigami en PySide op onze machine installeren.

logo of Linux operating system ManjaroManjarologo of Linux operating system Arch LinuxArch
sudo pacman -S python-pipx python-pyqt6 pyside6 kirigami flatpak-builder qqc2-desktop-style appstream
logo of Linux operating system openSUSEOpenSUSE
sudo zypper install python3-pipx python3-qt6 python3-pyside6 kf6-kirigami-devel flatpak-builder qqc2-desktop-style AppStream-compose
logo of Linux operating system FedoraFedora
sudo dnf install pipx python3-pyqt6 python3-pyside6 kf6-kirigami-devel flatpak-builder qqc2-desktop-style appstream-compose

Als u op een distributie werkt met oude PySide6 of PyQt6 pakketten, dan werkt deze handleiding met Software bouwen met distrobox.

Projectstructuur

Eerst maken we onze projectmap aan (u kunt de onderstaande commando's gebruiken). De onze gaan we kirigami_python/ noemen.

kirigami_python/
├── README.md
├── LICENSE.txt
├── MANIFEST.in                        # Om onze QML-bestanden toevoegen
├── pyproject.toml                     # Het hoofdbestand om het project te beheren
├── org.kde.kirigami_python.desktop
└── src/
    ├── __init__.py                    # Om de map src/ als een pakket te importeren

    ├── __main__.py                    # Om de toepassing als het entrypoint te signaleren

    ├── app.py
    └── qml/
        └── Main.qml

De pakketnaam wordt kirigami_python, het "uitvoerbare programma" (consolescript) zal kirigami_hello worden genoemd en het entrypoint zal app zijn.

Voor een meer uitgebreid project die in verder detail gaat over deze bestandsstructuur, zie Volledig project in Python + Kirigami.

pyproject.toml

Moderne Python toepassingen hebben alleen een enkel TOML-bestand nodig om alle metagegevens, pakketinformatie en afhankelijkheden zoals van PEP 621 te definiëren. Het volgende dient als een goed startpunt voor een toepassing en later worden uitgebreid.

Het meeste van de inhoud in dit bestand zijn recepten en een completere versie ervan is te zien in Python met Kirigami: Algemene structuur.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "kirigami_python"
version = "0.1"
authors = [
    {name = "Konqi", email = "konqi@example.com"}
]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
    "Intended Audience :: End Users/Desktop",
    "Topic :: Utilities",
    "Programming Language :: Python",
    "Operating System :: POSIX :: Linux",
]

[project.scripts]
kirigami_hello = "kirigami_python.app:main"

[tool.setuptools]
packages = ["kirigami_python"]
package-dir = {kirigami_python = "src"}
include-package-data = true

[tool.setuptools.data-files]
"share/applications" = ["org.kde.kirigami_python.desktop"]

Let op de geaccentueerde regels. Zoals genoemd onder Projectstructuur, is de naam van het pakket kirigami_python, de naam van het uitvoerbare programma is kirigami_hello en de naam van het entrypoint is app. Speciaal het volgende zou opgemerkt moeten worden:

  • Het projectscript bestaat uit een entrypoint-script dat gegenereerd zal worden door opzethulpmiddelen voor de uit te voeren toepassing, in dit geval kirigami_hello.
  • Het gegenereerde projectscript kirigami_hello voert de functie main() uit in het script app.py in het pakket kirigami_python.
  • De standaard package-dir voor Python projecten is gewoonlijk de hoofdmap. In dit geval wordt deze overschreven door de submap src/ zodat het werkt als de hoofdmap van het pakket.
  • De package-dir is waarom het gegenereerde projectscript kirigami_python → app doet in plaats van kirigami_python → src → app.
  • De package-dir is ook waarom de importlib.resources.files() inroepen app.py doet kirigami_python → qml → Main.qml in plaats van kirigami_python → src → qml → Main.qml.

Zie Direct uitvoeren, als een module en als een consolescript voor details.

org.kde.kirigami_python.desktop

Het hoofddoel van Desktop Entry bestanden is te zorgen dat uw programma in de toepassingenstarter van Linux verschijnt. Een andere reden om ze te hebben is om bij Wayland venster-pictogrammen te hebben, omdat ze nodig zijn om de compositor te vertellen "dit venster hoort bij dit icon".

Het moet een reverse-DNS naam-schema volgen gevolgd door de .desktop extensie zoals org.kde.kirigami_python.desktop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Desktop Entry]
Name=Kirigami Tutorial in Python
Name[ca]=Guia d'aprenentatge del Kirigami en Python
Name[eo]=Lernilo pri Kirigami en Python
Name[es]=Tutorial de Kirigami en Python
Name[nl]=Kirigami handleiding in Python
Name[sl]=Učbenik Kirigami v Pythonu
Name[sv]=Kirigami-handledning i Python
Name[uk]=Підручник з Kirigami для Python
Name[x-test]=xxKirigami Tutorial in Pythonxx
Exec=kirigami_hello
Icon=kde
Type=Application
Terminal=false
Categories=Utility

MANIFEST.in

Dit bestand is eenvoudig een declaratie van additionele broncodebestanden die aanwezig zouden moeten zijn in het pakket wanneer de toepassing actief is. Standaard voegt Python geen QML-bestanden in in pakketten en ze moeten beschikbaar zijn om de toepassing uit te kunnen voeren.

1
include src/qml/*.qml

src/app.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3

import os
import sys
import signal
from importlib.resources import files

from PySide6.QtGui import QGuiApplication
from PySide6.QtCore import QUrl
from PySide6.QtQml import QQmlApplicationEngine

def main():
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    """Needed to close the app with Ctrl+C"""
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    """Needed to get proper KDE style outside of Plasma"""
    if not os.environ.get("QT_QUICK_CONTROLS_STYLE"):
        os.environ["QT_QUICK_CONTROLS_STYLE"] = "org.kde.desktop"

    base_path = files('kirigami_python').joinpath('qml', 'Main.qml')
    url = QUrl(f"{base_path}")
    engine.load(url)

    app.exec()

if __name__ == "__main__":
    main()

Omdat dit een GUI-toepassing is, willen we dat de hoofdfunctie alleen wordt uitgevoerd wanneer het script wordt uitgevoerd, niet wanneer het wordt geïmporteerd, dus we hebben de voorwaarde if __name__ == "__main__" nodig aan het eind van het bestand. Zie Direct uitvoeren als een module en als een consolescript voor details.

We maken een QGuiApplication aan en initialiseren de QML-engine en met QGuiApplication.exec() zal de toepassing actief blijven totdat het wordt gesloten. Daarna pakt importlib.resources.files() het pad naar een bestand dat aanwezig is in het pakket, namelijk onze Main.qml. Met dat pad, laden we het QML-bestand in de QML-engine als het hoofd-entrypoint voor het interface van de toepassing.

src/__init__.py

Maak een leeg bestand kirigami_python/src/__init__.py. Dit bestand moet eenvoudig aanwezig zijn om een map als een pakket te importeren.

touch __init__.py

src/__main__.py

Maak een kirigami_python/src/__main__.py aan met de volgen inhoud:

1
2
3
from . import app

app.main()

Dit voegt eenvoudig de inhoud van de huidige map (src/) toe en importeert het als een module genaamd app, daarna wordt onmiddellijk de functie main() van de toepassing uitgevoerd.

src/qml/Main.qml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Includes relevant modules used by the QML
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

// Provides basic features needed for all kirigami applications
Kirigami.ApplicationWindow {
    // Unique identifier to reference this object
    id: root

    width: 400
    height: 300

    // Window title
    title: "Hello World"

    // Set the first page that will be loaded when the app opens
    // This can also be set to an id of a Kirigami.Page
    pageStack.initialPage: Kirigami.Page {
        Controls.Label {
            // Center label horizontally and vertically within parent object
            anchors.centerIn: parent
            text: "Hello World!"
        }
    }
}

Hier gaan we onze frontend van de toepassing behandelen.

Als u enige Javascript kent, dan zal veel van QML u bekend voorkomen (hoewel het zijn eigen eigenaardigheden heeft). Qt's documentation heeft een uitgebreide hoeveelheid materiaal over deze taal als u zelf iets wilt proberen. Gedurende de loop van deze inleidingen zullen we veel van onze aandacht focussen op onze QML code, waar we Kirigami kunnen gebruiken om er het meeste uit te krijgen.

Laten we ons voor nu focussen op Main.qml. Eerst importeren we een aantal belangrijke modulen:

  • QtQuick, de standaard bibliotheek gebruikt in QML toepassingen.
  • QtQuick Controls, die een aantal standaard besturingen levert die we kunnen gebruiken om onze toepassingen interactief te maken.
  • QtQuick Layouts, die hulpmiddelen voor het plaatsen van componenten in de toepassingsvensters levert.
  • Kirigami, die een aantal componenten levert geschikt voor het aanmaken van toepassingen die werken over apparaten met verschillende vormen en groottes.

Daarna komen we bij ons basiselement, Kirigami.ApplicationWindow die enige basis functies levert nodig voor alle Kirigami toepassen. Dit is het venster dat elk van onze pagina's bevat, de hoofdsecties van onze UI.

Daarna zetten we de eigenschap id van het venster op 'root'. ID's zijn nuttig omdat ze ons uniek verwijzen naar een component, zelfs als we er verschillende hebben van hetzelfde type.

We zetten de titel van het venstereigenschap op "Hello World".

Daarna zetten we de eerste pagina van onze pagina stapel. De meeste Kirigami toepassingen zijn georganiseerd als een stapel pagina's, elke pagina bevat gerelateerde componenten passend bij een specifieke taak. Voor nu houden we het eenvoudig en blijven bij een enkele pagina. pageStack is een initieel lege stapel pagina's geleverd door Kirigami.ApplicationWindow en met pageStack.initialPage: Kirigami.Page {...} zetten we de eerste pagina op gepresenteerd bij het laden van de toepassing op een Kirigami.Page. Deze pagina zal al onze inhoud zal bevatten.

Tenslotte voegen we in onze pagina een Controls.Label in die ons tekst laat plaatsen op onze pagina. We gebruiken anchors.centerIn: parent om ons label horizontaal en verticaal te centreren in ons ouderelement. In dit geval is de oudercomponent van Kirigami.Page. Het laatste ding dat we moeten doen is het zetten van zijn tekst: text: "Hello World!".

De toepassing uitvoeren

U kunt het consolescript kirigami_hello uitvoeren zonder het eerst te moeten installeren:

pipx run --system-site-packages --spec . kirigami_hello

De vlag --system-site-packages is nodig om te zorgen dat Python toegang heeft tot de Python-pakketten uit uw distributie. Dit is vereist omdat Kirigami en PySide het nodig heeft te zijn gebouwd tegen dezelfde Qt-versie om te werken, wat het geval is wanneer beiden komen uit de distributie.

De vlag --spec bepaalt het pad naar de broncode of wheel-pakket dat het programma heeft en kirigami_hello is het uitvoerbare script om uit te voeren.

Om het Python-pakket te bouwen , run:

pipx install --force --system-site-packages .

Het pakket zal geïnstalleerd worden in ~/.local/share/pipx/venvs/kirigami-python en een uitvoerbaar script zal geïnstalleerd worden in ~/.local/bin/kirigami_hello.

Hierna kan de toepassing gestart worden door uit te voeren:

kirigami_hello

Om het nieuwe QML-programma in de modus mobiel op te starten, kan u QT_QUICK_CONTROLS_MOBILE=1 gebruiken:

QT_QUICK_CONTROLS_MOBILE=1 kirigami_hello

Voilà! Nu ziet u uw allereerste Kirigami toepassing voor uw eigen ogen verschijnen.

Schermafdruk van de gegenereerde Kirigami toepassing