PyGobject(五十六)布局容器之TreeView(上)

  • GtkTreeView
    • 继承关系
    • Methods
    • Virtual Methods
    • Properties
    • Signals
    • 模型
      • GtkTreeModel
        • Methods
        • Virtual Methods
        • Signals
      • GtkListStore
        • Methods
      • GtkTreeStore
        • Methods
      • GtkTreePath
        • Methods
      • GtkTreeViewColumn
        • Methods
    • 视图
    • 排序
    • 过滤
    • 例子
      • 一ListStore
      • 二TreeStore
      • 三Treeview Filter
      • 四自定义TreeModelFile List
      • 五自定义TreeModelFile Tree

Gtk.TreeView

Gtk.TreeView显示数据的能力比较强大。通常与Gtk.ListStore或Gtk.TreeStore连在一起使用。提供很多显示和操纵数据的方法:

  • 当有数据添加,删除或编辑时,界面自动更新
  • 支持拖放
  • 数据排序
  • 支持嵌入部件如复选框,进度条等。
  • 可重排序和可调整大小的列
  • 数据过滤

继承关系

Gtk.TreeView是Gtk.Container的直接子类
PyGobject(五十六)布局容器之TreeView(上)_第1张图片

Methods

方法修饰词 方法名及参数
static new ()
static new_with_model (model)
append_column (column)
collapse_all ()
collapse_row (path)
columns_autosize ()
convert_bin_window_to_tree_coords (bx, by)
convert_bin_window_to_widget_coords (bx, by)
convert_tree_to_bin_window_coords (tx, ty)
convert_tree_to_widget_coords (tx, ty)
convert_widget_to_bin_window_coords (wx, wy)
convert_widget_to_tree_coords (wx, wy)
create_row_drag_icon (path)
enable_model_drag_dest (targets, actions)
enable_model_drag_source (start_button_mask, targets, actions)
expand_all ()
expand_row (path, open_all)
expand_to_path (path)
get_activate_on_single_click ()
get_background_area (path, column)
get_bin_window ()
get_cell_area (path, column)
get_column (n)
get_columns ()
get_cursor ()
get_dest_row_at_pos (drag_x, drag_y)
get_drag_dest_row ()
get_enable_search ()
get_enable_tree_lines ()
get_expander_column ()
get_fixed_height_mode ()
get_grid_lines ()
get_hadjustment ()
get_headers_clickable ()
get_headers_visible ()
get_hover_expand ()
get_hover_selection ()
get_level_indentation ()
get_model ()
get_n_columns ()
get_path_at_pos (x, y)
get_reorderable ()
get_rubber_banding ()
get_rules_hint ()
get_search_column ()
get_search_entry ()
get_selection ()
get_show_expanders ()
get_tooltip_column ()
get_tooltip_context (x, y, keyboard_tip)
get_vadjustment ()
get_visible_range ()
get_visible_rect ()
insert_column (column, position)
insert_column_with_attributes (position, title, cell, **kwargs)
insert_column_with_data_func (position, title, cell, func, *data)
is_blank_at_pos (x, y)
is_rubber_banding_active ()
map_expanded_rows (func, *data)
move_column_after (column, base_column)
remove_column (column)
row_activated (path, column)
row_expanded (path)
scroll_to_cell (path, column, use_align, row_align, col_align)
scroll_to_point (tree_x, tree_y)
set_activate_on_single_click (single)
set_column_drag_function (func, *user_data)
set_cursor (path, focus_column, start_editing)
set_cursor_on_cell (path, focus_column, focus_cell, start_editing)
set_destroy_count_func (func, *data)
set_drag_dest_row (path, pos)
set_enable_search (enable_search)
set_enable_tree_lines (enabled)
set_expander_column (column)
set_fixed_height_mode (enable)
set_grid_lines (grid_lines)
set_hadjustment (adjustment)
set_headers_clickable (setting)
set_headers_visible (headers_visible)
set_hover_expand (expand)
set_hover_selection (hover)
set_level_indentation (indentation)
set_model (model)
set_reorderable (reorderable)
set_row_separator_func (func, *data)
set_rubber_banding (enable)
set_rules_hint (setting)
set_search_column (column)
set_search_entry (entry)
set_search_equal_func (search_equal_func, *search_user_data)
set_search_position_func (func, *data)
set_show_expanders (enabled)
set_tooltip_cell (tooltip, path, column, cell)
set_tooltip_column (column)
set_tooltip_row (tooltip, path)
set_vadjustment (adjustment)
unset_rows_drag_dest ()
unset_rows_drag_source ()

Virtual Methods

do_columns_changed ()
do_cursor_changed ()
do_expand_collapse_cursor_row (logical, expand, open_all)
do_move_cursor (step, count)
do_row_activated (path, column)
do_row_collapsed (iter, path)
do_row_expanded (iter, path)
do_select_all ()
do_select_cursor_parent ()
do_select_cursor_row (start_editing)
do_start_interactive_search ()
do_test_collapse_row (iter, path)
do_test_expand_row (iter, path)
do_toggle_cursor_row ()
do_unselect_all ()

Properties

Name Type Flags Short Description
activate-on-single-click bool r/w/en Activate row on a single click
enable-grid-lines Gtk.TreeViewGridLines r/w/en Whether grid lines should be drawn in the tree view
enable-search bool r/w/en View allows user to search through columns interactively
enable-tree-lines bool r/w/en Whether tree lines should be drawn in the tree view
expander-column Gtk.TreeViewColumn r/w Set the column for the expander column
fixed-height-mode bool r/w/en Speeds up Gtk.TreeView by assuming that all rows have the same height
headers-clickable bool r/w/en Column headers respond to click events
headers-visible bool r/w/en Show the column header buttons
hover-expand bool r/w/en Whether rows should be expanded/collapsed when the pointer moves over them
hover-selection bool r/w/en Whether the selection should follow the pointer
level-indentation int r/w/en Extra indentation for each level
model Gtk.TreeModel r/w The model for the tree view
reorderable bool r/w/en View is reorderable
rubber-banding bool r/w/en Whether to enable selection of multiple items by dragging the mouse pointer
rules-hint bool d/r/w/en Set a hint to the theme engine to draw rows in alternating colors deprecated
search-column int r/w/en Model column to search through during interactive search
show-expanders bool r/w/en View has expanders
tooltip-column int r/w/en The column in the model containing the tooltip texts for the rows

Signals

