I need to write a custom Gtk.CellRenderer
(let's call it CellRendererToogleWithNone
) that behaves similar to Gtk.CellRendererToggle
, but instead of only supporting True
and False
I also want it to support None
which should be displayed as inconsistent state like this:
On toggle I want to rotate in some defined order, for example like so: True -> False -> None (But that's probably the easy part, I still thought I mention that)
I also don't know how to make it work with TreeStore because if I do
self.treestore = Gtk.TreeStore.new(types = (bool,))
iter = self.treestore.append(parent = None, row = (None,))
it will convert any None
value to False
because bool
seems not to allow for None
values
I failed to find any helpful custom Gtk.CellRenderer
examples online.
I want to do it by inheriting from Gtk.CellRenderer
and NOT from Gtk.CellRendererToggle
because this should also serve me as a helpful example to implement more cell renderers like this.
I can only guess that I have to define some custom data type for the TreeStore
, something like bool_or_none
instead of bool
(no idea how to do that either) and hold my own Gtk.ToggleButton
inside of my custom CellRendererToogleWithNone
.
Edit 0:
This post about how to write custom Gtk.CellRenderer
gives a couple of hints which maybe can be reused but does not solve my problem. It doesn't show how to make Gtk.TreeStore
accept None
values for bool
variables and I don't understand everything there. It doesn't even use a Gtk.Button, instead it seems to paint a box inside of a widget that I'm guessing may be the parent. I don't want to paint my own Toggle, I want to reuse Gtk.ToggleButton
and its inconsistent
property
Edit 1:
Since it seems custom cell renderers are not easy, I think it would be especially useful to see a minimal working example in python. I should also mention that I want to display the data as compactly as possible which excludes suggested workarounds such as having two toggles for one value.
Question: Custom
Gtk.CellRendererToggle
with a Toggle cycling between True, None (displayed as inconsistent) and False.
You are misguided, it's not the part of a Gtk.CellRendererToggle
object to set the inconsistant
flag. It's implemented allready there. You have to implement a Gtk.TreeCellDataFunc
instead.
I also want it to support
None
I don't get it to work with a
None
value,
therefore i use typeint
with values:[False, True, 2]
Note:
- In
def on_toggle(...)
themodel
values get changed to0 == False
and1 == True
. If you want it to be stay of typeboolean
, implement accordingly.- You should be aware, that the value
2
, evaluates toTrue
also.
Reference:
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.
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()
Tested with Python: 3.5 - gi.__version__: 3.22.0