The following code displays a window with a button and tree view. A handle for the 'clicked' signal is attached to the button and focuses the tree view. When the window is initially displayed, the tree selection has no selected items, but when the tree view receives focus, the first item is automatically selected. Is there a way to keep a selection from being made when the tree view receives focus?
Before click, button has focus and tree selection has no selected items. After click, tree view has focus, but an item has been selected.
The issue that arises from this is that I have an interface that keeps some things in sync by attaching to the 'changed' signal on the tree selection of the tree view. When the window is displayed, depending on where the tree views are in the interface, they may receive focus by default. That causes a 'changed' signal, and unexpected synchronization happens. It's possible to call set_can_focus(False) for all the tree views, but that:
Similarly I can use grab_default to ensure that something else gets focus first when the window is displayed, but it doesn't keep a stray focus event from making an unexpected selection.
Based on a posted answer that says that says that selection mode SINGLE "requires at least one item to be selected", and that that explains why an element is selected on focus, I looked more into the selection mode constants. Of these, SINGLE and BROWSE seem most relevant. The pygtk documentation, GTK Selection Mode Constants, only says that:
gtk.SELECTION_SINGLE
A single selection allowed by clicking.gtk.SELECTION_BROWSE
A single selection allowed by browsing with the pointer.
The GTK+3 documentation, enum GtkSelectionMode, goes into a bit more detail:
GTK_SELECTION_SINGLE
Zero or one element may be selected.GTK_SELECTION_BROWSE
Exactly one element is selected. In some circumstances, such as initially or during a search operation, it’s possible for no element to be selected with GTK_SELECTION_BROWSE. What is really enforced is that the user can’t deselect a currently selected element except by selecting another element.
I don't see anything here to suggest that at least one element must be selected when the selection mode is SINGLE.
Here's code to reproduce the window and serve as an example.
from gi.repository import Gtk
# A ListStore with some words
list_store = Gtk.ListStore(str)
for selection in "Can a machine think?".split():
list_store.append([selection])
# A TreeView with a single column
tree_view = Gtk.TreeView(model=list_store)
cell_renderer = Gtk.CellRendererText()
tree_view_column = Gtk.TreeViewColumn(cell_renderer=cell_renderer,text=0,title='Words')
tree_view.append_column(tree_view_column)
# A button to focus the list
focus = Gtk.Button(label='Focus List')
focus.connect('clicked',lambda *_: tree_view.grab_focus())
# A Box to hold everything, and a Window for the Box.
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.add(focus) # button on top gets initial focus
box.add(tree_view) # tree_view below doesn't, and has no selected items
window = Gtk.Window()
window.add(box)
window.show_all()
Gtk.main()
Looking at the source in root/gtk/gtktreeview.c for tree_view.grab_focus(), we can see that gtk_tree_view_focus_to_cursor always gets called, and selects the first element. You can work around this, in some cases, though.
This is a nasty hack.
It overrides the grab_focus
method, stores the selection before calling grab_focus
, and clears the selection afterwards if there was no selection before.
def tree_view_grab_focus():
selection = tree_view.get_selection()
_, selected = selection.get_selected()
Gtk.TreeView.grab_focus(tree_view)
if selected is None:
selection.unselect_all()
tree_view.grab_focus = tree_view_grab_focus
Unfortunately it only applies when calling grab_focus
from Python, other callers (such as GTK's keyboard navigation) don't.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With