Ir para o conteúdo

Python e GTK 3: Como adicionar a propriedade name em widgets

Propriedade name

A propriedade name permite a aplicação de estilos personalizados em determinados componentes da interface gráfica.

Para a criação do estilo personalizado é utilizado um arquivo do tipo CSS (Cascading Style Sheets).

No GTK podemos adicionar a propriedade name (nome) a um ou mais widgets (componentes).

Nesse post veremos:

  • Como adicionar a propriedade name a um componente.
  • Como criar um estilo simples utilizando CSS .
  • Como aplicar o estilo no aplicativo.

Adicionando a propriedade name

XML

A propriedade name pode ser adicionada no arquivos de interface *.ui (Gnome Builder) e *.glade (Gnome Glade) seguindo-se como exemplo o seguinte snippet (trecho de código):

1
<property name="name">nome-que-se-deseja-dar</property>

Gnome Builder

Para definir a propriedade name de um componente basta clicar sobre o arquivo de interface e selecionar a opção ver construção:

Gnome Builder selecionando o arquivo de interface e clicando em ver construção Gnome Builder selecionando o arquivo de interface e clicando em ver construção

Uma vez que a interface esteja sendo exibida selecione algum componente e clique na aba Comum.

Em seguida no campo Nome do componente digite o nome que o componente irá utilizar:

Gnome Builder adicionando o nome que o componente irá utilizar Gnome Builder adicionando o nome que o componente irá utilizar

Gnome Glade

No Gnome Glade a adição da tag class é feita do do mesmo modo que no Gnome Bulder.

Abra algum arquivo de interface criado com o Gnome Glade, clique sobre o componente que será configurado, selecione a aba Comum e digite no campo Nome do componente o nome que se deseja adicionar ao componente:

Gnome Glade adicionando o nome que o componente irá utilizar Gnome Glade adicionando o nome que o componente irá utilizar

Com Python

Para definir a propriedade name com Python é utilizado o método set_name() :

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: utf-8 -*-
"""Utilizando set_name()."""

import gi

gi.require_version(namespace='Gtk', version='3.0')

from gi.repository import Gio, Gtk


class MainWindow(Gtk.ApplicationWindow):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.set_title(title='Python com GTK')
        self.set_default_size(width=1366 / 2, height=768 / 2)
        self.set_position(position=Gtk.WindowPosition.CENTER)

        label = Gtk.Label.new(str='Hello World')
        # Definindo o nome do componente.
        label.set_name(name='NomeDoComponente')
        self.add(widget=label)

        self.show_all()


class Application(Gtk.Application):

    def __init__(self):
        super().__init__(application_id='br.natorsc.Exemplo',
                         flags=Gio.ApplicationFlags.FLAGS_NONE)

    def do_startup(self):
        Gtk.Application.do_startup(self)

    def do_activate(self):
        win = self.props.active_window
        if not win:
            win = MainWindow(application=self)
        win.present()

    def do_shutdown(self):
        Gtk.Application.do_shutdown(self)


if __name__ == '__main__':
    import sys

    app = Application()
    app.run(sys.argv)

Exemplo de utilização

Neste código de exemplo vamos criar um arqquivo chamado MainWindow.py , nele vamos criar 4 labels, onde 2 terão a propriedade name definida como label-bg-red e os outros 2 não:

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# -*- coding: utf-8 -*-
"""Código de exemplo com 4 labels:

* 2 labels onde foi definida a propriedade `name=label-bg-red`.
* 2 labels sem a tag class.
"""

import gi

gi.require_version(namespace='Gtk', version='3.0')
from gi.repository import Gio, Gtk, Gdk


class MainWindow(Gtk.ApplicationWindow):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.set_title(title='Utilizando set_name().')
        self.set_default_size(width=1366 / 2, height=768 / 2)
        self.set_position(position=Gtk.WindowPosition.CENTER)

        vbox = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        vbox.set_border_width(border_width=12)
        self.add(widget=vbox)

        for i in range(1, 3):
            label = Gtk.Label.new(str=f'Label {i} COM classe label-bg-red')
            label.set_name(name='label-bg-red')
            vbox.pack_start(child=label, expand=True, fill=True, padding=0)

        for i in range(1, 3):
            label = Gtk.Label.new(str=f'Label {i} SEM classe label-bg-red')
            vbox.pack_start(child=label, expand=True, fill=True, padding=0)

        self.show_all()


class Application(Gtk.Application):

    def __init__(self):
        super().__init__(application_id='br.natorsc.Exemplo',
                         flags=Gio.ApplicationFlags.FLAGS_NONE)

    def do_startup(self):
        Gtk.Application.do_startup(self)

    def do_activate(self):
        win = self.props.active_window
        if not win:
            win = MainWindow(application=self)
        win.present()

    def do_shutdown(self):
        Gtk.Application.do_shutdown(self)


