5

在 Gtk+3 上,我使用 aTreeModel来存储嵌套信息,并用 aCellRendererText和 a显示它CellRendererToggle。用户可以点击每个切换按钮,当有嵌套的按钮并且它们处于不同的状态时,我希望上层的按钮反映“不一致”状态。如何为一个元素设置此属性?

为了更清楚起见,我想从传输 bittorrent 客户端实现的示例: 在此处输入图像描述

我知道如何将单元格渲染器的所有按钮设置为不一致的状态,myCellRendererToggle.set_properties(inconsistent=True)但似乎我无法从这里访问一个元素;

我知道如何访问我的 TreeStore 模型的特定行,但我只能设置 «True» 和 «False» 值。

我的代码非常接近官方文档,因此您可以帮助我:https ://python-gtk-3-tutorial.readthedocs.org/en/latest/cellrenderers.html#cellrenderertoggle(我使用 treeStore 而不是列表存储)

这是我的代码:

class HelloMyApp:

def __init__(self):

    # Set the Glade file
    self.builder = Gtk.Builder()
    self.builder.add_from_file(GLADEFILE)


    dic = {
        "on_button1_clicked" : self.btnValidate_clicked,
        "on_MainWindow_destroy" : self.quit,
        "on_window1_delete_event" : self.quit,

        }

    self.builder.connect_signals(dic)

    window = self.builder.get_object("window1")

    treeview1 = self.builder.get_object("treeview1")

    ######## This is my model : it stores a string and a boolean. #########
    self.treeModel = Gtk.TreeStore(str, bool)

    # Example on how to insert data in the model
    treeIter = self.treeModel.append(None, ['example one', True])
    self.treeModel.append(treeIter, [' simple elt', True])
    treeIter = self.treeModel.append(treeIter, ['example two', False])
    self.treeModel.append(treeIter, ['under example two', True])


    select = treeview1.get_selection()
    select.set_mode(Gtk.SelectionMode.BROWSE)

    select.connect("changed", self.on_tree_selection_changed, buf) 

    # Using one column of text and another column with the toggle buttons
    renderer = Gtk.CellRendererText()
    column = Gtk.TreeViewColumn("Title", renderer, text=0)
    treeview1.append_column(column)

    ######  Here is the CellRendereToggle  ################
    renderer_toggle = Gtk.CellRendererToggle()
    renderer_toggle.connect("toggled", self.on_cell_toggled)
    column_toggle = Gtk.TreeViewColumn("Installer", renderer_toggle, active=1)
    treeview1.append_column(column_toggle)

    treeview1.set_model(self.treeModel)


    window.show_all()


if __name__ == "__main__":

    HelloMyApp = HelloMyApp()
    Gtk.main()

谢谢 !

编辑:回答马库斯:我想不通,当我在函数内更改 CellRendererToggle 的属性时,它会更改每一行。

编辑解决方案:正如 Marcu 指出的那样,我们必须在每种情况下设置属性,这就是我添加该else部分的原因。

def cellRenderer_func(column, cellRenderer, treeModel, treeIter, userData):
    if 'cat' in treeModel.get_value(treeIter, 0): 
        # it happens only ones in my model, 
        # so here I am in a row I want to change to inconsistent.
        cellRenderer.set_property('inconsistent',True) 
        # I was expecting that changes the box of that row but it affects every row. 

    else: 
        cellRenderer.set_property('inconsistent', False) # and that's ok now.

我得再试一次。我想知道......我们真的必须手动完成吗,它不能成为 treeView 的开箱即用功能吗?

4

2 回答 2

4

可以通过使用单元格数据函数来设置一个元素的属性。由于我只在 C 中完成此操作,因此我只能将 PyGTK 文档的链接传递给您,我还没有看到 PyGObject 的此功能的相关文档。

对于 PyGTK 已在此处记录,页面在底部为您提供了一个示例,PyGTK 的单元格数据函数的使用也在文档中进行了介绍。

例如,如果您想做与传输相同的操作,您可以执行以下操作:由于您接收当前迭代器作为单元格数据函数的参数,您可以在那里循环遍历其所有子节点并检查孩子们。然后,您将知道在父节点上设置哪个状态。现在主要的一点是,在单元格数据函数中设置一个属性只会影响这个单个单元格,而不是树视图的所有元素。

我还可以为我自己的应用程序提供一个可视化示例:

在此处输入图像描述

我在此树视图中有“值”列。如果“菜单元素”列中的值设置为“启用”并且“类型”列中的值是“选项”,则会显示一个复选框而不是文本(我已经突出显示了这一行)。示例图像还显示了一个活动搜索,它突出显示了搜索结果。两者都可以使用单元格数据函数来设置您在问题中要求的一个元素的属性。

编辑

我已经完成了一些示例代码。要点是始终为每个单元格设置单元格属性。所以不仅仅是“如果……,那么设置属性”,而是“如果,像这样设置属性,否则,像那样设置属性”。(它基于旧的 PyGTK 文档,但无论如何它应该澄清一些事情)。

#!/usr/bin/env python

# example basictreeview.py

import pygtk
pygtk.require('2.0')
import gtk

class BasicTreeViewExample:

    def set_status(self, column, cell, model, iter):
        if 'inconsistent' in model.get_value(iter, 0):
            cell.set_property('inconsistent',True) 
        else:
            cell.set_property('inconsistent',False)
        return

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

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        self.window.set_title("Basic TreeView Example")

        self.window.set_size_request(200, 200)

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

        self.treestore = gtk.TreeStore(str)

        for parent in range(4):
            piter = self.treestore.append(None, ['parent %i' % parent])
            for child in range(3):
                if child == 1:
                    self.treestore.append(piter, ['consistent'])
                else:
                    self.treestore.append(piter, ['inconsistent'])

        self.treeview = gtk.TreeView(self.treestore)

        self.tvcolumn0 = gtk.TreeViewColumn('Column 0')
        self.tvcolumn1 = gtk.TreeViewColumn('Column 1')

        self.treeview.append_column(self.tvcolumn0)
        self.treeview.append_column(self.tvcolumn1)

        self.text = gtk.CellRendererText()
        self.toggle = gtk.CellRendererToggle()

        self.tvcolumn0.pack_start(self.text, True)
        self.tvcolumn1.pack_start(self.toggle, True)

        self.tvcolumn0.add_attribute(self.text, 'text', 0)
        self.tvcolumn1.set_cell_data_func(self.toggle, self.set_status)

        self.window.add(self.treeview)

        self.window.show_all()

def main():
    gtk.main()

if __name__ == "__main__":
    tvexample = BasicTreeViewExample()
    main()
于 2013-02-07T22:51:38.990 回答
1

我最近遇到了同样的问题,发现如果您希望直接从模型中的列设置属性,则不需要单元格数据函数。实现该问题的代码中所需的更新应如下所示:

self.treeModel = Gtk.TreeStore(str, bool, bool)
...
column_toggle = Gtk.TreeViewColumn("Installer", renderer_toggle, active=1, inconsistent=2)

然后根据需要在新列中设置不一致的值。

作为关于何时在模型中选择单元格数据函数或新列的提示,请考虑以下事项(Gtk+ By Example):

每次渲染该(渲染器)列中的单元格时,都会调用您的单元格数据函数。如果你曾经使用过这个函数,去检查一下这个函数在你的程序中被调用的频率。如果您在单元格数据函数中执行耗时的操作,事情不会很快,特别是如果您有很多行。

于 2014-04-30T14:47:48.860 回答