Баннер мобильный (1) Пройти тест

Как написать приложение для Linux на Python

Создаем магический шар на языке Python

Инструкция

12 апреля 2024

Поделиться

Скопировано
Как написать приложение для Linux на Python

Содержание

    Расскажем, как написать простое приложение для Linux на Python. В качестве примера создадим магический шар с предсказаниями.

    GNOME Builder и создание проекта

    Приложение, которое мы будем писать, называется Predictor — «Предсказатель». Это простое игровое приложение будет имитировать работу магического шара с предсказаниями и показывать пользователю случайные фразы из специального списка. Исчезновение и появление фраз будет анимированным. Чтобы написать программу, используем компоненты из GTK и Adwaita. Весь исходный код приложения можно посмотреть здесь

    Для разработки этой программы идеально подойдет интегрированная среда разработки (IDE) GNOME Builder. Ее специально создали, чтобы писать приложения для среды рабочего стола GNOME, которая очень популярна среди дистрибутивов GNU/Linux. Скачать ее можно здесь. После запуска среды разработки нужно ввести название проекта (predictor) и некоторые другие параметры. 

    Писать приложение мы будем на языке Python. В качестве шаблона выбираем пункт «Приложение среды GNOME». Идентификатор приложения (ID) можно выбрать любой, а можно вообще оставить это поле пустым. В итоге заполненная форма должна выглядеть примерно так:

    Создать новый проект
    Источник: автор статьи

    Нажимаем «Создать проект» и видим вот такое окно:

    Python-скрипт
    Источник: автор статьи

    Это Python-скрипт, в котором будет находиться весь наш код. Приложение запускается изолированно от основной системы. Среда выполнения установилась вместе со средой разработки, поэтому дополнительно ничего ставить не нужно. Если что и понадобится (какой-нибудь SDK, например), то Builder сам предложит и установит все необходимое в автоматическом режиме. В заголовке окна нажмем на черный треугольник. Наша программа запущена:

    Hello, World!
    Источник: автор статьи

    Мы видим стандартное приветствие Hello, World. Его мы будем переделывать, чтобы получить нашу программу. Для этого нам понадобится файл описания интерфейса. Это файл с именем window.ui, и его содержимое выглядит следующим образом:

    Файл с именем window.ui
    Источник: автор статьи

    Такие файлы очень неудобны для ручного редактирования, поэтому лучше использовать специально созданные для этого конструкторы. Один из них мы и будем использовать.

    Cambalache и конструирование интерфейса

    Называется этот конструктор Cambalache — удобный инструмент для быстрого создания графических интерфейсов. Скачать его можно отсюда. Откроем наш файл интерфейса в конструкторе. Для этого в GNOME Builder необходимо перейти в файл window.ui и открыть его при помощи внешней программы. В качестве внешней программы в контекстном меню следует выбрать Cambalache. После выбора мы увидим следующее:

     Конструктор Cambalache
    Источник: автор статьи

    Приступим к конструированию интерфейса. Для начала нужно удалить метку с текстом приветствия. Затем через строку поиска найдем компонент GtkBox и добавим его в наше окно. Должно получиться так:

    Компонент GtkBox
    Источник: автор статьи

    В правой панели поменяем ориентацию контейнера на вертикальную, а с помощью комбинации клавиш Ctrl+Delete удалим лишнюю секцию. В итоге получим такой вид:

    Вертикальная ориентация контейнера
    Источник: автор статьи

    В верхнюю часть контейнера добавим компонент GtkRevealer. Он нужен для анимирования содержащихся в нем компонентов. Укажем для него в правой панели тип перехода (transition-type) — crossfade и время перехода (transition-duration) — 5000. В нашем случае в GtkRevealer будет содержаться текстовая метка GtkLabel. Добавим ее и получим примерно следующее:

    Компонент GtkRevealer
    Источник: автор статьи

    Не забываем прописывать идентификаторы (id) для некоторых компонентов, к которым мы будем обращаться из кода. Идентификатор содержится в самом верхнем поле правой панели и отображается в левой рядом с названием компонента. Так, для GtkRevealer идентификатор — revealer, а для GtkLabel — label. 

    Теперь добавим кнопку GtkButton. Для нее указываем идентификатор (button) и в правой панели в поле css-classes прописываем стили pill и suggested-action. Благодаря указанным стилям кнопка будет закругленной и изменит цвет. Интерфейс примет следующий вид:

    Кнопка GtkButton
    Источник: автор статьи

    Интерфейс готов. Нажимаем в меню Export all, и если сейчас запустить проект посредством Builder, то мы увидим это:

    Заготовка интерфейса
    Источник: автор статьи

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

    Логика приложения

    Вся логика приложения находится в файле window.py. В начале класса PredictorWindow нужно проинициализировать компоненты, созданные при помощи Cambalache:

      label = Gtk.Template.Child()
      button = Gtk.Template.Child()
      revealer = Gtk.Template.Child()

    Это необходимо для того, чтобы можно было обращаться к этим объектам в коде. Также нам понадобится строковый массив, в котором будут храниться фразы для предсказаний. Создадим и его:

    arr_str = []

    Массив пока пустой, и чтобы его заполнить, в функции init пропишем следующее:

            self.arr_str.append(_("It is certain."))
            self.arr_str.append(_("It is decidedly so."))
            self.arr_str.append(_("Without a doubt."))
            self.arr_str.append(_("Yes--definitely."))
            self.arr_str.append(_("You may rely on it."))
            self.arr_str.append(_("As I see it, yes."))
            self.arr_str.append(_("Most likely."))
            self.arr_str.append(_("Outlook good."))
            self.arr_str.append(_("Yes."))
            self.arr_str.append(_("Signs point to yes."))
            self.arr_str.append(_("Yep!"))
            self.arr_str.append(_("Absolutely!"))
            self.arr_str.append(_("You bet!"))
            self.arr_str.append(_("Confirmed."))
            self.arr_str.append(_("Don't count on it."))
            self.arr_str.append(_("My reply is no."))
            self.arr_str.append(_("My sources say no."))
            self.arr_str.append(_("Outlook not so good."))
            self.arr_str.append(_("Very doubtful."))
            self.arr_str.append(_("Naw."))
            self.arr_str.append(_("I've got a bad feeling about this..."))
            self.arr_str.append(_("Reply hazy, try again."))
            self.arr_str.append(_("Ask again later."))
            self.arr_str.append(_("Better not tell you now."))
            self.arr_str.append(_("Cannot predict now."))
            self.arr_str.append(_("Concentrate and ask again."))
            self.arr_str.append(_("Impossible to see, the future is."))
            self.arr_str.append(_("404 Answer Not Found"))

    Таким образом, наш массив теперь содержит все необходимые фразы. Эти фразы в случайном порядке нужно отображать в текстовой метке после нажатия на кнопку. Отображаться они будут с эффектом затухания и медленного проявления, о чем позаботится Revealer. Также следует подумать и о цвете текста каждой фразы. 

    Весь набор фраз делится на три группы. Первая группа — позитивные фразы, и они окрашиваются в зеленый цвет. Вторая группа — негативные фразы. Их цвет — красный. Фразы из третьей группы имеют нейтральный характер и окрашиваются в серый цвет. Прежде чем рассматривать функцию, которая срабатывает при нажатии на кнопку, нужно сначала связать эту функцию с кнопкой. В init добавим такую строчку:

    self.button.connect('clicked', self.on_button_clicked)

    Сама функция on_button_clicked имеет такой вид:

    def on_button_clicked(self, widget):
    
            self.revealer.set_reveal_child(not self.revealer.get_child_revealed)
    
            GLib.timeout_add(6000, self.after_timeout)
    
            self.button.set_sensitive(False)

    Первая строчка заставляет фразу исчезнуть с эффектом затухания. А вот чтобы медленно проявилась следующая фраза, вызывается функция after_timeout, но вызывается она после временной задержки в шесть секунд. Содержимое функции after_timeout:

    def after_timeout(self):
    
            self.revealer.set_reveal_child(self.revealer.get_child_revealed)
    
            rand = random.randint(0, 27)
    
            self.label.set_text(self.arr_str[rand])
    
            self.label.remove_css_class('success')
            self.label.remove_css_class('error')
            self.label.remove_css_class('warning')
    
            if rand < 14:
              self.label.add_css_class('success')
            elif rand > 13 and rand < 21:
              self.label.add_css_class('error')
            else:
              self.label.add_css_class('warning')
    
            if self.revealer.get_child_revealed:
              self.button.set_sensitive(True)
              self.button.grab_focus()

    Первая строка в теле функции заставляет фразу медленно появляться, а вот какая это будет фраза и какого цвета — об этом заботятся следующие команды. Команда на второй строке генерирует случайное число от нуля до 27-и. Это будет индекс элемента массива, в котором содержатся фразы предсказаний. На следующем шаге фраза с полученным ранее индексом отображается в метке.

    Следующая группа из трех команд удаляет классы стилей из текстовой метки. Далее при помощи оператора выбора нужные стили добавляются, и таким образом метка окрашивается в нужный цвет. Для того чтобы какая-нибудь фраза отображалась сразу после запуска приложения, в init следует добавить эту строчку:

    GLib.timeout_add(1000, self.after_timeout)

    Чтобы приложение сохраняло размер своего окна при перезапуске, в функцию init надо добавить следующее:

    settings = Gio.Settings(schema_id="io.github.alexkdeveloper.predictor")
    
    settings.bind("width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
    settings.bind("height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
    settings.bind("is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
    settings.bind("is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT)

    Как видим, для Settings указан параметр в виде schema_id. Это идентификатор схемы. В папке data имеется файл с расширением …gschema.xml. Добавим в него такое содержимое:

    <?xml version="1.0" encoding="UTF-8"?>
    <schemalist gettext-domain="predictor">
    <schema id="io.github.alexkdeveloper.predictor" path="/io/github/alexkdeveloper/predictor/">
      <key name="width" type="i">
          <default>600</default>
        </key>
        <key name="height" type="i">
          <default>300</default>
        </key>
        <key name="is-maximized" type="b">
          <default>false</default>
        </key>
        <key name="is-fullscreen" type="b">
          <default>false</default>
        </key>
    </schema>
    </schemalist>

    Теперь программа может запоминать длину и ширину своего окна и восстанавливать их при каждом новом запуске. Также в самом начале исходника нужно прописать соответствующие импорты:

    import random
    
    from gi.repository import Adw
    from gi.repository import Gtk
    from gi.repository import GLib
    from gi.repository import Gio

    Можно попробовать запустить наше приложение. Нажимаем на кнопку запуска в верхней панели и видим примерно такое:

    Интерфейс с предсказанием на английском языке
    Источник: автор статьи

    Все работает, но фразы отображаются на английском языке. Давайте добавим перевод на русский язык.

    Добавляем перевод

    Все переводы хранятся в папке po. Для перевода программы будем использовать редактор Poedit. Загрузить его можно отсюда. После запуска нас встречает окно приветствия:

    Редактор Poedit
    Источник: автор статьи

    Открываем меню и нажимаем «Создать». После выбора языка нас встречает такое окно:

    Создание перевода
    Источник: автор статьи

    Нажимаем «Сохранить» и выбираем место, куда следует сохранить файл с русским переводом. Обычно это папка po проекта, а файл перевода в этой папке называется ru.po. Далее выбираем пункт «Извлечь из исходного кода» и указываем файлы проекта, для которых требуется перевод. В нашем случае это файлы window.py и window.ui. Можно просто указать папку src. В конце концов мы увидим это:

    Финальный вид в Poedit
    Источник: автор статьи

    Думаем, здесь не требуется особых пояснений. Заполняем все отсутствующие пункты справа и нажимаем на «Сохранить» сверху. Перевод готов! Осталось только указать язык в файле LINGUAS. По умолчанию этот файл должен быть пуст. Чтобы указать в нем свой перевод на русский язык, нужно просто прописать в этом файле: ru.

    Запуск и упаковка

    Если запустить проект после добавления перевода, то скорее всего нас будет ждать разочарование. Builder все так же запустит проект с англоязычной локализацией. Исправить это можно путем небольшого редактирования манифеста. Это файл с расширением .json, находящийся в корне проекта. Именно в соответствии с этим файлом и происходит сборка проекта. В раздел finish-args манифеста нужно добавить эту строчку:

    "--env=LC_ALL=ru_RU.UTF-8"

    То есть упомянутый раздел в итоге должен быть приведен в такой вид:

    "finish-args" : [
            "--share=ipc",
            "--socket=fallback-x11",
            "--device=dri",
            "--socket=wayland",
            "--env=LC_ALL=ru_RU.UTF-8"
        ]

    Теперь после запуска наше приложение будет выглядеть примерно так:

    Предсказание на русском языке
    Источник: автор статьи

    Сейчас очень популярны самодостаточные пакеты в формате flatpak. Они работают изолированно от основной системы и не засоряют ее кучей лишних зависимостей. Builder по умолчанию упаковывает приложения как раз в этом формате. Перед упаковкой добавленную строку в манифесте с указанием языковой локали следует удалить, так как установленное приложение при запуске само способно определять локализацию.

    Чтобы упаковать приложение в пакет flatpak, в Builder, в левой панели, нужно переключиться на вкладку под названием «Конвейер сборки» и в ней выбрать самый последний пункт. После успешной сборки пакета папка с ним откроется в файловом менеджере. Теперь этот пакет можно установить с помощью того же Центра приложений или подобного ему инструмента.

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

    Инструкция

    Поделиться

    Скопировано
    0 комментариев
    Комментарии