Hello,
I’m working on an application that uses sometimes editable treeviews and I have stumbled upon an issue when using an editable Gtk.CellRenderCombo.
Once the cell is edited, a Combobox kicks in and its model is filled with options. Those options can vary according to other fields in the form.
The issue is that if a user edits the cell then click somewhere else on the form then the Combobox stays there. I would have expected it the be removed (and in fact in the application some business code runs at this time).
For now I can simulate this behaviour by connecting on the editing-started
signal and in this callback connecting to the focus-out
event of the underlying Gtk.Entry of the Combobox another callback that will emit remove-widget
on the original editable
.
Some code might make this more understandable (it’s GTK3 because the application is using this version but I could reproduce the behaviour with GTK4):
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa: E402
class TreeViewWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Treeview Filter Demo")
# Setting up the self.grid in which the elements are to be positioned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
self.store = Gtk.ListStore(str, str, float)
self.store.append(["Yes", "Hello", 12])
self.store.append(["No", "Goodbye", 2])
self.store.append(["No", "Brol", 1])
self.store.append(["Yes", "Foo", 120])
self.prop_store = Gtk.ListStore(str)
self.prop_store.append(['Yes'])
self.prop_store.append(['No'])
self.prop_store.append(['N/A'])
self.tree = Gtk.TreeView(model=self.store)
renderer_1 = Gtk.CellRendererCombo()
renderer_1.set_property('editable', True)
renderer_1.set_property('model', self.prop_store)
renderer_1.set_property('text-column', 0)
renderer_1.set_property('has-entry', True)
renderer_1.connect('editing-started', self.editing_started)
col_1 = Gtk.TreeViewColumn("Propagate", renderer_1, text=0)
self.tree.append_column(col_1)
renderer_2 = Gtk.CellRendererText()
renderer_2.set_property('editable', True)
col_2 = Gtk.TreeViewColumn("Name", renderer_2, text=1)
self.tree.append_column(col_2)
renderer_3 = Gtk.CellRendererText()
col_3 = Gtk.TreeViewColumn("Weight", renderer_3, text=2)
self.tree.append_column(col_3)
self.scrollable_treelist = Gtk.ScrolledWindow()
self.scrollable_treelist.set_vexpand(True)
self.scrollable_treelist.add(self.tree)
self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)
label = Gtk.Label(label="Test")
self.grid.attach(label, 0, 10, 1, 1)
checkbutton = Gtk.CheckButton()
checkbutton.connect('toggled', self.button_checked)
self.grid.attach(checkbutton, 1, 10, 1, 1)
entry = Gtk.Entry()
self.grid.attach(entry, 2, 10, 2, 1)
self.show_all()
def button_checked(self, button):
self.prop_store.clear()
if button.props.active:
self.prop_store.append(['Foo'])
self.prop_store.append(['Bar'])
self.prop_store.append(['Baz'])
else:
self.prop_store.append(['Yes'])
self.prop_store.append(['No'])
self.prop_store.append(['N/A'])
def editing_started(self, cell, editable, path):
entry = editable.get_child()
entry.connect('focus-out-event', self.focus_out, editable)
def focus_out(self, entry, event, editable):
editable.emit('editing-done')
editable.emit('remove-widget')
win = TreeViewWindow()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
Is this the expected behaviour of the CellRendererCombo
? If so, is my assumption valid that I have to add those two callbacks in order to get the behaviour I expect? If not what would be the canonical way to solve this?
Another issue I have with my solution is that I noticed that it does not work when using X11. It works as I expect it to work under Wayland and Windows but not under X11. Is this an issue worth reporting to the bug tracker?
Thank you for any pointer on how to solve this the GTK way