Skip to main content
Перейти к содержимому

Настройка проекта на Python

Создание первого приложения Kirigami на PySide

Предварительные требования

Прежде чем начать, необходимо установить Kirigami и PySide на компьютере.

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 kf6-qqc2-desktop-style AppStream-compose
logo of Linux operating system FedoraFedora
sudo dnf install pipx python3-pyqt6 python3-pyside6 kf6-kirigami-devel flatpak-builder kf6-qqc2-desktop-style appstream-compose

Если в дистрибутиве установлены старые пакеты PySide6 или PyQt6, для работы с этим руководством можно использовать раздел Сборка программного обеспечения с помощью distrobox.

Структура проекта

Сначала создаётся папка проекта (можно использовать приведённые ниже команды). Папка будет называться kirigami_python/.

kirigami_python/
├── README.md
├── LICENSE.txt
├── MANIFEST.in                        # Добавление файлов QML
├── pyproject.toml                     # Основной файл управления проектом
├── org.kde.kirigami_python.desktop
└── src/
    ├── __init__.py                    # Импорт папки src/ в качестве пакета
    ├── __main__.py                    # Указание app в качестве точки входа
    ├── app.py
    └── qml/
        └── Main.qml

Имя пакета будет kirigami_python, «исполняемый файл» (консольный сценарий) будет называться kirigami_hello, а точкой входа будет app.

Более полный проект, в котором структура этих файлов рассматривается подробнее, описан в разделе Весь проект на Python + Kirigami.

pyproject.toml

Современным приложениям Python достаточно одного файла TOML, чтобы указать все метаданные, сведения о пакете и зависимости в соответствии с PEP 621. Приведённый ниже пример послужит хорошей отправной точкой для приложения, и его можно расширить в дальнейшем.

Большая часть содержимого этого файла — шаблонный код, а более полную его версию можно увидеть в разделе Python с Kirigami: общая структура.

 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"]

Обратите внимание на выделенные строки. Как упоминалось в разделе Структура проекта, имя пакета — kirigami_python, имя исполняемого файла — kirigami_hello, а имя точки входа — app. В частности, следует отметить следующее:

  • Сценарий проекта состоит из сценария точки входа, который будет создан setuptools для запуска приложения, в этом случае — kirigami_hello.
  • Сценарий созданного проекта kirigami_hello запускает функцию main() в сценарии app.py пакета kirigami_python.
  • По умолчанию package-dir для проектов Python обычно является корневой папкой. В этом случае он переопределяется вложенной папкой src/, чтобы тот выступал в роли корневой папки пакета.
  • Именно из-за package-dir созданный сценарий проекта выполняет kirigami_python → app, а не kirigami_python → src → app.
  • package-dir также объясняет, почему вызов importlib.resources.files() в app.py возвращает kirigami_python → qml → Main.qml, а не kirigami_python → src → qml → Main.qml.

Подробнее см. в разделе Прямой запуск, запуск в качестве модуля и в качестве консольного сценария.

org.kde.kirigami_python.desktop

Основное назначение файлов .desktop — показывать приложение в меню запуска приложений в Linux. Ещё одна причина их использовать — значки окон в Wayland, поскольку они нужны, чтобы сообщить композитору: «это окно соответствует этому значку».

Оно должно соответствовать схеме обратного именования DNS, за которой следует расширение .desktop, например org.kde.kirigami_python.desktop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Desktop Entry]
Name=Kirigami Tutorial in Python
Name[ar]=درس كيريغامي ببايثون
Name[ca]=Guia d'aprenentatge del Kirigami en Python
Name[eo]=Lernilo pri Kirigami en Python
Name[es]=Tutorial de Kirigami en Python
Name[fr]=Tutoriel pour Kirigami en Python
Name[it]=Esercitazione di Kirigami in Python
Name[nl]=Kirigami handleiding in Python
Name[pt_BR]=Tutorial do Kirigami em Python
Name[ro]=Îndrumar Kirigami în Python
Name[ru]=Учебное руководство по Kirigami на Python
Name[sk]=Tutoriál Kirigami v Pythone
Name[sl]=Učbenik Kirigami v Pythonu
Name[sv]=Kirigami-handledning i Python
Name[tr]=Python ile Kirigami Öğreticisi
Name[uk]=Підручник з Kirigami для Python
Exec=kirigami_hello
Icon=kde
Type=Application
Terminal=false
Categories=Utility

MANIFEST.in

Этот файл — просто объявление дополнительных файлов исходного кода, которые должны присутствовать в пакете при запуске приложения. Python по умолчанию не включает файлы QML в пакеты, и они должны быть доступны, чтобы приложение работало.

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()

