[TUTORIAL] Python, GTK+ 3 e Flatpak

tutorial
#1

Neste texto gostaria de exemplificar a construção de um pequeno aplicativo no melhor estilo hello world :sunglasses: (Olá Mundo).

OBS: Caso eu tenha criado o tópico no lugar errado, algum moderado favor direcionar para o local correto :grin:.

Resolvi escrever sobre o tema devido a uma das perguntas aqui do fórum:

Qual a vantagem de usar Flatpak?

A ideia é apenas mostrar um outro ponto de vista para o crescimento do Flatpak.

O qual acredito que não seja apenas pelo isolamento da aplicação (e outras vantagens e desvantagens discutidas no link acima), mais sim pelo conjunto de ferramentas que o Gnome tem disponibilizado para o desenvolvimento de aplicativos.

Digo isso porque independente da linguagem de programação sempre chegamos em um ponto onde a criação de binários, o empacotamento e distribuição se tornam problemáticos.

Para este texto meio tutorial serão utilizadas as seguintes ferramentas:

Gnome Builder

O GNOME Builder é um ambiente de desenvolvimento integrado (IDE) com foco no desenvolvimento de aplicativos para o ecossistema do Gnome.

Ele irá fornecer uma estrutura de projeto padronizada e é nele que iremos desenvolver a lógica do aplicativo.

Acredito que em algum momento o designe da interface será encorporado a ele.

Até o momento em que escrevo é possível trabalhar com as linguagens:

  • C#.
  • C.
  • C++.
  • JavaScript.
  • Python.
  • Vala.

A instalação do Gnome Builder pode ser realizada via repositório (apt, dnf, yay, etc) das distribuições Linux.

Exemplo: sudo apt install gnome-builder

No entanto para utilizar as versões mais recentes ou mesmo a versão de desenvolvimento é recomendada a instalação via Flatpak.

Glade

O Glade é uma ferramenta que permite a criação de interfaces gráficas de forma visual.

O grande beneficio dessa prática é poder separar o designe da interface, da lógica de programação.

Essa interface gerada pelo Glade pode ser utilizada juntamente com a linguagem Python através da Classe Gtk.Builder() ou pelo decorador @GtkTemplate() do Gnome Builder.

A instalação do Glade pode ser feita também via repositório (apt, dnf, yay, etc) das distribuições Linux.

Exemplo: sudo apt install glade

Sua instalação também pode ser feita utilizando-se Flatpak.

Neste caso acredito que não existam grandes diferenças entre a versão do repositório e o Flatpak, a menos que se esteja utilizando uma distribuição mais antiga ou com foco em estabilidade.

Iniciando o desenvolvimento

Para iniciar o projeto vamos abrir o Gnome Builder, na tela inicial podemos contribuir com algum projeto ou mesmo acessar estes projetos para estudo, no entanto queremos iniciar um novo projeto para isso basta clicar em Novo:

Na tela seguinte podemos configurar o projeto definindo:

  • Nome do projeto.
  • Local do projeto.
  • Linguagem que será utilizada (Python neste caso).
  • Licença do projeto.
  • Se será utilizado controle de versão (git).
  • Modelo do projeto (Selecione Aplicativo do GNOME).

Após realizar as configurações basta clicar em Criar:

O Gnome Builder será iniciado e vai começar a baixar os SDKs (runtimes) necessários para o desenvolvimento do aplicativo:

Com o fim do download podemos iniciar o desenvolvimento.

Vamos começar executando o projeto que já temos, para isso bastar pressionar Ctrl + F5 ou clicar no botão que parece um play na barra de cabeçalho (antiga barra de titulo):

Como resultado temos uma janela com o texto Hello, World!, essa janela é exibida porque escolhemos um modelo do Gnome como base para o projeto.

builder-hello-world

Podemos fechar a janela que foi exibida e começar o desenvolvimento.

Do lado esquerdo do IDE temos a estrutura de diretórios que foi criada para o projeto, o que nos interessa neste momento é a pasta src e os arquivos:

  • window.py: Arquivo/Script Python onde criaremos a lógica do aplicativo.
  • window.ui: Arquivo do tipo XML que descreve a interface do aplicativo.

