O widget gtk.TreeView permite que mudemos várias propriedades das suas células. Aqui, explicaremos como mudar a cor de fundo da célula, mas a "lógica" por trás de nossos exemplos se aplica a praticamente qualquer propriedade de célula.
A cor de fundo de uma célula é definida pela propriedade "cell-background" do objeto gtk.CellRenderer que a desenha. É possível tanto mudar a cor de todas as células renderizadas pelo objeto (o que geralmente implica em mudar a cor uma coluna), quanto só de algumas células. Aqui, veremos três exemplos de como mudar as cores. Começaremos pelo mais simples, que é justamente mudar a cor de todas as células renderizadas por um gtk.CellRenderer específico.
Mudando a cor de uma coluna
As células de uma coluna são geralmente renderizadas por um único gtk.CellRenderer. Podemos definir a cor das células desenhadas por esse renderizador associando uma cor à propriedade "cell-background". A cor é representada por uma string. Para associar a cor, basta chamar o método set_property() como abaixo:
A pequena aplicação de teste abaixo demonstra como fazer isso. Ela cria um gtk.TreeView que mostra um orçamento doméstico. Há duas colunas: a primeira descreve a despesa ou receita; a segunda mostra o valor da movimentação.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # file: color-column.py
4 import gtk
5
6 def get_window(view):
7 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
8 window.add(view)
9 window.show_all()
10
11 def get_store(pairs):
12 store = gtk.ListStore(str, int)
13 for pair in pairs:
14 store.append(pair)
15 return store
16
17 def get_tree_view(store):
18 view = gtk.TreeView(store)
19 column1 = gtk.TreeViewColumn('Movimentação')
20 column2 = gtk.TreeViewColumn('Valor')
21 view.append_column(column1)
22 view.append_column(column2)
23 renderer1 = gtk.CellRendererText()
24 renderer2 = gtk.CellRendererText()
25 # The secret is here:
26 renderer1.set_property('cell-background', 'yellow')
27 renderer2.set_property('cell-background', 'green')
28 column1.pack_start(renderer1)
29 column2.pack_start(renderer2)
30 column1.add_attribute(renderer1, 'text', 0)
31 column2.add_attribute(renderer2, 'text', 1)
32 # No selection, for allowing bettter observation
33 view.get_selection().set_mode(gtk.SELECTION_NONE)
34 return view
35
36 pairs = [
37 ('Salário', 800),
38 ('Compras do mês', -150),
39 ('Poupança', -300),
40 ('Ônibus', -150)
41 ]
42
43 store = get_store(pairs)
44 view = get_tree_view(store)
45 window = get_window(view)
46 gtk.main()
Note como nas linhas 26 e 27 nós alteramos a propriedade "cell-background" dos renderizadores. O resultado segue abaixo:
Adicionando a cor da célula ao gtk.TreeModel
Nem sempre queremos mudar a cor de toda uma coluna. Podemos querer mudar apenas a cor de algumas células. Uma maneira de fazer isso é adicionar os nomes das cores nas linhas gtk.TreeModel correspondente. Depois, é só associar a propriedade "cell-background" com as colunas correspondentes.
Na aplicação abaixo, por exemplo, as linhas adicionadas ao gtk.TreeModel não possuem mais apenas dois valores, mas quatro. Os dois primeiros valores são os já usados, e os dois últimos são as cores das células.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # filer: color-model.py
4 import gtk
5
6 def get_window(view):
7 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
8 window.add(view)
9 window.show_all()
10
11 def get_store(pairs):
12 store = gtk.ListStore(str, int, str, str)
13 for pair in pairs:
14 store.append(pair)
15 return store
16
17 def get_tree_view(store):
18 view = gtk.TreeView(store)
19 column1 = gtk.TreeViewColumn('Movimentação')
20 column2 = gtk.TreeViewColumn('Valor')
21 view.append_column(column1)
22 view.append_column(column2)
23 renderer1 = gtk.CellRendererText()
24 renderer2 = gtk.CellRendererText()
25 column1.pack_start(renderer1)
26 column2.pack_start(renderer2)
27 column1.add_attribute(renderer1, 'text', 0)
28 column2.add_attribute(renderer2, 'text', 1)
29 # The secret is here:
30 column1.add_attribute(renderer1, 'cell-background', 2)
31 column2.add_attribute(renderer2, 'cell-background', 3)
32 # No selection, for better visualization
33 view.get_selection().set_mode(gtk.SELECTION_NONE)
34 return view
35
36 pairs = [
37 ('Salário', 800, 'blue', 'cyan'),
38 ('Compras do mês', -150, 'green', 'purple'),
39 ('Poupança', -300, 'yellow', 'white'),
40 ('Ônibus', -150, 'red', 'pink')
41 ]
42
43 store = get_store(pairs)
44 view = get_tree_view(store)
45 window = get_window(view)
46 gtk.main()
Observe as linhas 30 e 31. Nelas, "informamos" as colunas que as cores das células numa determinada linha estão, respectivamente, no terceiro e no quarto valor da linha no gtk.TreeModel. Não é muito diferente do que fazemos com os textos. Notoriamente, você pode comparar as linhas 27 e 29 com as linhas 30 e 31: note como só mudamos a propriedade a ser inicializada e a posição na tupla de onde o dado será tirado. O resultado é...
Mudando a cor de células com uma função de atribuição de dados de células
Mudar a cor de células como fizemos acima pode ser trabalhoso: temos de definir que cor usar e explicitamente adicioná-la ao gtk.TreeModel. Uma maneira mais flexível (embora um pouco mais complexa) de mudar as propriedades de um gtk.CellRenderer para uma célula específica é utilizar o método gtk.TreeViewColumn.set_cell_data_func().
gtk.TreeViewColumn.set_cell_data_func() espera como parâmetro um gtk.CellRenderer, uma função de atribuição de dados de células cuja assinatura descrevemos abaixo e, opcionalmente, algum dado a ser passado para a função. A função de atribuição de dados de células espera cinco argumentos: um objeto gtk.TreeViewColumn, um objeto gtk.CellRenderer, um gtk.TreeModel e um gtk.TreeIter. Naturalmente, o gtk.TreeViewColumn será aquele com o qual invocamos o método gtk.TreeViewColumn.set_cell_data_func(); o gtk.CellRenderer será aquele passado por argumento para o método acima; o gtk.TreeModel será o modelo em uso e gtk.TreeIter apontará para a linha corrente nesse modelo.
Ufa! Agora complicou, né? Mas nada que um exemplo não resolva.
Agora, vamos fazer com que as linhas em que haja débitos fiquem em rosa e vermelho, e as linhas em que haja créditos fiquem em tons de azul. A nova aplicação segue abaixo. Nela, definimos duas funções novas: set_first_column_color() e set_second_column_color(). Depois, definimos essas funções como as funções de atribuição de dados de células.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # file: color-func.py
4 import gtk
5
6 def set_first_column_color(column, renderer, model, iter):
7 value = model.get_value(iter, 1)
8 if value < 0:
9 renderer.set_property('cell-background', 'pink')
10 else:
11 renderer.set_property('cell-background', 'cyan')
12
13 def set_second_column_color(column, renderer, model, iter):
14 value = model.get_value(iter, 1)
15 if value < 0:
16 renderer.set_property('cell-background', 'red')
17 else:
18 renderer.set_property('cell-background', 'blue')
19
20 def get_window(view):
21 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
22 window.add(view)
23 window.show_all()
24
25 def get_store(pairs):
26 store = gtk.ListStore(str, int)
27 for pair in pairs:
28 store.append(pair)
29 return store
30
31 def get_tree_view(store):
32 view = gtk.TreeView(store)
33 column1 = gtk.TreeViewColumn('Movimentação')
34 column2 = gtk.TreeViewColumn('Valor')
35 view.append_column(column1)
36 view.append_column(column2)
37 renderer1 = gtk.CellRendererText()
38 renderer2 = gtk.CellRendererText()
39 column1.pack_start(renderer1)
40 column2.pack_start(renderer2)
41 column1.add_attribute(renderer1, 'text', 0)
42 column2.add_attribute(renderer2, 'text', 1)
43 # The secret is here:
44 column1.set_cell_data_func(renderer1, set_first_column_color)
45 column2.set_cell_data_func(renderer2, set_second_column_color)
46 # No selection, for better visualization
47 view.get_selection().set_mode(gtk.SELECTION_NONE)
48 return view
49
50 pairs = [
51 ('Salário', 800),
52 ('Compras do mês', -150),
53 ('Poupança', -300),
54 ('Ônibus', -150)
55 ]
56
57 store = get_store(pairs)
58 view = get_tree_view(store)
59 window = get_window(view)
60 gtk.main()
A primeira função, que definirá as cores das células da primeira coluna, atribui a cor rosa às células que ficam em linhas cuja movimentação tenha sido negativa; caso contrário, atribui a cor ciano. Já a segunda função atribui a cor vermelha à célula da segunda coluna, se a linha corresponder a um débito; caso contrário, atribui a cor azul. Quando as colunas vão desenhar uma célula, essa função é invocada antes e, nesse momento, muda as propriedades dos renderizadores.
No final, temos algo como:
O método gtk.TreeViewColumn.set_cell_data_func() muito poderoso, embora um pouco sofisticado. Com um pouco de experiência, pode se fazer coisas impressioantes com ele.
Utilizando cores mais variadas
Durante todo esse artigo, nós atribuímos cores às células através da propriedade "cell-background". Essa propriedade espera strings com o nome das cores. Muitas vezes, porém, não queremos nos limitar a um conjunto restrito de cores. Por exemplo, no nosso último exemplo, as cores da segunda coluna ficaram fortes demais, dificultando a leitura.
Nesses casos, ao invés de utilizarmos a propriedade "cell-background", podemos utilizar a propriedade "cell-background-gdk". Essa propriedade não espera uma string; no lugar, ela aceita objetos gtk.gdk.Color. Esses objetos representam várias cores, misturando azul, verde e vermelho. Desse modo, podemos criar nossas cores customizadas.
O código abaixo é uma reescrita do nosso primeiro exemplo. Nele, nós criamos duas cores customizadas para as colunas (tons bem leves de azul e vermelho). Depois, atribuímos essas cores às propriedades "cell-background-gdk" das respectivas colunas. Note como precisamos importar o módulo gtk.gdk.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # file: color-gdk.py
4 import gtk
5 # Now, it is necessary to import gtk.gdk
6 import gtk.gdk
7
8 def get_window(view):
9 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
10 window.add(view)
11 window.show_all()
12
13 def get_store(pairs):
14 store = gtk.ListStore(str, int)
15 for pair in pairs:
16 store.append(pair)
17 return store
18
19 def get_tree_view(store):
20 view = gtk.TreeView(store)
21 column1 = gtk.TreeViewColumn('Movimentação')
22 column2 = gtk.TreeViewColumn('Valor')
23 view.append_column(column1)
24 view.append_column(column2)
25 renderer1 = gtk.CellRendererText()
26 renderer2 = gtk.CellRendererText()
27 # The secret is here:
28 # We are using the hexadecimal notation. Naturally you can use
29 # decimal notation.
30 color1 = gtk.gdk.Color(red=0xF000, green=0xF000, blue=0xFFFF)
31 color2 = gtk.gdk.Color(red=0xFFFF, green=0xF000, blue=0xF000)
32 renderer1.set_property('cell-background-gdk', color1)
33 renderer2.set_property('cell-background-gdk', color2)
34 column1.pack_start(renderer1)
35 column2.pack_start(renderer2)
36 column1.add_attribute(renderer1, 'text', 0)
37 column2.add_attribute(renderer2, 'text', 1)
38 # No selection, for allowing bettter observation
39 view.get_selection().set_mode(gtk.SELECTION_NONE)
40 return view
41
42 pairs = [
43 ('Salário', 800),
44 ('Compras do mês', -150),
45 ('Poupança', -300),
46 ('Ônibus', -150)
47 ]
48
49 store = get_store(pairs)
50 view = get_tree_view(store)
51 window = get_window(view)
52 gtk.main()
Esse código gerou a janela abaixo:
Exercício
Utilizando as cores abaixo
reescrevemos o programa color-func.py de modo a ficar com a aparência abaixo:
Tente você mesmo reescrever o programa, usando essas cores.
Conclusão
gtk.TreeView e suas classes relacionadas foram um sistema complicado, quase uma biblioteca a parte dentro de PyGTK. Entretanto, essa complexidade resulta em poder. As "técnicas" (se é que merecem esse nome pomposo...) que apresentamos aqui foram para usar o poder dessas classes para mudar a cor de fundo das células, mas podem ser usadas para quaisquer propriedades das células, como cor de texto, alinhamento, tamanho... Entenda o que acontece aqui, e poderá aproveitar mais do poder de customizar a aparência de gtk.TreeView.