Name Short Description
columns-changed The number of columns of the treeview has changed.
cursor-changed The position of the cursor (focused cell) has changed.
expand-collapse-cursor-row
move-cursor The Gtk.TreeView ::move-cursor signal is a keybinding signal which gets emitted when the user presses one of the cursor keys.
row-activated The “row-activated” signal is emitted when the method Gtk.TreeView.row_activated() is called, when the user double clicks a treeview row with the “activate-on-single-click” property set to False, or when the user single clicks a row when the “activate-on-single-click” property set to True.
row-collapsed The given row has been collapsed (child nodes are hidden).
row-expanded The given row has been expanded (child nodes are shown).
select-all
select-cursor-parent
select-cursor-row
start-interactive-search
test-collapse-row The given row is about to be collapsed (hide its children nodes).
test-expand-row The given row is about to be expanded (show its children nodes).
toggle-cursor-row
unselect-all

模型

每个Gtk.TreeView具有相关联的Gtk.TreeModel,其中包含TreeView显示的数据。每个Gtk.TreeModel可以由一个或以上的Gtk.TreeView使用。

虽然理论上可以实现自己的模型,通常使用Gtk.ListStore或Gtk.TreeStore模型类。 Gtk.ListStore包含数据的简单行,每行没有孩子,而Gtk.TreeStore包含的数据行,每行可有子行。

当构建一个模型,你必须为模型认为每列指定数据类型。

store = Gtk.ListStore(str, str, float)

创建了包含三列的Gtk.ListStore模型,两个string 列,一个float列
使用append方法往模型里面添加数据

treeiter = store.append(["The Art of Computer Programming",                          "Donald E. Knuth", 25.46])

方法返回一个Gtk.TreeIter实例,指向新插入一行的位置。可以使用Gtk.TreeModel.get_iter(path)方法获取Gtk.TreeIter实例。
一旦数据插入,可以通过 TreeIter和列索引获取或者修改数据

print(store[treeiter][2]) # Prints value of third column 
store[treeiter][2] = 42.15

与Python的list一样,你可以使用len()来获得每行里面的数据个数和使用切片来获取或设置值

# Print number of rows 
print(len(store)) 
# Print all but first column 
print(store[treeiter][1:]) 
# Print last column 
print(store[treeiter][-1]) 
# Set first two columns 
store[treeiter][:2] = ["Donald Ervin Knuth", 41.99]

获取所有行内容

for row in store:
     # Print values of all columns
     print(row[:])

请记住,如果你使用Gtk.TreeStore,上面的代码将只迭代顶层的行,但没有节点的孩子。遍历所有的行和它的孩子,可使用print_tree_store方法

def print_tree_store(store):
    rootiter = store.get_iter_first()
    print_rows(store, rootiter, "")


def print_rows(store, treeiter, indent):
    while treeiter != None:
        print(indent + str(store[treeiter][:]))
        if store.iter_has_child(treeiter):
            childiter = store.iter_children(treeiter)
            print_rows(store, childiter, indent + "\t")
        treeiter = store.iter_next(treeiter)

获取某行内容,使用TreePath

# Get path pointing to 6th row in list store
path = Gtk.TreePath(5)
treeiter = liststore.get_iter(path)
# Get value at 2nd column
value = liststore.get_value(treeiter, 1)

获取某行某列内容

# Get path pointing to 5th child of 3rd row in tree store
path = Gtk.TreePath([2, 4])
treeiter = treestore.get_iter(path)
# Get value at 2nd column
value = treestore.get_value(treeiter, 1)

Gtk.TreePath的实例可以像列表被访问, len(treepath)返回项目的深度。
treepath[i]返回第i层孩子的索引

Gtk.TreeModel

PyGobject(五十六)布局容器之TreeView(上)_第2张图片

Methods

方法修饰词 方法名及参数
filter_new (root)
foreach (func, *user_data)
get (treeiter, *columns)
get_column_type (index_)
get_flags ()
get_iter (path)
get_iter_first ()
get_iter_from_string (path_string)
get_n_columns ()
get_path (iter)
get_string_from_iter (iter)
get_value (iter, column)
iter_children (parent)
iter_has_child (iter)
iter_n_children (iter)
iter_next (iter)
iter_nth_child (parent, n)
iter_parent (child)
iter_previous (iter)
ref_node (iter)
row_changed (path, iter)
row_deleted (path)
row_has_child_toggled (path, iter)
row_inserted (path, iter)
rows_reordered (path, iter, new_order)
set_row (treeiter, row)
sort_new_with_model ()
unref_node (iter)

Virtual Methods

do_get_column_type (index_)
do_get_flags ()
do_get_iter (path)
do_get_n_columns ()
do_get_path (iter)
do_get_value (iter, column)
do_iter_children (parent)
do_iter_has_child (iter)
do_iter_n_children (iter)
do_iter_next (iter)
do_iter_nth_child (parent, n)
do_iter_parent (child)
do_iter_previous (iter)
do_ref_node (iter)
do_row_changed (path, iter)
do_row_deleted (path)
do_row_has_child_toggled (path, iter)
do_row_inserted (path, iter)
do_unref_node (iter)

Signals

Name Short Description
row-changed This signal is emitted when a row in the model has changed.
row-deleted This signal is emitted when a row has been deleted.
row-has-child-toggled This signal is emitted when a row has gotten the first child row or lost its last child row.
row-inserted This signal is emitted when a new row has been inserted in the model.
rows-reordered This signal is emitted when the children of a node in the Gtk.TreeModel have been reordered.

Gtk.ListStore

PyGobject(五十六)布局容器之TreeView(上)_第3张图片

Methods

方法修饰词 方法名及参数
static new (types)
append (row=None)
clear ()
insert (position, row=None)
insert_after (sibling, row=None)
insert_before (sibling, row=None)
insert_with_valuesv (position, columns, values)
iter_is_valid (iter)
move_after (iter, position)
move_before (iter, position)
prepend (row=None)
remove (iter)
reorder (new_order)
set (iter, columns, values)
set_column_types (types)
set_value (iter, column, value)
swap (a, b)

Gtk.TreeStore

PyGobject(五十六)布局容器之TreeView(上)_第4张图片

Methods

方法修饰词 方法名及参数
static new (types)
append (parent, row=None)
clear ()
insert (parent, position, row=None)
insert_after (parent, sibling)
insert_before (parent, sibling, row=None)
insert_with_values (parent, position, columns, values)
is_ancestor (iter, descendant)
iter_depth (iter)
iter_is_valid (iter)
move_after (iter, position)
move_before (iter, position)
prepend (parent, row=None)
remove (iter)
set (iter, columns, values)
set_column_types (types)
set_value (iter, column, value)
swap (a, b)

Gtk.TreePath

Methods