Vamos começar pelo arquivo window.ui o mesmo deve ser aberto com o Glade para que possamos alterá-lo de forma visual:

Ao abrir o arquivo vemos a mesma janela que foi exibida ao se executar o projeto no Gnome Builder.

A ideia é fazer uma janela que tenha:

  • Um widget do tipo label.
  • um widget do tipo entry.
  • um widget do tipo botão.

Importante notar que cada widget tem um campo chamado ID e este campo deve ser único, isso porque este nome será utilizado como nome de variável no Python!

Caso não queira tentar desenhar a interface da imagem acima utilize o seguinte XML:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <template class="HelloWorldWindow" parent="GtkApplicationWindow">
    <property name="can_focus">False</property>
    <property name="default_width">600</property>
    <property name="default_height">300</property>
    <child type="titlebar">
      <object class="GtkHeaderBar" id="header_bar">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="title">Olá Mundo</property>
        <property name="show_close_button">True</property>
      </object>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="margin_left">5</property>
        <property name="margin_right">5</property>
        <property name="margin_top">5</property>
        <property name="margin_bottom">5</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkEntry" id="entry">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="placeholder_text" translatable="yes">Digite algo</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Este texto será alterado!</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button">
            <property name="label" translatable="yes">Clique Aqui</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </template>
</interface>

Para utilizar este XML basta acessar o arquivo window.ui do Gnome Builder e colar o conteúdo.

Com a interface criada podemos abrir o arquivo window.py do Gnome Builder e começar a desenvolver a lógica.

A ideia é pegar o valor digitado no entry e exibir no label quando o button for clicado, se o entry estiver vazio exibimos outra mensagem.

Para executar a proposta um código possível é:

# window.py
#
# Copyright 2019 Renato Cruz
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from gi.repository import Gtk
from .gi_composites import GtkTemplate

# Decorador que faz a leitura do arquivo ``window.ui``.
@GtkTemplate(ui='/org/gnome/Hello-World/window.ui')
class HelloWorldWindow(Gtk.ApplicationWindow):
    """Classe."""

    __gtype_name__ = 'HelloWorldWindow'

    # Atribuindo os widgets da interface nas variáveis.
    # A ID (XML) deve ser o mesmo da variável.
    entry = GtkTemplate.Child()
    label = GtkTemplate.Child()
    button = GtkTemplate.Child()

    def __init__(self, **kwargs):
        """Construtor/inicializador."""
        super().__init__(**kwargs)
        self.init_template()

        # Conectando o sinal (signal) clicked ao slot (ação).
        # Quando o botão é clicado o método _on_button_clicked() é executado.
        self.button.connect('clicked', self._on_button_clicked)


    def _on_button_clicked(self, button):
        """Método é chamado quando o botão da interface é clicado.

        :param button: Instância do objeto ``Gtk.Button`` que foi pressionado.
        """
        # Verificando se algum valor foi digitado no entry.
        if self.entry.get_text():

            # Alterando o texto do label para o valor digitado no entry.
            self.label.set_label(self.entry.get_text())

        # Se nenhum valor for digitado no entry é exibida uma mensagem no label.
        else:
            self.label.set_label('Digite algo no campo acima!')

Perceba que a solução apresenta acima não é a única possibilidade, todavia foi a que eu considerei mais simples.

Ao executar este código (Ctrl + F5 ) temos como resultado:

builder-app-running

Temos o aplicativo sendo executado e realizado a proposta, agora vamos ver como empacotar e ver o que o Gnome Builder resolve neste aspecto.

Empacotamento

Se não estivéssemos utilizando o Gnome Builder eu teria que começar a utilizar/testar ferramentas como:

E claro na hora de empacotar (deb, rpm, etc) verificar:

  • Se as dependências do Python estão sendo copiadas e compiladas de forma correta.
  • Se o tema, ícones e bibliotecas do Gnome estão sendo copiadas.
  • Entre outros cuidados e detalhes.

