Debian + NSLU2

Debian installer fungerar numera på 'the slug', eller rättare sagt linksys NSLU2. En armbaserad liten dator tänkt för NAS. Linux har man länge kunnat få in, dock inte utan viss handpåläggning. Nu kommer allt bli mkt enklare.

tor 16 november 2006

Opensourcemobil

En nästan helt öppen mobiltelefon/pda, som använder apt-get som pakethanterar. Vem vill inte ha en sådan?

ons 8 november 2006

Kan du motså frestelsen?

Trotsa invanda gränssnittsregler och navigera utan att använda musknappen. Testa själv på www.dontclick.it.

ons 1 november 2006

Oracle kopierar RedHat

Oracle ger sig in i distrubitionsbranschen!

må 30 oktober 2006

PyGTK: Objekt i en lista

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.