if __name__ == '__main__':
    import sys

    app = Application()
    app.run(sys.argv)

Como resultado da execução do código temos:

Executando o código de exemplo Executando o código de exemplo

Nosso aplicativo de exemplo está funcionando perfeitamente e agora devemos criar e carregar o arquivo CSS personalizado.

Criando o arquivo CSS personalizado

No mesmo diretório do arquivo MainWindow.py vamos criar um arquivo CSS com o nome custom.css.

Em seguida será adicionado o seguinte código no arquivo:

1
2
3
4
5
/* # = Seletor utilizado para a propriedade name do widget. */
#label-bg-red {
    background-color: darkred;
    color: white;
}

Nota

O resultado esperado do código CSS acima é que labels que possuam a propriedade name definida como label-bg-red tenham cor de fundo vermelho escuro e que a cor do texto seja branca.

Carregando o arquivo CSS personalizado

Para utilizar o estilo que acabamos de criar devemos utilizar Gtk.CssProvider.new() para fazer a leitura do arquivo CSS e Gtk.StyleContext.new() para definir que o aplicativo deve utilizar esse arquivo css personalizado.

O código a seguir é uma receita e pode ser utilizada sempre que houver a necessidade de se utilizar um arquivo CSS personalizado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
css_provider = Gtk.CssProvider.new()
css_provider.load_from_path(path='caminho-até-o-arquivo.css')

screen = Gdk.Screen()

style_context = Gtk.StyleContext.new()
style_context.add_provider_for_screen(
    screen=screen.get_default(),
    provider=css_provider,
    priority=Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
)

Por fim vamos adicionar o arquivo CSS que criamos no código de exemplo:

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# -*- coding: utf-8 -*-
"""Código de exemplo com 4 labels:

* 2 labels onde foi definida uma tag class `label-bg-red`.
* 2 labels sem a tag class.
"""

import gi

gi.require_version(namespace='Gtk', version='3.0')
from gi.repository import Gio, Gtk, Gdk


def load_custom_css(file):
    css_provider = Gtk.CssProvider.new()
    css_provider.load_from_path(path=file)

    screen = Gdk.Screen()

    style_context = Gtk.StyleContext.new()
    style_context.add_provider_for_screen(
        screen=screen.get_default(),
        provider=css_provider,
        priority=Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
    )


class MainWindow(Gtk.ApplicationWindow):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.set_title(title='Estilo personalizado com a propriedade name')
        self.set_default_size(width=1366 / 2, height=768 / 2)
        self.set_position(position=Gtk.WindowPosition.CENTER)

        vbox = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        vbox.set_border_width(border_width=12)
        self.add(widget=vbox)

        for i in range(1, 3):
            label = Gtk.Label.new(str=f'Label {i} COM classe label-bg-red')
            label.set_name(name='label-bg-red')
            vbox.pack_start(child=label, expand=True, fill=True, padding=0)

        for i in range(1, 3):
            label = Gtk.Label.new(str=f'Label {i} SEM classe label-bg-red')
            vbox.pack_start(child=label, expand=True, fill=True, padding=0)

        self.show_all()


class Application(Gtk.Application):

    def __init__(self):
        super().__init__(application_id='br.natorsc.Exemplo',
                         flags=Gio.ApplicationFlags.FLAGS_NONE)

    def do_startup(self):
        Gtk.Application.do_startup(self)

        # Carregando e aplicando o arquivo de css personalizado.
        load_custom_css(file='custom.css')

    def do_activate(self):
        win = self.props.active_window
        if not win:
            win = MainWindow(application=self)
        win.present()

    def do_shutdown(self):
        Gtk.Application.do_shutdown(self)


if __name__ == '__main__':
    import sys

    app = Application()
    app.run(sys.argv)

Nota

Dei preferencia por criar um método (def load_custom_css(file)) que realiza essa operação de leitura e configuração do arquivo CSS.

Simta-se a vontade para implementar da forma que julgar mais prático.

Ao executar novamente o código de exemplo temos como resultado:

Executando o código de exemplo com o arquivo CSS personalizado Executando o código de exemplo com o arquivo CSS personalizado

Como esperado, apenas os labels que possuem a propriedade name=labal-bg-red tem a cor de fundo vermelho escuro e a fonte branca.

Extra

Cuidado

Se a distribuição Linux realiza alterações no tema padrão do Gnome/GTK essas classes (suggested-action e destructive-action) podem acabar tendo cores diferentes ou mesmo cor alguma.

A propriedade name pode ser altara em tempo de execução, só para ilustrar:

Alterando a proriedade name durante a execução do aplicativo Alterando a proriedade name durante a execução do aplicativo