pickarooney
pickarooney

Reputation: 415

Python (GTK) : Can someone explain the difference between TreeStore, Listmodel and all the rest?

I'm trying to get my head around the following concepts but all the documentation I've read bundles the whole lot in together without explaining what any of them really are and as a result I don't know how to use any of them properly. If someone could give some kind of real-world analogy that would help hugely.

TreeView ListView (is this even a thing?) TreeStore ListStore TreeModel TreeIter

My ultimate goal is to read a set of results from a database and display them on a widget as clickable items. I've got the lookup and retrieval parts down but passing the results back, displaying them and getting them to update is proving a lot more tricky.

update: The following is meant to read the results from a postgreSQL DB and put it into a 'container' from whence I can assign the results to an output dialog:

result = self.lookup_player(search) # this returns a result of cur.fetchall
    print result # just to make sure it returns the right things
    if len(result) > 0:  # make sure there are results
       for i in range(0, len(result)): # i used treeiter to see what it did
        treeiter=store.append([result[i][0],result[i][1],str(result[i][4])])
        print result[i][0],result[i][1],result[i][2],result[i][3],result[i][4],result[i][5],result[i][6],result[i][7],result[i][8],result[i][9],result[i][10]
    else:
       print "No players found"

I've used a ListStore in the above as it seemed like the best fit. But maybe I should have used a Treestore, or a simple list, or an array... It's easy to see what a string is, or an integer, a float, but what do these list/tree/model/stores actually look like or do?

I had to give up coding in C years ago as I just could not get my head around what a polymorphic linked list was and I desperately want to avoid the same fate with python this time around.

Upvotes: 1

Views: 987

Answers (1)

andlabs
andlabs

Reputation: 11588

You have the right idea with your GtkListStore code above: it's a data store that works very similarly to an SQL table. In fact, you'll find tha the GtkTreeView infrastructure works like SQL tables. Your Gtk.ListStore() constructor call maps directly to CREATE TABLE and your append() call maps directly to INSERT ROW.

The important thing to note is that the columns in your GtkListStore are numbered from left to right, starting at 0, rather than named. This will be important in a bit.

The difference between GtkListStore and GtkTreeStore is that the latter allows you to have rows as children of other rows, like a folder tree in a file browser would. The children rows have to have the same column format as the parent rows.

Both GtkListStore and GtkTreeStore are implementations of GtkTreeModel, which is an interface. From what I've been told, Python doesn't have an immediate concept like interfaces, so just imagine an interface as an abstract base class where there are no default implementations and every function must be defined. GtkTreeModel specifies methods which allows a GtkTreeView to display the data on screen.

So the only question now is how do you connect a GtkTreeView to a GtkTreeModel/GtkListStore/GtkTreeStore?

As you remember from SQL, each column of a table has a specific data type. With GtkTreView, all cells in a column have the same cell renderer. The cell renderer draws text, pictures, checkboxes, etc., using GObject properties. You've likely used properties already: text is a property on GtkLabels, active is a property on GtkCheckButtons, etc. Cell renderers have properties that not only specify what data to draw, but also how to draw it.

When you supply the "attributes" (in the function name) to a GtkTreeViewColumn (the representation of a single column in a GtkTreeView), you give the function you call to do the supplying two things: the cell renderer itself and a list of attribute-column number pairs.

For instance, let's say you want column 0 of the table model to provide the text for the first column. Here's how you would create the column:

renderer = Gtk.CellRendererText()            # create a text cell renderer
column = Gtk.TreeViewColumn("Column")        # create the column
column.pack_start(renderer, True)            # load the renderer...
column.add_attribute(renderer, "text", 0)    # ...and tell it to get its text from the first column of the model

Now all that's left is to add the columns to the GtkTreeView and to set your GtkListStore as the GtkTreeView's model (with set_model()). If all goes well, you should see your data in the GtkTreeView.


GtkTreeView doesn't provide its own scrollbars. Be sure to put your GtkTreeView in a GtkScrolledWindow to get them.

There is a GtkListBox, but it's entirely unrelated to this.

Hopefully this helps clear things up! If not, feel free to point out what you don't understand and I'll amend this answer accordingly.


Update: In response to your comment asking why GtkTreeView works like this, rather than managing all the data itself and just having functions like add_row() and set_cell_value(). There are a few advantages to this design:

  • It makes GtkTreeView's own code simpler and more extensible in the future.
  • It allows people with special needs to implement their own GtkTreeModel to use as the data store. For example, someone writing a sufficiently advanced or memory-hungry program can create a GtkTreeModel that communicates directly with the SQL database, avoiding the need to copy data everywhere.
  • It allows the same data store to be used by multiple instances of GtkTreeView.
  • It allows the same data store to be used by other widgets. GtkIconView is another widget that uses GtkTreeModel to store its data (and it also uses cell renderers to render the data).

Upvotes: 5

Related Questions