自定义 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

我需要编写一个行为类似于 Gtk.CellRendererToggle 的自定义 Gtk.CellRenderer(我们称之为 CellRendererToogleWithNone),而不是仅支持 TrueFalse 我还希望它支持 None 应该显示为这样的不一致状态:

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

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

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

它将任何 None 值转换为 False 因为 bool 似乎不允许 None

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

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

我只能猜测我必须为 TreeStore 定义一些自定义数据类型,比如 bool_or_none 而不是 bool(也不知道该怎么做)和在我的习惯 CellRendererToogleWithNone 中保留我自己的 Gtk.ToggleButton

编辑 0:

This post 关于如何编写自定义 Gtk.CellRenderer 给出了一些可能可以重用但不能解决我的问题的提示。它没有显示如何让 Gtk.TreeStore 接受 bool 变量的 None 值,我不明白那里的一切。它甚至不使用 Gtk.Button,而是似乎在我猜可能是父级的小部件内绘制了一个框。我不想画自己的 Toggle,我想重用 Gtk.ToggleButton 和它的 inconsistent 属性

编辑 1:

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

Question: Custom Gtk.CellRendererToggle with a Toggle cycling between True, None (displayed as inconsistent) and False.

你被误导了,设置 inconsistant 标志不是 Gtk.CellRendererToggle 对象的一部分。它已经在那里实施了。您必须改为实施 Gtk.TreeCellDataFunc

I also want it to support None

I don't get it to work with a None value,
therefore i use type int with values: [False, True, 2]

:

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


参考:

  • Gtk.TreeViewColumn.set_cell_data_func

    This function is used instead of the standard attributes mapping for setting the column value, and should set the value of self’s cell renderer as appropriate.

  • Gtk.TreeCellDataFunc

    A function to set the properties of a cell instead of just using the straight mapping between the cell and the model. This is useful for customizing the cell renderer


Implementation: Core point: .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

Usage:

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