方法修饰词 方法名及参数
static new ()
static new_first ()
static new_from_indices (indices)
static new_from_string (path)
append_index (index_)
compare (b)
copy ()
down ()
free ()
get_depth ()
get_indices ()
is_ancestor (descendant)
is_descendant (ancestor)
next ()
prepend_index (index_)
prev ()
to_string ()
up ()

Gtk.TreeViewColumn

Methods

方法修饰词 方法名及参数
static new ()
static new_with_area (area)
add_attribute (cell_renderer, attribute, column)
cell_get_position (cell_renderer)
cell_get_size (cell_area)
cell_is_visible ()
cell_set_cell_data (tree_model, iter, is_expander, is_expanded)
clear ()
clear_attributes (cell_renderer)
clicked ()
focus_cell (cell)
get_alignment ()
get_button ()
get_clickable ()
get_expand ()
get_fixed_width ()
get_max_width ()
get_min_width ()
get_reorderable ()
get_resizable ()
get_sizing ()
get_sort_column_id ()
get_sort_indicator ()
get_sort_order ()
get_spacing ()
get_title ()
get_tree_view ()
get_visible ()
get_widget ()
get_width ()
get_x_offset ()
pack_end (cell, expand)
pack_start (cell, expand)
queue_resize ()
set_alignment (xalign)
set_attributes (cell_renderer, **attributes)
set_cell_data_func (cell_renderer, func, *func_data)
set_clickable (clickable)
set_expand (expand)
set_fixed_width (fixed_width)
set_max_width (max_width)
set_min_width (min_width)
set_reorderable (reorderable)
set_resizable (resizable)
set_sizing (type)
set_sort_column_id (sort_column_id)
set_sort_indicator (setting)
set_sort_order (order)
set_spacing (spacing)
set_title (title)
set_visible (visible)
set_widget (widget)

视图

Treeview和TreeModel绑定,在Treeview的构造方法中指定模型

tree = Gtk.TreeView(store)

或者使用Gtk.TreeView.set_model()方法

tree.set_model(store)

一旦Gtk.TreeView小部件有一个模型,它需要知道如何显示模型。为此,它使用数据列和单元格渲染器来显示数据。

单元渲染器用于绘制树模型中的数据。有许多Gtk.CellRenderer类用来展示不同类型的数据,例如Gtk.CellRendererText,Gtk.CellRendererPixbuf和Gtk.CellRendererToggle单元格渲染器。此外,它比较容易自定义。

一个Gtk.TreeViewColumn是Gtk.TreeView中用来组织列的对象。它需要知道列的名称,使用什么类型的单元格渲染器,从模型行中的哪一列检索数据。

renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Title", renderer, text=0)
tree.append_column(column)

一列显示多个数据

column = Gtk.TreeViewColumn("Title and Author")

title = Gtk.CellRendererText()
author = Gtk.CellRendererText()

column.pack_start(title, True)
column.pack_start(author, True)

column.add_attribute(title, "text", 0)
column.add_attribute(author, "text", 1)

tree.append_column(column)

选择

select = tree.get_selection()
select.connect("changed", on_tree_selection_changed)


def on_tree_selection_changed(selection):
    model, treeiter = selection.get_selected()
    if treeiter != None:
        print("You selected", model[treeiter][0])

可以设置多行选择模式

Gtk.TreeSelection.set_mode(Gtk.SelectionMode.MULTIPLE)

多行选择模式下Gtk.TreeSelection.get_selected()不起作用,使用Gtk.TreeSelection.get_selected_rows()方法代替

排序

点击列头排序

model = Gtk.ListStore(str)
model.append(["Benjamin"])
model.append(["Charles"])
model.append(["alfred"])
model.append(["Alfred"])
model.append(["David"])
model.append(["charles"])
model.append(["david"])
model.append(["benjamin"])

treeView = Gtk.TreeView(model)

cellRenderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Title", renderer, text=0)#text为model中的第1列数据
column.set_sort_column_id(0)

自定义排序方法

def compare(model, row1, row2, user_data):
    sort_column, _ = model.get_sort_column_id()
    value1 = model.get_value(row1, sort_column)
    value2 = model.get_value(row2, sort_column)
    if value1 < value2:
        return -1
    elif value1 == value2:
        return 0
    else:
        return 1

设置排序方法。Gtk.TreeSortable.set_sort_func().

model.set_sort_func(0, compare, None)

过滤

过滤需要用到Gtk.TreeModelFilter类
先定义一个实例

filter = model.filter_new()

设置过滤方法

filter.set_visible_func(filter_func, data=None)

例子

一.ListStore

PyGobject(五十六)布局容器之TreeView(上)_第5张图片
代码:

#!/usr/bin/env python3
# section 075
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
#
# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri 
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
# USA

TITLE = "List Store"
DESCRIPTION = """
The GtkListStore is used to store data in list form, to be used later on by a
GtkTreeView to display it. This demo builds a simple GtkListStore and displays
it. See the Stock Browser demo for a more advanced example.
"""
import gi

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject, GLib


class Bug:
    def __init__(self, is_fixed, number, severity, description):
        self.is_fixed = is_fixed
        self.number = number
        self.severity = severity
        self.description = description