Vale notar que mesmo com esses cuidados pode haver uma diferença visual entre o que foi criado e o que é executado. Isso porque cada ambiente gráfico utiliza um CSS e diretórios diferentes para criar o estilo da interface.

Bom pra mim é aqui que o Gnome Builder se destaca, isso porque ele realizada uma abstração de todas essas etapas, claro temos que notar que nosso aplicativo é simples e não possui dependências externas.

Para empacotar e distribuir o aplicativos vamos na barra de cabeçalho do Gnome Builder e vamos clicar na opção exportar:

Ao final do processo basta verifcar o diretório onde o aplicativo foi salvo.

Este diretório costurma ser /home/SeuUsuário/.var/app/org.gnome.Builder/cache/gnome-builder/projects/hello-world/flatpak/staging/x86_64-sem versão/, mas podem haver variações. Na duvida basta ver o final do log que foi gerado no terminal.

Ao acessar o diretório percemos que o formato final é um Flatpak! Sim o Gnome apoia esse formato e reparem que da forma com que está já é possível distribuir o aplicativo, basta dar 2 cliques sobre o arquivo org.gnome.Hello-World.flatpak.

Gnome Software:

KDE Discover:

Com o final da instalação basta procurar o aplicativo no menu da distribuição que se está utilizando.

Com isso finalizamos o nosso aplicativo e realmente tenho que eloginar o trabalho que o projeto Gnome está fazendo com o Gnome Builder.

Em poucos passo conseguimos empacotar e distribuir nosso aplicativo de exemplo.

Conclusão

Eu sei que para o usuário pode ser custoso fazer downloads grandes, problemas com espaço em disco e tudo mais, porém acredito que por muitos anos o mais custoso e doloso foi desenvolver um aplicativo e ter que escolher em qual distribuição o mesmo será executado e até mesmo a fragmentação que é gerada.

Por isso em um primeiro momento não acho critico ou mesmo impeditivo o tamanho do download em vista da praticidade que é gerada (lado do dev).

Claro, cabe analisar que o formato Flatpak está apenas começando e tanto Gnome, KDE e Freedesktop ainda estão se adaptando a este novo formato de empacotamente, acredito inclusive que em alguns anos teremos runtimes bem mais otimizadas .

Caso encontre algum erro favor entrar em contato para que o conteudo possa ser atualizado :slight_smile: . Espero não ter me perdido muito no texto, Valeu!

16 Likes

[TUTORIAL] Python e Qt 5 [Parte 1]
[RESOLVIDO]Como desenvolver softwares nativos para distros Linux?
[TUTORIAL] Python e Qt 5 [Parte 3]
#2

Muito útil, vou até estudar um pouco mais esse sistema e tentar adequá-lo aos meus projetos.

1 Like

#3

parabéns, explicou do ponto de vista técnico e prático da coisa, o porque que devemos incentivar esse tipo de tecnologia, que só tem a nos beneficiar…

3 Likes

#4

Muito sensato e objetivo na abordagem do tema, bom demais.

2 Likes

#5

É esse tipo de conteúdo que faz valer a pena ter criado o fórum! :slight_smile:

3 Likes

#6

Mds do céu. Fantástico seu artigo. Olha, se você criar um blog sobre desenvolvimento com postagens nessa linha, pode ter certeza que eu seria um leitor semanal. Tô aprendendo a programar só por curiosidade mesmo.

3 Likes

#7

Ótimo post!

Eu tenho um blog sobre desenvolvimento (por enquanto só tenho conteúdo de web) e estou tentando iniciar o desenvolvimento de apps nativos pra Linux. Seu post caiu como uma luva!

Você toparia se eu (após fazer uns testes e aprender mais) fizesse um post baseado no seu em meu blog? Eu creditaria você, é claro. O blog é em inglês e mesmo nesse idioma acho difícil encontrar material sobre.

Valeu!

1 Like

#8

Fique a vontade para utilizar o conteúdo @fantinel.
Finalizando a semana de provas da faculdade quero voltar a postar mais contudo aqui no fórum :muscle:.

2 Likes