Так как это приложение с графическим интерфейсом, нужно, чтобы главная функция выполнялась только при запуске сценария, а не при его импорте, поэтому в конце файла требуется условие if __name__ == "__main__". Дополнительные сведения см. в разделе Прямой запуск, запуск в качестве модуля и в качестве консольного сценария.

Создаётся QGuiApplication и инициализируется движок QML, а с помощью QGuiApplication.exec() приложение продолжает работу до закрытия. Затем importlib.resources.files() получает путь к файлу, присутствующему в пакете, а именно к Main.qml. С помощью этого пути файл QML загружается в движок QML как основная точка входа для интерфейса приложения.

src/init.py

Создайте пустой файл kirigami_python/src/__init__.py. Этот файл нужен лишь для того, чтобы папку можно было импортировать как пакет.

touch __init__.py

src/main.py

Создайте файл kirigami_python/src/__main__.py со следующим содержимым:

1
2
3
from . import app

app.main()

Он просто добавляет содержимое текущей папки (src/) и импортирует его как модуль с именем app, после чего сразу запускает функцию main() приложения.

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!"
        }
    }
}

Здесь мы займёмся фронтендом приложения.

Тем, кто знаком с JavaScript, многое в QML покажется знакомым (хотя у него есть свои особенности). В документации Qt содержится обширный материал по этому языку, если возникнет желание попробовать что-то самостоятельно. В этих уроках основное внимание будет уделено коду QML, где с помощью Kirigami можно извлечь из него максимум.

Пока сосредоточимся на Main.qml. Сначала импортируем несколько важных модулей:

  • QtQuick — стандартная библиотека, используемая в приложениях QML.
  • QtQuick Controls предоставляет ряд стандартных элементов управления, которые можно использовать, чтобы сделать приложения интерактивными.
  • QtQuick Layouts, который предоставляет средства для размещения компонентов в окне приложения.
  • Kirigami, предоставляющий набор компонентов, подходящих для создания приложений, работающих на устройствах разных форм и размеров.

Далее следует базовый элемент — Kirigami.ApplicationWindow, который предоставляет ряд основных возможностей, необходимых всем приложениям Kirigami. Это окно, в котором будут размещаться все страницы — основные разделы пользовательского интерфейса.

Затем свойству id окна присваивается значение «root». Идентификаторы полезны, поскольку позволяют однозначно ссылаться на компонент, даже если имеется несколько компонентов одного типа.

Также свойству title окна присваивается значение «Hello World».

Затем задаётся первая страница стека страниц. Большинство приложений Kirigami организованы в виде стека страниц, каждая из которых содержит связанные компоненты, подходящие для конкретной задачи. Пока всё делается просто, и используется только одна страница. pageStack — это изначально пустой стек страниц, предоставляемый Kirigami.ApplicationWindow, а с помощью pageStack.initialPage: Kirigami.Page {...} первая страница, показываемая при загрузке приложения, задаётся как Kirigami.Page. Именно на ней будет размещено всё содержимое.

Наконец, на страницу добавляется Controls.Label, позволяющий разместить текст. Чтобы выровнять надпись по центру по горизонтали и вертикали внутри родительского элемента, используется anchors.centerIn: parent. В этом случае родительским компонентом надписи является Kirigami.Page. Последнее, что нужно сделать, — задать её текст: text: "Hello World!".

Запуск приложения

Консольный сценарий kirigami_hello можно запустить без предварительной установки:

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

Флаг --system-site-packages нужен, чтобы Python получил доступ к пакетам Python из дистрибутива. Это необходимо, поскольку Kirigami и PySide должны быть собраны с одной и той же версией Qt, чтобы работать, — а это так, когда оба они входят в состав дистрибутива.

Флаг --spec определяет путь к исходному коду или пакету wheel, содержащему программу, а kirigami_hello — исполняемый сценарий, который нужно запустить.

Для сборки и установки пакета Python выполните:

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

Пакет будет установлен в ~/.local/share/pipx/venvs/kirigami-python, а исполняемый сценарий — в ~/.local/bin/kirigami_hello.

После этого приложение запускается командой:

kirigami_hello

Чтобы запустить новое приложение QML в мобильном режиме, можно использовать QT_QUICK_CONTROLS_MOBILE=1:

QT_QUICK_CONTROLS_MOBILE=1 kirigami_hello

Вот и всё! Теперь перед глазами появится самое первое приложение Kirigami.

Снимок созданного приложения Kirigami