Of course! Let's dive deep into using Gtk.TreeView in Python. This is one of the most powerful and commonly used widgets in GTK for displaying lists and tables of data.

A Gtk.TreeView doesn't hold the data itself. Instead, it acts as a view for a data model. This separation is a core concept in GTK and is what makes TreeView so flexible.
The workflow is always:
- Create a Model: Choose the right data model to hold your information.
- Create a
TreeView: Instantiate the widget. - Create
TreeViewColumns: Define how the data from the model is displayed in the view. - Pack the Columns into the
TreeView: Connect the visual columns to the data model's columns. - Populate the Model: Add your actual data to the model.
- Attach the Model to the
TreeView: Link the view to its data source.
Let's break this down with clear examples.
The Core Components
a) The Model (Gtk.TreeModel)
The model is the data source. It's an abstract interface, and GTK provides several concrete implementations.

Gtk.ListStore: The simplest model. It's a one-dimensional list of rows. Each row can contain columns of different types (e.g., a string, an integer, a boolean). This is perfect for simple lists.Gtk.TreeStore: A more complex model that can handle a hierarchy. Rows can have child rows, making it ideal for things like file trees or expandable/collapsible lists.Gtk.TreeModelFilter: A "proxy" model that filters another model, showing only a subset of its data.Gtk.TreeModelSort: A "proxy" model that sorts another model.
For most beginners, Gtk.ListStore is the best place to start.
b) The View (Gtk.TreeView)
This is the widget you see on the screen. It displays the data from the model. It knows nothing about the data itself, only how to render what the model gives it.
c) The Columns (Gtk.TreeViewColumn)
These are the visual columns in the TreeView. Each TreeViewColumn contains:
- A title (e.g., "Name", "Age").
- A renderer (an object that knows how to draw a specific type of data, like text or an image).
- A mapping that tells the renderer which column in the data model to get its data from.
d) The Renderers (Gtk.CellRenderer)
Renderers are responsible for drawing the actual data. Common ones include:

Gtk.CellRendererText: For displaying text.Gtk.CellRendererPixbuf: For displaying images.Gtk.CellRendererToggle: For displaying checkboxes.Gtk.CellRendererProgress: For displaying a progress bar.
You can have multiple renderers in a single TreeViewColumn. For example, you could have a column with an image renderer on the left and a text renderer on the right.
Example 1: A Simple List with Gtk.ListStore
This is the "Hello, World!" of TreeView. We'll create a list of names.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# 1. Create the ListStore (the data model)
# It will hold strings. We have one column.
liststore = Gtk.ListStore(str)
# 2. Populate the model with some data
names = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
for name in names:
liststore.append([name])
# 3. Create the TreeView (the visual widget)
treeview = Gtk.TreeView(model=liststore)
# 4. Create a TreeViewColumn to display the data
# The column will have a title and will use a text renderer.
text_column = Gtk.TreeViewColumn(title="Names")
# 5. Create a CellRenderer to render the text
cell_renderer = Gtk.CellRendererText()
# 6. Pack the renderer into the column.
# The 'expand=True' argument makes the column take up any extra space.
text_column.pack_start(cell_renderer, True)
# 7. Add an attribute mapping.
# This tells the renderer: "To get the text to display, use the first
# column (index 0) of the data model."
text_column.add_attribute(cell_renderer, "text", 0)
# 8. Append the column to the TreeView
treeview.append_column(text_column)
# 9. Create a window and add the TreeView to it
window = Gtk.Window(title="Simple TreeView Example")
window.set_default_size(300, 200)
window.connect("destroy", Gtk.main_quit)
# Add a scrolled window in case the list is long
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(treeview)
window.add(scrolled_window)
window.show_all()
Gtk.main()
To run this: Save it as simple_list.py and run python simple_list.py.
Example 2: A Table with Multiple Columns and Data Types
Now, let's make it more interesting. We'll create a table with a name (string), age (integer), and an employed checkbox (boolean).
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# 1. Create the ListStore with multiple column types
# The types are: (string, int, bool)
# GType.STRING, GType.INT, GType.BOOL are also valid
people_store = Gtk.ListStore(str, int, bool)
# 2. Populate the model with data
# The data must match the types defined in the ListStore
people_data = [
("Alice", 30, True),
("Bob", 25, False),
("Charlie", 35, True),
("Diana", 28, True),
("Eve", 42, False)
]
for person in people_data:
people_store.append(person)
# 3. Create the TreeView
treeview = Gtk.TreeView(model=people_store)
# --- Column 1: Name ---
name_col = Gtk.TreeViewColumn(title="Name")
name_renderer = Gtk.CellRendererText()
name_col.pack_start(name_renderer, True)
# Map the "text" attribute of the renderer to model column 0
name_col.add_attribute(name_renderer, "text", 0)
treeview.append_column(name_col)
# --- Column 2: Age ---
age_col = Gtk.TreeViewColumn(title="Age")
age_renderer = Gtk.CellRendererText()
age_col.pack_start(age_renderer, True)
# Map the "text" attribute to model column 1 (the integer)
# We convert the int to a string for display
age_col.add_attribute(age_renderer, "text", 1)
treeview.append_column(age_col)
# --- Column 3: Employed ---
employed_col = Gtk.TreeViewColumn(title="Employed")
employed_renderer = Gtk.CellRendererToggle()
employed_col.pack_start(employed_renderer, True)
# Map the "active" attribute (boolean state) to model column 2
employed_col.add_attribute(employed_renderer, "active", 2)
treeview.append_column(employed_col)
# --- Window Setup ---
window = Gtk.Window(title="Multi-Column TreeView")
window.set_default_size(400, 200)
window.connect("destroy", Gtk.main_quit)
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(treeview)
window.add(scrolled_window)
window.show_all()
Gtk.main()
Key changes in this example:
- The
ListStoreis defined with multiple types:Gtk.ListStore(str, int, bool). - We create three separate
TreeViewColumnobjects, one for each piece of data. - We use
Gtk.CellRendererTogglefor the boolean value. Its key attribute isactive.
Handling User Interaction (Selections)
A TreeView is useless if you can't interact with it. The Gtk.TreeSelection object handles this.
# Add this code inside the window setup section from Example 2,
# right after creating the TreeView.
# Get the selection object from the TreeView
selection = treeview.get_selection()
# Define a callback function for when a row is selected
def on_selection_changed(selection):
# Get the model and the selected path/iter tuple
model, treeiter = selection.get_selected()
if treeiter is not None:
# Get the value from the first column (index 0)
name = model[treeiter][0]
print(f"Selected: {name}")
# Connect the callback to the 'changed' signal of the selection object
selection.connect("changed", on_selection_changed)
# --- The rest of the window setup code...
Now, when you run the code and click on a row, you'll see the selected name printed to your terminal.
Modifying Data (Editable Cells)
You can make cells editable by connecting to the edited signal of a renderer.
# Add this to Example 2, after creating the name_renderer
# Make the "Name" column editable
name_renderer.set_property("editable", True)
# Define a callback for when the text is edited
def on_name_edited(renderer, path, new_text):
# 'path' is the path to the row that was edited (e.g., "0" for the first row)
# 'new_text' is the text the user entered
# Get the iter from the path
treeiter = people_store.get_iter(path)
# Update the model's first column (index 0) with the new text
people_store.set(treeiter, 0, new_text)
# Connect the callback to the 'edited' signal
name_renderer.connect("edited", on_name_edited)
Now, you can click on a name in the "Name" column, it will become an entry field, and you can type a new name. Pressing Enter will save the change.
Summary and Best Practices
- Model-View Separation: Always remember this pattern. It allows you to change the view (e.g., add sorting or filtering) without touching your underlying data.
- Use
ScrolledWindow: If your data might be longer than the window, always wrap yourTreeViewin aGtk.ScrolledWindow. - Choose the Right Model: Start with
ListStore. If you need nested data (like a file system), useTreeStore. - Iterators are Key: The
Gtk.TreeIteris your handle to a specific row in the model. You get it from paths (model.get_iter(path)) or by searching (model.get_iter_first()). - Documentation is Your Friend: The official GTK documentation is excellent. Search for "Gtk.TreeView", "Gtk.ListStore", etc., to find all available properties, methods, and signals.