# initial data we use to fill in the store
data = [Bug(False, 60482, "Normal", "scrollable notebooks and hidden tabs"),
        Bug(False, 60620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe"),
        Bug(False, 50214, "Major", "Xft support does not clean up correctly"),
        Bug(True, 52877, "Major", "GtkFileSelection needs a refresh method. "),
        Bug(False, 56070, "Normal", "Can't click button after setting in sensitive"),
        Bug(True, 56355, "Normal", "GtkLabel - Not all changes propagate correctly"),
        Bug(False, 50055, "Normal", "Rework width/height computations for TreeView"),
        Bug(False, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work"),
        Bug(False, 55767, "Normal", "Getters for all setters"),
        Bug(False, 56925, "Normal", "Gtkcalender size"),
        Bug(False, 56221, "Normal", "Selectable label needs right-click copy menu"),
        Bug(True, 50939, "Normal", "Add shift clicking to GtkTextView"),
        Bug(False, 6112, "Enhancement", "netscape-like collapsable toolbars"),
        Bug(False, 1, "Normal", "First bug :=)")]


class ListStoreApp:
    (COLUMN_FIXED,
     COLUMN_NUMBER,
     COLUMN_SEVERITY,
     COLUMN_DESCRIPTION,
     COLUMN_PULSE,
     COLUMN_ICON,
     COLUMN_ACTIVE,
     COLUMN_SENSITIVE,
     NUM_COLUMNS) = range(9)

    def __init__(self):
        self.window = Gtk.Window()
        self.window.set_title('Gtk.ListStore Demo')
        self.window.connect('destroy', Gtk.main_quit)

        vbox = Gtk.VBox(spacing=8)
        self.window.add(vbox)

        label = Gtk.Label(
                label='This is the bug list (note: not based on real data, it would be nice to have a nice ODBC interface to bugzilla or so, though).')
        vbox.pack_start(label, False, False, 0)

        sw = Gtk.ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        sw.set_policy(Gtk.PolicyType.NEVER,
                      Gtk.PolicyType.AUTOMATIC)
        vbox.pack_start(sw, True, True, 0)

        self.create_model()
        treeview = Gtk.TreeView(model=self.model)
        treeview.set_rules_hint(True)
        treeview.set_search_column(self.COLUMN_DESCRIPTION)
        sw.add(treeview)

        self.add_columns(treeview)

        self.window.set_default_size(280, 250)
        self.window.show_all()

        self.window.connect('delete-event', self.window_closed)
        self.timeout = GLib.timeout_add(80, self.spinner_timeout)

    def window_closed(self, window, event):
        if self.timeout != 0:
            GLib.source_remove(self.timeout)

    def spinner_timeout(self):
        if self.model is None:
            return False

        iter_ = self.model.get_iter_first()
        pulse = self.model.get(iter_, self.COLUMN_PULSE)[0]
        if pulse == 999999999:
            pulse = 0
        else:
            pulse += 1

        self.model.set_value(iter_, self.COLUMN_PULSE, pulse)
        self.model.set_value(iter_, self.COLUMN_ACTIVE, True)

        return True

    def create_model(self):
        self.model = Gtk.ListStore(bool,
                                   GObject.TYPE_INT,
                                   str,
                                   str,
                                   GObject.TYPE_INT,
                                   str,
                                   bool,
                                   bool)

        for row, bug in enumerate(data):
            if row == 1 or row == 3:
                icon_name = 'battery-caution-charging-symbolic'
            else:
                icon_name = ''
            if row == 3:
                is_sensitive = False
            else:
                is_sensitive = True

            self.model.append([bug.is_fixed,
                               bug.number,
                               bug.severity,
                               bug.description,
                               0,
                               icon_name,
                               False,
                               is_sensitive])

    def add_columns(self, treeview):
        model = treeview.get_model()

        # column for is_fixed toggle
        renderer = Gtk.CellRendererToggle()
        renderer.connect('toggled', self.is_fixed_toggled, model)

        column = Gtk.TreeViewColumn("Fixed?", renderer,
                                    active=self.COLUMN_FIXED)
        column.set_fixed_width(50)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        treeview.append_column(column)

        # column for severities
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Severity", renderer,
                                    text=self.COLUMN_SEVERITY)
        column.set_sort_column_id(self.COLUMN_SEVERITY)
        treeview.append_column(column)

        # column for description
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Description", renderer,
                                    text=self.COLUMN_DESCRIPTION)
        column.set_sort_column_id(self.COLUMN_DESCRIPTION)
        treeview.append_column(column)

        # column for spinner
        renderer = Gtk.CellRendererSpinner()
        column = Gtk.TreeViewColumn("Spinning", renderer,
                                    pulse=self.COLUMN_PULSE,
                                    active=self.COLUMN_ACTIVE)
        column.set_sort_column_id(self.COLUMN_PULSE)
        treeview.append_column(column)

        # column for symbolic icon
        renderer = Gtk.CellRendererPixbuf()
        renderer.props.follow_state = True
        column = Gtk.TreeViewColumn("Symbolic icon", renderer,
                                    icon_name=self.COLUMN_ICON,
                                    sensitive=self.COLUMN_SENSITIVE)
        column.set_sort_column_id(self.COLUMN_ICON)
        treeview.append_column(column)

    def is_fixed_toggled(self, cell, path_str, model):
        # get toggled iter
        iter_ = model.get_iter(path_str)
        is_fixed = model.get_value(iter_, self.COLUMN_FIXED)

        # do something with value
        is_fixed ^= 1

        model.set_value(iter_, self.COLUMN_FIXED, is_fixed)


def main():
    ListStoreApp()
    Gtk.main()


if __name__ == '__main__':
    main()

代码解析

二.TreeStore

PyGobject(五十六)布局容器之TreeView(上)_第6张图片

代码

#!/usr/bin/env python3
# Created by xiaosanyu at 16/6/15
# section 076
TITLE = "Tree Store"
DESCRIPTION = """
The GtkTreeStore is used to store data in tree form, to be
used later on by a GtkTreeView to display it. This demo builds
a simple GtkTreeStore and displays it. If you're new to the
GtkTreeView widgets and associates, look into the GtkListStore
example first.
"""
import gi

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

(
    HOLIDAY_NAME_COLUMN,
    ALEX_COLUMN,
    HAVOC_COLUMN,
    TIM_COLUMN,
    OWEN_COLUMN,
    DAVE_COLUMN,

    VISIBLE_COLUMN,
    WORLD_COLUMN,
) = range(8)

# tree data
january = [
    ["New Years Day", True, True, True, True, False, True],
    ["Presidential Inauguration", False, True, False, True, False, False],
    ["Martin Luther King Jr. day", False, True, False, True, False, False],
]

february = [
    ["Presidents' Day", False, True, False, True, False, False],
    ["Groundhog Day", False, False, False, False, False, False],
    ["Valentine's Day", False, False, False, False, True, True],
]

march = [
    ["National Tree Planting Day", False, False, False, False, False, False],
    ["St Patrick's Day", False, False, False, False, False, True],
]
april = [
    ["April Fools' Day", False, False, False, False, False, True],
    ["Army Day", False, False, False, False, False, False],
    ["Earth Day", False, False, False, False, False, True],
    ["Administrative Professionals' Day", False, False, False, False, False, False],
]

may = [
    ["Nurses' Day", False, False, False, False, False, False],
    ["National Day of Prayer", False, False, False, False, False, False],
    ["Mothers' Day", False, False, False, False, False, True],
    ["Armed Forces Day", False, False, False, False, False, False],
    ["Memorial Day", True, True, True, True, False, True],
]

june = [
    ["June Fathers' Day", False, False, False, False, False, True],
    ["Juneteenth (Liberation of Slaves)", False, False, False, False, False, False],
    ["Flag Day", False, True, False, True, False, False],
]

july = [
    ["Parents' Day", False, False, False, False, False, True],
    ["Independence Day", False, True, False, True, False, False],
]

august = [
    ["Air Force Day", False, False, False, False, False, False],
    ["Coast Guard Day", False, False, False, False, False, False],
    ["Friendship Day", False, False, False, False, False, False],
]

september = [
    ["Grandparents' Day", False, False, False, False, False, True],
    ["Citizenship Day or Constitution Day", False, False, False, False, False, False],
    ["Labor Day", True, True, True, True, False, True],
]

