Multiple Selection in Flowbox, trying to toggle selection

I’m trying to use multiple selection in a flowbox to allow toggle a selected item, shift to select a range etc. I also expected that clicking without Ctrl would replace the current selection.

However, shift and ctrl make no difference and items are just added to the selection.

import gi

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

class FlowBoxMultiSelectionWindow(Gtk.Window):
    def __init__(self):
        super().__init__(title="FlowBox Multiple Selection (Python)")
        self.set_default_size(400, 300)
        self.connect("destroy", Gtk.main_quit)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        self.add(vbox)

        self.flowbox = Gtk.FlowBox()
        # Set the selection mode to multiple
        self.flowbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self.flowbox.set_homogeneous(True)
        self.flowbox.set_row_spacing(5)
        self.flowbox.set_column_spacing(5)
        self.flowbox.set_max_children_per_line(5)

        # Add some children to the FlowBox
        for i in range(20):
            label = Gtk.Label(label=f"Item {i + 1}")
            self.flowbox.add(label)

        scrolled_window = Gtk.ScrolledWindow()
        scrolled_window.add(self.flowbox)
        vbox.pack_start(scrolled_window, True, True, 0)

        button = Gtk.Button(label="Print Selected")
        button.connect("clicked", self.print_selected_children)
        vbox.pack_start(button, False, False, 0)

    def print_selected_children(self, button):
        selected_children = self.flowbox.get_selected_children()
        print("Selected children:")
        for child in selected_children:
            # Get the widget inside the FlowBoxChild
            child_widget = child.get_child()
            if isinstance(child_widget, Gtk.Label):
                print(f"  - {child_widget.get_label()}")

if __name__ == "__main__":
    win = FlowBoxMultiSelectionWindow()
    win.show_all()
    Gtk.main()

What am I missing? from the description GTK_SELECTION_MULTIPLE sounds to do what I want.

 GTK_SELECTION_MULTIPLE

    Any number of elements may be selected. The Ctrl key may be used to enlarge the selection, and Shift key to select between the focus and the child pointed to. Some widgets may also allow Click-drag to select a range of elements.

I’ve tried both GTK3 and GTK4, but get same behaviour.
I’m using Ubuntu 24.04 and have checked (in a separate test) that the SHIFT and CONTROL masks are set on a clicked event handler.

Hoping someone can point me in the right direction, have I misunderstood how it is supposed to work, or if no one can see problems with my code, any pointers for debugging?

Hi,

I just checked the gtk4-demo:

  • the Ctrl and Shift keys work fine to extend the selection when using the keyboard arrows.
  • I can extend the selection by click-and-drag with the mouse.
  • but Ctrl or Shift with the mouse have no effect.

I can’t tell if the mouse behavior is correct or not. Maybe the docs are only about selecting with the keyboard.
Should be possible anyway to catch the click events and programmatically select a range, if needed by your app.

EDIT: <TL;DR>
setting set_activate_on_single_click(False) fixed it.
Thanks for your help
</TL;DR>

Hi,
Thanks, it helps get more detail, in my case:

  • Ctrl and Shift with the keyboard work fine.
  • I also discovered Ctrl and Shift work correctly with click and drag with the mouse, even if the selection area is small enough only to cause a single child element to be selected.

Clicking with or without modifiers always only adds the child to the existing selection, it never replaces it.

If It’s implemented for keyboard and “multiple selection” with the mouse (even if that’s one element) it feels like it should work for mouse click too. Implementing it myself for click feels a bit like it would be re-implementing.

I’m not familiar with the internals of GTK, but looking at the source best I can it suggests it only considers the modifiers for a click when activate_on_single_click is false

static void
gtk_flow_box_multipress_gesture_released (GtkGestureMultiPress *gesture,
                                          guint                 n_press,
                                          gdouble               x,
                                          gdouble               y,
                                          GtkFlowBox           *box)

if (priv->activate_on_single_click)
        gtk_flow_box_select_and_activate (box, priv->active_child);
      else
        {
          GdkEventSequence *sequence;
          GdkInputSource source;
          const GdkEvent *event;
          gboolean modify;
          gboolean extend;

          get_current_selection_modifiers (GTK_WIDGET (box), &modify, &extend);

          /* With touch, we default to modifying the selection.
           * You can still clear the selection and start over
           * by holding Ctrl.
           */

          sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
          event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
          source = gdk_device_get_source (gdk_event_get_source_device (event));

          if (source == GDK_SOURCE_TOUCHSCREEN)
            modify = !modify;

          gtk_flow_box_update_selection (box, priv->active_child, modify, extend);
1 Like

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