This is potentially a bug, though perhaps I'm misunderstanding something.
Brief description
Basically, I have found that using "Shift+Arrows" to do multiple selection in a Gtk.TreeView
does not work correctly after changing the selection using Gtk.TreeSelection.select_iter
. On the other hand, if you change the selection by clicking on a row and then pressing "Shift+Arrows", the selection behaves as one would expect.
I should note that if you change the selected row by calling Gtk.TreeSelection.select_iter
, the UI updates as you would expect and calling Gtk.TreeSelection.get_selected_rows()
returns the rows it should. It's only when you then try to select multiple rows using the arrow keys that you get strange behavior.
This is perhaps best illustrated in this self contained example, which I've tried to make as simple as possible:
Code
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class TreeViewBug(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.connect('destroy', Gtk.main_quit)
# Create model consisting of row path and a name
self.treeModel = Gtk.ListStore(int, str)
self.treeModel.append([0, 'alice'])
self.treeModel.append([1, 'bob'])
self.treeModel.append([2, 'chad'])
self.treeModel.append([3, 'dan'])
self.treeModel.append([4, 'emma'])
self.treeView = Gtk.TreeView()
self.treeView.append_column(Gtk.TreeViewColumn('path', Gtk.CellRendererText(), text=0))
self.treeView.append_column(Gtk.TreeViewColumn('name', Gtk.CellRendererText(), text=1))
self.treeView.set_model(self.treeModel)
# Allow for multiple selection
self.treeView.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
self.add(self.treeView)
def run(self):
self.show_all()
# Focus the TreeView so we can test multiple select via keyboard without clicking on a row
self.treeView.grab_focus()
# Manually change the selected row to the row with "chad"
chadIter = self.treeModel[2].iter
self.treeView.get_selection().select_iter(chadIter)
print('Press "Shift+Down" and see what happens')
print(' it should select "chad, dan", but instead it selects "bob, chad"')
print('Afterwards, try clicking on "chad" and then pressing Shift+Down. It should behave normally')
Gtk.main()
if __name__ == '__main__':
tv = TreeViewBug()
tv.run()
Things I've tried
I initially encountered the bug when my code changed the selected row via Gtk.TreeSelection.select_iter
in response to a button click.
I've also tried:
Gtk.TreeSelection.set_select_function
)Gtk.TreeSelection.unselect_all
)GLib.idle_add
).TreeView
after changing selectionSpeculations
I'm guessing that TreeView
/TreeViewSelection
has some internal state variable tracking selection and row that, for some reason, isn't getting properly updated when TreeSelection.select_iter
is called. These variables are probably related to UI features, because TreeSelection.get_selected_rows
still works properly. Also it makes sense the UI would need additional state information since the UI logic of multiple selection depends on previous UI interaction (Shift+Down behaves differently when extending a selection depending on whether you initially selected upwards or downwards)
Because a Gtk.TreeView uses MVC, you actually need to set the cursor of the treeview. This may affect the rest of the program, depending on what you are doing. Example:
#chadIter = self.treeModel[2].iter
#self.treeView.get_selection().select_iter(chadIter)
path = 2
column = self.treeView.get_column(0)
edit = False
self.treeView.set_cursor(path, column, edit)