october = [
    ["National Children's Day", False, False, False, False, False, False],
    ["Bosses' Day", False, False, False, False, False, False],
    ["Sweetest Day", False, False, False, False, False, False],
    ["Mother-in-Law's Day", False, False, False, False, False, False],
    ["Navy Day", False, False, False, False, False, False],
    ["Columbus Day", False, True, False, True, False, False],
    ["Halloween", False, False, False, False, False, True],
]

november = [
    ["Marine Corps Day", False, False, False, False, False, False],
    ["Veterans' Day", True, True, True, True, False, True],
    ["Thanksgiving", False, True, False, True, False, False],
]

december = [
    ["Pearl Harbor Remembrance Day", False, False, False, False, False, False],
    ["Christmas", True, True, True, True, False, True],
    ["Kwanzaa", False, False, False, False, False, False],
]

toplevel = [
    ["January", False, False, False, False, False, False, january],
    ["February", False, False, False, False, False, False, february],
    ["March", False, False, False, False, False, False, march],
    ["April", False, False, False, False, False, False, april],
    ["May", False, False, False, False, False, False, may],
    ["June", False, False, False, False, False, False, june],
    ["July", False, False, False, False, False, False, july],
    ["August", False, False, False, False, False, False, august],
    ["September", False, False, False, False, False, False, september],
    ["October", False, False, False, False, False, False, october],
    ["November", False, False, False, False, False, False, november],
    ["December", False, False, False, False, False, False, december],
]


class TreeViewFilterWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Tree Store")
        self.set_default_size(650, 400)
        vbox = Gtk.VBox(spacing=8)

        vbox.set_border_width(8)
        self.add(vbox)

        vbox.pack_start(Gtk.Label("Jonathan's Holiday Card Planning Sheet"), False, False, 0)

        sw = Gtk.ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        vbox.pack_start(sw, True, True, 0)

        # create model
        model = self.create_model()

        # create tree view
        treeview = Gtk.TreeView.new_with_model(model)
        treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)

        self.add_columns(treeview)

        sw.add(treeview)

        # expand all rows after the treeview widget has been realized
        treeview.connect("realize", Gtk.TreeView.expand_all)

    @staticmethod
    def create_model():
        # create tree store
        model = Gtk.TreeStore(str, bool, bool, bool, bool, bool, bool, bool)

        # add data to the tree store
        for month in toplevel:
            holiday = month[-1]

            iter = model.append(None)
            model.set_row(iter, (month[0], False, False, False, False, False, False, False))

            # add children
            for child in holiday:
                child_iter = model.append(iter)
                model.set_row(child_iter, (child[0], child[1], child[2], child[3], child[4], child[5], True, child[6]))

        return model

    def add_columns(self, treeview):
        model = treeview.get_model()

        # column for holiday names
        renderer = Gtk.CellRendererText()
        renderer.xalign = 0

        treeview.insert_column_with_attributes(
                position=-1,
                title="Holiday",
                cell=renderer,
                text=HOLIDAY_NAME_COLUMN)
        column = treeview.get_column(HOLIDAY_NAME_COLUMN)
        column.set_clickable(True)

        # alex column
        renderer = Gtk.CellRendererToggle()
        renderer.xalign = 0
        renderer.column = ALEX_COLUMN

        renderer.connect("toggled", self.item_toggled, model)

        treeview.insert_column_with_attributes(
                position=-1,
                title="Alex",
                cell=renderer,
                active=ALEX_COLUMN,
                visible=VISIBLE_COLUMN,
                activatable=WORLD_COLUMN)

        column = treeview.get_column(ALEX_COLUMN)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(50)
        column.set_clickable(True)

        # havoc column
        renderer = Gtk.CellRendererToggle()
        renderer.xalign = 0
        renderer.column = HAVOC_COLUMN
        renderer.connect("toggled", self.item_toggled, model)

        treeview.insert_column_with_attributes(
                position=-1,
                title="Havoc",
                cell=renderer,
                active=HAVOC_COLUMN,
                visible=VISIBLE_COLUMN)

        column = treeview.get_column(HAVOC_COLUMN)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(50)
        column.set_clickable(True)

        # tim column
        renderer = Gtk.CellRendererToggle()
        renderer.xalign = 0

        renderer.column = TIM_COLUMN
        renderer.connect("toggled", self.item_toggled, model)

        treeview.insert_column_with_attributes(
                position=-1,
                title="Tim",
                cell=renderer,
                active=TIM_COLUMN,
                visible=VISIBLE_COLUMN,
                activatable=WORLD_COLUMN)

        column = treeview.get_column(TIM_COLUMN)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(50)
        column.set_clickable(True)

        # owen column
        renderer = Gtk.CellRendererToggle()
        renderer.xalign = 0
        renderer.column = OWEN_COLUMN
        renderer.connect("toggled", self.item_toggled, model)

        treeview.insert_column_with_attributes(
                position=-1,
                title="Owen",
                cell=renderer,
                active=OWEN_COLUMN,
                visible=VISIBLE_COLUMN)

        column = treeview.get_column(OWEN_COLUMN)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(50)
        column.set_clickable(True)

        # dave column
        renderer = Gtk.CellRendererToggle()
        renderer.xalign = 0
        renderer.column = DAVE_COLUMN
        renderer.connect("toggled", self.item_toggled, model)

        treeview.insert_column_with_attributes(
                position=-1,
                title="Dave",
                cell=renderer,
                active=DAVE_COLUMN,
                visible=VISIBLE_COLUMN)

        column = treeview.get_column(DAVE_COLUMN)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(50)
        column.set_clickable(True)

    @staticmethod
    def item_toggled(cell, path_str, model):
        path = Gtk.TreePath.new_from_string(path_str)

        column = cell.column

        # get toggled iter
        iter = model.get_iter(path)
        toggle_item = model.get_value(iter, column)

        # toggle the value
        toggle_item = not toggle_item

        # set new value
        model.set_value(iter, column, toggle_item)


def main():
    win = TreeViewFilterWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
    Gtk.main()


if __name__ == "__main__":
    main()

三.Treeview Filter

PyGobject(五十六)布局容器之TreeView(上)_第7张图片
代码

#!/usr/bin/env python3
# Created by xiaosanyu at 16/6/15
# section 077
TITLE = "Treeview Filter"
DESCRIPTION = ""
import gi

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

