Att göra en enkel lista av värden kan vara lite jobbigare än man tänkt sig i GTK eftersom det använder sig av samma widget som visar trädstrukturer. Villa man sedan göra det lite objektorienterat blir det ännu lite krångligare. Här kommer ett litet exempel med kommentarer.
Först tittar vi koden i sin helhet.
Koden
import pygtk
pygtk.require('2.0')
import gtk
class Data(object):
def __init__(self,foo,bar):
self.foo = foo
self.bar = bar
class Lista(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_size_request(400,600)
cell = gtk.CellRendererText()
col1 = gtk.TreeViewColumn('Foo',cell)
col2 = gtk.TreeViewColumn('Bar',cell)
def cell_data_func(column,cell,model,itr,attr):
obj = model.get(itr,0)[0]
cell.set_property('text',str(getattr(obj,attr)))
col1.set_cell_data_func(cell,cell_data_func,'foo')
col2.set_cell_data_func(cell,cell_data_func,'bar')
self.tree = gtk.TreeView()
self.tree.append_column(col1)
self.tree.append_column(col2)
scroll = gtk.ScrolledWindow()
scroll.add(self.tree)
self.add(scroll)
self.connect('delete-event',gtk.main_quit)
#skapa modellen för trädet att visa
model = gtk.ListStore(object)
for i in range(10000):
model.append([Data('foo'+str(i),i)])
ls = Lista()
ls.tree.set_model(model)
ls.show_all()
gtk.main()
gtk.TreeView
Listor i GTK, liksom trädstrukturer, visas av widgeten gtk.TreeView. Det den visar ligger däremot i en modell, de vanligaste är gtk.ListStore och gtk.TreeStore. Vi kommer här använda gtk.ListStore. Modellen är frånskild från vyn, därför måste vi själva specifiera hur varje rad i modellen ska visas i vyn. mer om detta senare.
För att göra det ännu mer kångligare, men mycket mer kraftfullt, så finns det två andra widgets att hålla reda på: gtk.CellRenderer och gtk.TreeViewColumn. gtk.CellRenderer representerar en ruta i listan och det finns flera sorters, bla annat de som visar text och de som visar en bild. gtk.TreeViewColumn representerar en kolumn i listan och håller reda på vilken gtk.CellRenderer som ska visa värdet i just denna kolumnens rader.
Steg för steg
Vi går igenom hela koden och ser vad den gör:
import pygtk
pygtk.require('2.0')
import gtk
Helt vanliga importer, här kräver vi GTK version 2 eller större.
class Data(object):
def __init__(self,foo,bar):
self.foo = foo
self.bar = bar
Vårt data objekt som vill lägga i en lista, en enkel klass med två attribut.
Jag valde att skapa en klass som kapslar in vårt gränssnitt
class Lista(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_size_request(400,600)
Eftersom vi ärver gtk.Window så måste vi köra dess konstruktor. Sedan sätter vi storleken på vårt fönster.
Här kommer vi till den viktiga delen, där vi bygger upp trädet. Vi börjar med kolumnerna:
cell = gtk.CellRendererText()
col1 = gtk.TreeViewColumn('Foo',cell)
col2 = gtk.TreeViewColumn('Bar',cell)
Först skapar vi en gtk.CellRendererText som vi återanvänder i båda kolumnerna, det är helt ok eftersom cellerrenderare ska i normala fall inte behålla något "state" mellan renderingarna. 'Foo' och 'Bar' ovan är namnen på kolumnerna.
För att kunna visa vårt objekt så behöver vi en funktion som mappar objektets attribut mot ett värde i cellen.
def cell_data_func(column,cell,model,itr,attr):
obj = model.get(itr,0)[0]
cell.set_property('text',str(getattr(obj,attr)))
Det har vi inte sett ännu, men modellen kommer bara bestå av en mängd Data objekt, en per rad.
Sedan måste vi bara se till att funktionen används av kolumnerna.
col1.set_cell_data_func(cell,cell_data_func,'foo')
col2.set_cell_data_func(cell,cell_data_func,'bar')
Det sista argumentet skickas visare till cell_data_func och är namnet på det attribut vi vill visa i just denna kolumnen. Om vi inte hade gjort det på detta sättet hade vi vart tvungna att skriva en cell_data_func för varje column.
self.tree = gtk.TreeView()
self.tree.append_column(col1)
self.tree.append_column(col2)
Här skapar vi vår trädwidget och lägger till våra två kolumner.
scroll = gtk.ScrolledWindow()
scroll.add(self.tree)
self.add(scroll)
Eftersom vi vill testa med en stor lista kan vi behöva scrollbars på sidorna, så vi lägger vårt träd i ett scrollat fönster och sedan det i huvudfönstret.
self.connect('delete-event',gtk.main_quit)
Kopplar samman krysset uppe i högra hörnet med att avsluta programmet.
Nu är vårt lilla GUI färdigt, det enda som behövs är en modell.
#skapa modellen för trädet att visa
model = gtk.ListStore(object)
for i in range(10000):
model.append([Data('foo'+str(i),i)])
Eftersom det är en lista vi vill visa använder vi gtk.ListStore.
Sedan är det bara att skapa en instans av vårt gui, ge den modellen och starta allt
ls = Lista()
ls.tree.set_model(model)
ls.show_all()
gtk.main()
Det kan tyckas ganska mycket kod för en enkel lista, och det är det också, men gtk.TreeView belönar oss istället med kraftfullhet. Just på grund av uppdelning i flera klasser, celler,träd,modeller och kolumner så kan man göra otroligt mycket med en lista. Samma modell kan med fördel visas i flera olika vyer, vilket i större projekt kan spara mycket huvudvärk.