自定义 Gtk.CellRenderer,在 True、None(显示为不一致)和 False、python GTK 3 之间切换循环

Custom Gtk.CellRenderer with a Toggle cycling between True, None (displayed as inconsistent) and False, python GTK 3

提问人:evolution 提问时间:12/30/2019 最后编辑:evolution 更新时间:12/31/2019 访问量:411

问:

我需要编写一个自定义(我们称之为),其行为类似于 ,但不是仅支持,我还希望它支持,它应该显示为不一致的状态,如下所示:Gtk.CellRendererCellRendererToogleWithNoneGtk.CellRendererToggleTrueFalseNoneinconsistent state pygtk

在切换时,我想按某个定义的顺序旋转,例如:True -> False -> None (但这可能是最简单的部分,我仍然认为我提到了这一点)

我也不知道如何让它与 TreeStore 一起使用,因为如果我这样做

self.treestore = Gtk.TreeStore.new(types = (bool,))
iter = self.treestore.append(parent = None, row = (None,))

它会将任何值转换为,因为似乎不允许值NoneFalseboolNone

我在网上找不到任何有用的自定义示例。Gtk.CellRenderer

我想通过继承而不是继承来做到这一点,因为这也应该为我提供一个有用的例子,以实现更多这样的单元格渲染器。Gtk.CellRendererGtk.CellRendererToggle

我只能猜测我必须为 ,而不是(也不知道该怎么做)并将我自己的数据类型保留在我的自定义中。TreeStorebool_or_noneboolGtk.ToggleButtonCellRendererToogleWithNone

编辑 0:

这篇关于如何编写自定义的文章提供了一些提示,这些提示也许可以重用,但并不能解决我的问题。它没有显示如何为变量创建接受值,我不明白那里的所有内容。它甚至没有使用Gtk.Button,相反,它似乎在一个小部件内画了一个框,我猜它可能是父级。我不想画我自己的 Toggle,我想重用它的属性Gtk.CellRendererGtk.TreeStoreNoneboolGtk.ToggleButtoninconsistent

编辑1:

由于自定义单元格渲染器似乎并不容易,因此我认为在 python 中查看一个最小的工作示例会特别有用。我还应该提到,我希望尽可能紧凑地显示数据,这排除了建议的解决方法,例如对一个值进行两个切换。

python 切换 gtk3 gtktreeview

评论

0赞 stovfl 12/30/2019
这回答了你的问题吗?如何在python和GTK 3中编写自定义Gtk.CellRenderer?
1赞 Alexander Dmitriev 12/30/2019
1)您可以将值存储在GVariant中,也可以创建具有3个可能值的自定义类,然后可以创建类型为.我不确定它是否一定是 GObject 子类。2) 编写自定义 CellRenderer 不是一件容易的事情,因为它们不是传统的小部件,因为您必须手动渲染所有内容。查看“CellRendererToggle 源代码”以获取提示。object
1赞 Alexander Dmitriev 12/30/2019
3) 另一种方法是使用 和 2 列:一列用于属性,一列用于GtkCellRendererToggle"active""inconsistent"
0赞 evolution 12/30/2019
@Alexander 感谢您的 GVariant 提示。这正是我在这里问的原因。我似乎不太容易实现单元格渲染器,所以我希望有人能有使用它们的经验。关于您的第二条评论,我的目标之一是尽可能紧凑地显示数据,因此将切换量增加一倍对我来说是不可能的。

答:

3赞 stovfl 12/30/2019 #1

:自定义在 True、None(显示为不一致)和 False 之间切换循环。Gtk.CellRendererToggle

你被误导了,它不是设置标志的对象的一部分。它在那里实现。你必须实现一个。Gtk.CellRendererToggleinconsistantGtk.TreeCellDataFunc

我也希望它支持 None

我无法让它与值一起使用,
因此我使用带有值的类型:
Noneint[False, True, 2]

注意

  • 在值中,更改为 和 。如果您希望它保持类型,请相应地实现。def on_toggle(...)model0 == False1 == Trueboolean
  • 您应该知道,值 的计算结果也为 。2True

App


参考资料

  • Gtk.TreeViewColumn.set_cell_data_func

    此函数用于代替标准属性映射来设置列值,并且应根据需要设置 self 的单元格渲染器的值。

  • Gtk.TreeCellDataFunc

    用于设置单元格属性的函数,而不仅仅是使用单元格和模型之间的直接映射。这对于自定义单元格呈现器非常有用


实现: 核心点:.set_cell_data_func(cell_renderer, .set_status)

class TreeViewColumnTriState(Gtk.TreeViewColumn):

    def __init__(self, title='', model=None, **attributes):
        cell_renderer = Gtk.CellRendererToggle()
        cell_renderer.connect("toggled", self.on_toggle, model)

        self.inconsistent = attributes.pop('inconsistent', None)
        super().__init__(title, cell_renderer, active=0, **attributes)
        self.set_cell_data_func(cell_renderer, self.set_status)

    def set_status(self, column, cell, model, _iter, *ignore):    
        if model.get_value(_iter, 0) == self.inconsistent:
            cell.set_property('inconsistent', True)
        else:
            cell.set_property('inconsistent', False)

    def on_toggle(self, cell, path, model, *ignore):
        if path is not None:
            model = model[model.get_iter(path)]    
            model[0] += 1
            if model[0] == 3:
                model[0] = 0

用法

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


class App(Gtk.ApplicationWindow):
    def __init__(self):
        super().__init__()
        self.connect("destroy", Gtk.main_quit)

        model = Gtk.ListStore(int)

        #  Some initial data
        for n in [False, True, 2]:
            model.append([n])

        col = TreeViewColumnTriState("Foo", model, inconsistent=2)

        tv = Gtk.TreeView(model)
        tv.append_column(col)
        self.add(tv)

        self.show_all()


if __name__ == "__main__":
    main = App()
    Gtk.main()

与Python版本兼容:3.5 - gi.__version__:3.22.0

评论

1赞 evolution 12/31/2019
在仔细查看并玩弄代码后,我接受了您的回答。你是对的,我误解了几件事。我不需要实现 CellRenderer,我可以像在示例中那样使用 CellRendererToggle。实现 CellRenderer 意味着我需要绘制自己的切换开关,这与我重用现有切换开关的愿望相矛盾。我的 TreeStore 仍然不接受 None 值,但我觉得我现在应该把它作为一个单独的问题。现在,我没有采取 int,而是坚持使用 bool,但做了一些诡计,所以我不需要依赖 TreeStore on None。