# list of tuples for each software, containing the software name, initial release, and main programming languages used
software_list = [("Firefox", 2002, "C++"),
                 ("Eclipse", 2004, "Java"),
                 ("Pitivi", 2004, "Python"),
                 ("Netbeans", 1996, "Java"),
                 ("Chrome", 2008, "C++"),
                 ("Filezilla", 2001, "C++"),
                 ("Bazaar", 2005, "Python"),
                 ("Git", 2005, "C"),
                 ("Linux Kernel", 1991, "C"),
                 ("GCC", 1987, "C"),
                 ("Frostwire", 2004, "Java")]


class TreeViewFilterWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Treeview Filter Demo")
        self.set_border_width(10)

        # Setting up the self.grid in which the elements are to be positionned
        self.grid = Gtk.Grid()
        self.grid.set_column_homogeneous(True)
        self.grid.set_row_homogeneous(True)
        self.add(self.grid)

        # Creating the ListStore model
        self.software_liststore = Gtk.ListStore(str, int, str)
        for software_ref in software_list:
            self.software_liststore.append(list(software_ref))
        self.current_filter_language = None

        # Creating the filter, feeding it with the liststore model
        self.language_filter = self.software_liststore.filter_new()
        # setting the filter function, note that we're not using the
        self.language_filter.set_visible_func(self.language_filter_func)

        # creating the treeview, making it use the filter as a model, and adding the columns
        self.treeview = Gtk.TreeView.new_with_model(self.language_filter)
        for i, column_title in enumerate(["Software", "Release Year", "Programming Language"]):
            renderer = Gtk.CellRendererText()
            column = Gtk.TreeViewColumn(column_title, renderer, text=i)
            self.treeview.append_column(column)

        # creating buttons to filter by programming language, and setting up their events
        self.buttons = list()
        for prog_language in ["Java", "C", "C++", "Python", "None"]:
            button = Gtk.Button(prog_language)
            self.buttons.append(button)
            button.connect("clicked", self.on_selection_button_clicked)

        # setting up the layout, putting the treeview in a scrollwindow, and the buttons in a row
        self.scrollable_treelist = Gtk.ScrolledWindow()
        self.scrollable_treelist.set_vexpand(True)
        self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)
        self.grid.attach_next_to(self.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1)
        for i, button in enumerate(self.buttons[1:]):
            self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1)
        self.scrollable_treelist.add(self.treeview)


    def language_filter_func(self, model, iter, data):
        """Tests if the language in the row is the one in the filter"""
        if self.current_filter_language is None or self.current_filter_language == "None":
            return True
        else:
            return model[iter][2] == self.current_filter_language

    def on_selection_button_clicked(self, widget):
        """Called on any of the button clicks"""
        # we set the current language filter to the button's label
        self.current_filter_language = widget.get_label()
        print("%s language selected!" % self.current_filter_language)
        # we update the filter, which updates in turn the view
        self.language_filter.refilter()


def main():
    win = TreeViewFilterWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
    Gtk.main()


if __name__ == "__main__":
    main()

四.自定义TreeModel——File List

PyGobject(五十六)布局容器之TreeView(上)_第8张图片

代码:

#!/usr/bin/env python3
# section 078
TITLE = "File List (GenericTreeModel)"
DESCRIPTION = """
This is a file list demo which makes use of the GenericTreeModel python
implementation of the Gtk.TreeModel interface. This demo shows what methods
need to be overridden to provide a valid TreeModel to a TreeView.
"""

import os
import stat
import time

import pygtkcompat
pygtkcompat.enable()
pygtkcompat.enable_gtk('3.0')

import gtk


folderxpm = [
    "17 16 7 1",
    "  c #000000",
    ". c #808000",
    "X c yellow",
    "o c #808080",
    "O c #c0c0c0",
    "+ c white",
    "@ c None",
    "@@@@@@@@@@@@@@@@@",
    "@@@@@@@@@@@@@@@@@",
    "@@+XXXX.@@@@@@@@@",
    "@+OOOOOO.@@@@@@@@",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OOOOOOOOOOOOO. ",
    "@                ",
    "@@@@@@@@@@@@@@@@@",
    "@@@@@@@@@@@@@@@@@"
    ]
folderpb = gtk.gdk.pixbuf_new_from_xpm_data(folderxpm)

filexpm = [
    "12 12 3 1",
    "  c #000000",
    ". c #ffff04",
    "X c #b2c0dc",
    "X        XXX",
    "X ...... XXX",
    "X ......   X",
    "X .    ... X",
    "X ........ X",
    "X .   .... X",
    "X ........ X",
    "X .     .. X",
    "X ........ X",
    "X .     .. X",
    "X ........ X",
    "X          X"
    ]
filepb = gtk.gdk.pixbuf_new_from_xpm_data(filexpm)


class FileListModel(gtk.GenericTreeModel):
    __gtype_name__ = 'DemoFileListModel'

    column_types = (gtk.gdk.Pixbuf, str, int, str, str)
    column_names = ['Name', 'Size', 'Mode', 'Last Changed']

    def __init__(self, dname=None):
        gtk.GenericTreeModel.__init__(self)
        self._sort_column_id = 0
        self._sort_order = gtk.SORT_ASCENDING

        if not dname:
            self.dirname = os.path.expanduser('~')
        else:
            self.dirname = os.path.abspath(dname)
        self.files = ['..'] + [f for f in os.listdir(self.dirname)]
        return

    def get_pathname(self, path):
        filename = self.files[path[0]]
        return os.path.join(self.dirname, filename)

    def is_folder(self, path):
        filename = self.files[path[0]]
        pathname = os.path.join(self.dirname, filename)
        filestat = os.stat(pathname)
        if stat.S_ISDIR(filestat.st_mode):
            return True
        return False

    def get_column_names(self):
        return self.column_names[:]

    #
    # GenericTreeModel Implementation
    #
    def on_get_flags(self):
        return 0  # gtk.TREE_MODEL_ITERS_PERSIST

    def on_get_n_columns(self):
        return len(self.column_types)

    def on_get_column_type(self, n):
        return self.column_types[n]

    def on_get_iter(self, path):
        return self.files[path[0]]

    def on_get_path(self, rowref):
        return self.files.index(rowref)

    def on_get_value(self, rowref, column):
        fname = os.path.join(self.dirname, rowref)
        try:
            filestat = os.stat(fname)
        except OSError:
            return None
        mode = filestat.st_mode
        if column is 0:
            if stat.S_ISDIR(mode):
                return folderpb
            else:
                return filepb
        elif column is 1:
            return rowref
        elif column is 2:
            return filestat.st_size
        elif column is 3:
            return oct(stat.S_IMODE(mode))
        return time.ctime(filestat.st_mtime)

    def on_iter_next(self, rowref):
        try:
            i = self.files.index(rowref) + 1
            return self.files[i]
        except IndexError:
            return None

    def on_iter_children(self, rowref):
        if rowref:
            return None
        return self.files[0]

    def on_iter_has_child(self, rowref):
        return False

    def on_iter_n_children(self, rowref):
        if rowref:
            return 0
        return len(self.files)

    def on_iter_nth_child(self, rowref, n):
        if rowref:
            return None
        try:
            return self.files[n]
        except IndexError:
            return None

    def on_iter_parent(child):
        return None


