Spurious row selection on dragging column divider

Run the following program and then click on the line dividing the two headers as you would do to change the width of the columns. On clicking on that line, the first row of the treeview gets selected. Is that behavior normal? Is there a way to prevent it?

Note that the selection occurs only the first time that line gets clicked. If you subsequently unselect the first row (ctrl-leftclick), clicking the dividing line no longer selects the first row.

import random

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

# Create a list of tuples of random strings.
def ranstr():
    strlen = random.randrange(3, 10)
    return ''.join(chr(random.choice(range(ord('a'), ord('a') + 26)))
            for _ in range(strlen))

ranlist = [(ranstr().capitalize(), ranstr().capitalize()) for i in range(10)]

class TreeViewWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect('destroy', Gtk.main_quit)
        self.show()

        liststore = Gtk.ListStore(str, str)
        for item in ranlist:
            liststore.append(item)

        treeview = Gtk.TreeView()
        treeview.set_model(liststore)
        treeview.show()

        renderer = Gtk.CellRendererText()

        for i in range(2):
            column = Gtk.TreeViewColumn()
            column.set_title(f'Column{i}')
            column.pack_start(renderer, True)
            column.add_attribute(renderer, 'text', i)
            column.set_resizable(True)
            column.set_fixed_width(150)
            treeview.append_column(column)

        self.add(treeview)


win = TreeViewWindow()
Gtk.main()

After some research in gtktreeview.c, I can divide the situation into two parts:

  1. Clicking on the column divider causes the treeview to grab_focus(). This part seems reasonable.

  2. If GtkTreeView’s implementation of grab_focus finds the keyboard cursor unset and no row is selected, it will set the cursor to the first focusable row. As documented, the call to set_cursor() will also select the row.

An offhand thought: If the automatic selection triggers unwanted behavior in your application, have you considered adding some sort of explicit ‘None’ row at the top? You could then change the selection mode to BROWSE.

However, I did come up an ugly workaround:

    treeview.set_cursor('0', None, False)
    treeview.get_selection().unselect_all()

Doing this after creating the treeview sets the cursor so that grab_focus() doesn’t trigger a selection. It might need to be repeated any time the model is emptied and repopulated as that would unset the cursor again.

1 Like

Brilliant. Anything that works is beautiful in my book. Thanks.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.