class GenericTreeModelExample:
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False

    def __init__(self):
        # Create a new window
        self.window = gtk.Window(type=gtk.WINDOW_TOPLEVEL)

        self.window.set_size_request(300, 200)

        self.window.connect("delete_event", self.delete_event)

        self.listmodel = FileListModel()

        # create the TreeView
        self.treeview = gtk.TreeView()

        self.tvcolumns = []

        # create the TreeViewColumns to display the data
        for n, name in enumerate(self.listmodel.get_column_names()):
            if n == 0:
                cellpb = gtk.CellRendererPixbuf()
                col = gtk.TreeViewColumn(name, cellpb, pixbuf=0)
                cell = gtk.CellRendererText()
                col.pack_start(cell, False)
                col.add_attribute(cell, 'text', 1)
            else:
                cell = gtk.CellRendererText()
                col = gtk.TreeViewColumn(name, cell, text=n + 1)
            if n == 1:
                cell.set_property('xalign', 1.0)

            self.treeview.append_column(col)

        self.treeview.connect('row-activated', self.open_file)

        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.add(self.treeview)
        self.window.add(self.scrolledwindow)
        self.treeview.set_model(self.listmodel)
        self.window.set_title(self.listmodel.dirname)
        self.window.show_all()

    def open_file(self, treeview, path, column):
        model = treeview.get_model()
        if model.is_folder(path):
            pathname = model.get_pathname(path)
            new_model = FileListModel(pathname)
            self.window.set_title(new_model.dirname)
            treeview.set_model(new_model)
        return


def main():
    demo = GenericTreeModelExample()
    gtk.main()

if __name__ == "__main__":
    main()

五.自定义TreeModel——File Tree

PyGobject(五十六)布局容器之TreeView(上)_第9张图片
代码:

#!/usr/bin/env python3
# section 079
TITLE = "File Tree (GenericTreeModel)"
DESCRIPTION = """
This is a file list demo which makes use of the GenericTreeModel python
implementation of the Gtk.TreeModel interface. This demo shows what methods
need to be overridden to provide a valid TreeModel to a TreeView.
"""

import os
import stat
import time
from collections import OrderedDict

import pygtkcompat
pygtkcompat.enable_gtk('3.0')

import gtk


folderxpm = [
    "17 16 7 1",
    "  c #000000",
    ". c #808000",
    "X c yellow",
    "o c #808080",
    "O c #c0c0c0",
    "+ c white",
    "@ c None",
    "@@@@@@@@@@@@@@@@@",
    "@@@@@@@@@@@@@@@@@",
    "@@+XXXX.@@@@@@@@@",
    "@+OOOOOO.@@@@@@@@",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OXOXOXOXOXOXO. ",
    "@+XOXOXOXOXOXOX. ",
    "@+OOOOOOOOOOOOO. ",
    "@                ",
    "@@@@@@@@@@@@@@@@@",
    "@@@@@@@@@@@@@@@@@"
    ]
folderpb = gtk.gdk.pixbuf_new_from_xpm_data(folderxpm)

filexpm = [
    "12 12 3 1",
    "  c #000000",
    ". c #ffff04",
    "X c #b2c0dc",
    "X        XXX",
    "X ...... XXX",
    "X ......   X",
    "X .    ... X",
    "X ........ X",
    "X .   .... X",
    "X ........ X",
    "X .     .. X",
    "X ........ X",
    "X .     .. X",
    "X ........ X",
    "X          X"
    ]
filepb = gtk.gdk.pixbuf_new_from_xpm_data(filexpm)


class FileTreeModel(gtk.GenericTreeModel):
    __gtype_name__ = 'DemoFileTreeModel'

    column_types = (gtk.gdk.Pixbuf, str, int, str, str)
    column_names = ['Name', 'Size', 'Mode', 'Last Changed']

    def __init__(self, dname=None):
        gtk.GenericTreeModel.__init__(self)
        if not dname:
            self.dirname = os.path.expanduser('~')
        else:
            self.dirname = os.path.abspath(dname)
        self.files = self.build_file_dict(self.dirname)
        return

    def build_file_dict(self, dirname):
        """
        :Returns:
            A dictionary containing the files in the given dirname keyed by filename.
            If the child filename is a sub-directory, the dict value is a dict.
            Otherwise it will be None.
        """
        d = OrderedDict()
        for fname in os.listdir(dirname):
            try:
                filestat = os.stat(os.path.join(dirname, fname))
            except OSError:
                d[fname] = None
            else:
                d[fname] = OrderedDict() if stat.S_ISDIR(filestat.st_mode) else None

        return d

    def get_node_from_treepath(self, path):
        """
        :Returns:
            The node stored at the given tree path in local storage.
        """
        # TreePaths are a series of integer indices so just iterate through them
        # and index values by each integer since we are using an OrderedDict
        if path is None:
            path = []
        node = self.files
        for index in path:
            node = list(node.values())[index]
        return node

    def get_node_from_filepath(self, filepath):
        """
        :Returns:
            The node stored at the given file path in local storage.
        """
        if not filepath:
            return self.files
        node = self.files
        for key in filepath.split(os.path.sep):
            node = node[key]
        return node

    def get_column_names(self):
        return self.column_names[:]

    #
    # GenericTreeModel Implementation
    #

    def on_get_flags(self):
        return 0

    def on_get_n_columns(self):
        return len(self.column_types)

    def on_get_column_type(self, n):
        return self.column_types[n]

    def on_get_path(self, relpath):
        path = []
        node = self.files
        for key in relpath.split(os.path.sep):
            path.append(list(node.keys()).index(key))
            node = node[key]
        return path

    def on_get_value(self, relpath, column):
        fname = os.path.join(self.dirname, relpath)
        try:
            filestat = os.stat(fname)
        except OSError:
            return None
        mode = filestat.st_mode
        if column is 0:
            if stat.S_ISDIR(mode):
                return folderpb
            else:
                return filepb
        elif column is 1:
            return os.path.basename(relpath)
        elif column is 2:
            return filestat.st_size
        elif column is 3:
            return oct(stat.S_IMODE(mode))
        return time.ctime(filestat.st_mtime)

    def on_get_iter(self, path):
        filepath = ''
        value = self.files
        for index in path:
            filepath = os.path.join(filepath, list(value.keys())[index])
            value = list(value.values())[index]
        return filepath

    def on_iter_next(self, filepath):
        parent_path, child_path = os.path.split(filepath)
        parent = self.get_node_from_filepath(parent_path)

        # Index of filepath within its parents child list
        sibling_names = list(parent.keys())
        index = sibling_names.index(child_path)
        try:
            return os.path.join(parent_path, sibling_names[index + 1])
        except IndexError:
            return None

    def on_iter_children(self, filepath):
        if filepath:
            children = list(self.get_node_from_filepath(filepath).keys())
            if children:
                return os.path.join(filepath, children[0])
        elif self.files:
            return list(self.files.keys())[0]

        return None

    def on_iter_has_child(self, filepath):
        return bool(self.get_node_from_filepath(filepath))

    def on_iter_n_children(self, filepath):
        return len(self.get_node_from_filepath(filepath))

    def on_iter_nth_child(self, filepath, n):
        try:
            child = list(self.get_node_from_filepath(filepath).keys())[n]
            if filepath:
                return os.path.join(filepath, child)
            else:
                return child
        except IndexError:
            return None

    def on_iter_parent(self, filepath):
        return os.path.dirname(filepath)

    def on_ref_node(self, filepath):
        value = self.get_node_from_filepath(filepath)
        if value is not None:
            value.update(self.build_file_dict(os.path.join(self.dirname, filepath)))

    def on_unref_node(self, filepath):
        pass


class GenericTreeModelExample:
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False

    def __init__(self):
        # Create a new window
        self.window = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
        self.window.set_size_request(300, 200)
        self.window.connect("delete_event", self.delete_event)

        self.listmodel = FileTreeModel()

        # create the TreeView
        self.treeview = gtk.TreeView()

        # create the TreeViewColumns to display the data
        column_names = self.listmodel.get_column_names()
        self.tvcolumn = [None] * len(column_names)
        cellpb = gtk.CellRendererPixbuf()
        self.tvcolumn[0] = gtk.TreeViewColumn(column_names[0],
                                              cellpb, pixbuf=0)
        cell = gtk.CellRendererText()
        self.tvcolumn[0].pack_start(cell, False)
        self.tvcolumn[0].add_attribute(cell, 'text', 1)
        self.treeview.append_column(self.tvcolumn[0])
        for n in range(1, len(column_names)):
            cell = gtk.CellRendererText()
            if n == 1:
                cell.set_property('xalign', 1.0)
            self.tvcolumn[n] = gtk.TreeViewColumn(column_names[n],
                                                  cell, text=n + 1)
            self.treeview.append_column(self.tvcolumn[n])

        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.add(self.treeview)
        self.window.add(self.scrolledwindow)
        self.treeview.set_model(self.listmodel)
        self.window.set_title(self.listmodel.dirname)
        self.window.show_all()


def main():
    demo = GenericTreeModelExample()
    gtk.main()

if __name__ == "__main__":
    main()

PyGobject(五十六)布局容器之TreeView(上)_第10张图片
代码:

#!/usr/bin/env python3
# section 080
# -*- Mode: Python; py-indent-offset: 4 -*-
# pygobject - Python bindings for the GObject library
# Copyright (C) 2014 Simon Feltman
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see .

TITLE = "Tree Model with Large Data"
DESCRIPTION = """
Implementation of the Gtk.TreeModel interface to create a custom model.
The demo uses a fake data store (it is not backed by a Python list) and is for
the purpose of showing how to override the TreeModel interfaces virtual methods.
"""
import gi

gi.require_version('Gtk', '3.0')
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gtk


class Model(GObject.Object, Gtk.TreeModel):
    columns_types = (str, str)
    item_count = 100000
    item_data = 'abcdefghijklmnopqrstuvwxyz'

    def __init__(self):
        super(Model, self).__init__()

    def do_get_flags(self):
        return Gtk.TreeModelFlags.LIST_ONLY

    def do_get_n_columns(self):
        return len(self.columns_types)

    def do_get_column_type(self, n):
        return self.columns_types[n]

    def do_get_iter(self, path):
        # Return False and an empty iter when out of range
        index = path.get_indices()[0]
        if index < 0 or index >= self.item_count:
            return False, None

        it = Gtk.TreeIter()
        it.user_data = index
        return True, it

    def do_get_path(self, it):
        return Gtk.TreePath([it.user_data])

    def do_get_value(self, it, column):
        if column == 0:
            return str(it.user_data)
        elif column == 1:
            return self.item_data

    def do_iter_next(self, it):
        # Return False if there is not a next item
        next = it.user_data + 1
        if next >= self.item_count:
            return False

        # Set the iters data and return True
        it.user_data = next
        return True

    def do_iter_previous(self, it):
        prev = it.user_data - 1
        if prev < 0:
            return False

        it.user_data = prev
        return True

    def do_iter_children(self, parent):
        # If parent is None return the first item
        if parent is None:
            it = Gtk.TreeIter()
            it.user_data = 0
            return True, it
        return False, None

    def do_iter_has_child(self, it):
        return it is None

    def do_iter_n_children(self, it):
        # If iter is None, return the number of top level nodes
        if it is None:
            return self.item_count
        return 0

    def do_iter_nth_child(self, parent, n):
        if parent is not None or n >= self.item_count:
            return False, None
        elif parent is None:
            # If parent is None, return the nth iter
            it = Gtk.TreeIter()
            it.user_data = n
            return True, it

    def do_iter_parent(self, child):
        return False, None


def main():
    model = Model()
    # Use fixed-height-mode to get better model load and display performance.
    view = Gtk.TreeView(fixed_height_mode=True, headers_visible=False)
    column = Gtk.TreeViewColumn()
    column.props.sizing = Gtk.TreeViewColumnSizing.FIXED

    renderer1 = Gtk.CellRendererText()
    renderer2 = Gtk.CellRendererText()
    column.pack_start(renderer1, expand=True)
    column.pack_start(renderer2, expand=True)
    column.add_attribute(renderer1, 'text', 0)
    column.add_attribute(renderer2, 'text', 1)
    view.append_column(column)

    scrolled = Gtk.ScrolledWindow()
    scrolled.add(view)

    window = Gtk.Window(title=TITLE)
    window.set_size_request(480, 640)
    window.add(scrolled)
    window.show_all()
    GLib.timeout_add(10, lambda *args: view.set_model(model))
    return window


if __name__ == "__main__":
    window = main()
    window.connect('destroy', Gtk.main_quit)
    Gtk.main()




代码下载地址:http://download.csdn.net/detail/a87b01c14/9594728

你可能感兴趣的:(PyGObject,PyGobject详解,Python,PyGobject,gtk+,TreeView,布局容器)