Stop Gtk.DropDown pre-selecting the first item

I’ve developed an Adw application. I’m going to give quite a bit of context because I don’t know enough about Adw/Gtk to know what will be relevant.

I have a Gtk.DropDown in my app’s toolbar. I create it using Gtk.DropDown.new_from_strings() in my Adw.ApplicationWindow subclass before calling self.present().

I connect the “notify-selected” signal to my handler for dealing with changing the selected item in the dropdown. I don’t do anything in the app until someone chooses from this dropdown to decide what to work on. I do not want a default.

What I’m seeing is that the first item in the dropdown is always pre-selected. Clicking on it doesn’t send a signal (obviously because the selection isn’t changing.) This means that if I want to select the first item, I have to select another and then come back and select the first item.

I’ve tried doing my_dropdown.set_selected(Gtk.INVALID_LIST_POSITION) but this makes no difference. I’ve tried making that call before connecting the signal, after connecting the signal, and from a GLib.idle_add but there’s no visible change.

As a workaround I’ve resorted to creating a dummy entry at the start of the list of strings I use to populate the DropDown, and then remove the first entry from my_dropdown.get_model() and reselect the appropriate entry to reflect the new model contents.

Is there anything better I can do?

Code if needed:

        names.insert(0, self.DUMMY_COLLECTION_NAME)
        self.collection_box: Gtk.DropDown = Gtk.DropDown.new_from_strings(names)
        # Make the collection box's button in the toolbar look flat to match the rest of the buttons
        self.collection_box.add_css_class('flat-dropdown')
        self.collection_box.connect('notify::selected', self.collection_chosen)

There could be better solutions, but from what I see, for your use case 'no default action' entry is not a dummy entry. It’s a 'No action' entry.

Something like below from gtk4-demo: (Lists > Colors)

gtk-drop-down-default

1 Like

I work in C and the following works for me:

// nothing selected
 gtk_drop_down_set_selected (GTK_DROP_DOWN (drop_down),GTK_INVALID_LIST_POSITION);

image

Greetings

Thanks @Sid. That makes me feel better :slight_smile:

Thanks @Holger. Where is that call in relation to creating and populating the dropdown? I’ve tried selecting the INVALID_LIST_POSITION in various places and the first list item is always selected regardless.

The program in C looks like this:

 
#include"dropdown-glist.h"

GHashTable *hash_table;

// callback function
void cb_test(GtkDropDown *self,GParamSpec *spec, gpointer  data)
{
   if (gtk_widget_get_visible(GTK_WIDGET(data)))
   {
     GObject*  object = gtk_drop_down_get_selected_item (self);
     const char *key = gtk_string_object_get_string(GTK_STRING_OBJECT(object));
     gchar *wert =g_hash_table_lookup (hash_table, key);

     g_print("selected: %s  %s\n",key,wert);
   }
}

void activate (GtkApplication *app, gpointer data)
{
  GtkWidget *window;

  window =gtk_application_window_new(app);
  gtk_widget_set_size_request(window,50,50);
 
   hash_table = g_hash_table_new (g_str_hash,g_str_equal);

  GtkWidget *drop_down = gtk_drop_down_new(NULL,NULL);

  g_hash_table_insert(hash_table,"Key0","Value0");
  g_hash_table_insert(hash_table,"Key1","Value1");
  g_hash_table_insert(hash_table,"Key2","Value2");
  g_hash_table_insert(hash_table,"Key3","Value3");


 guint hash_size;
 /* Get the keys, which are strings, as an array */
 gpointer key_array = g_hash_table_get_keys_as_array (hash_table, &hash_size);
 /* Create a new GtkStringList model from the array of strings. */
 GtkStringList *stringlist = gtk_string_list_new (key_array); 
 /* Set the model as the source for the dropdown menu. */
 gtk_drop_down_set_model (GTK_DROP_DOWN(drop_down), G_LIST_MODEL(stringlist)); 
 // nothing selected
 gtk_drop_down_set_selected (GTK_DROP_DOWN (drop_down),GTK_INVALID_LIST_POSITION);

  g_signal_connect(drop_down, "notify::selected-item", G_CALLBACK(cb_test),window );

 GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,10);
 gtk_box_append(GTK_BOX(box),drop_down);
 gtk_window_set_child(GTK_WINDOW(window),box);
 
 gtk_widget_set_visible(window,TRUE);
}

For a part of the script was my source:

Greetings

Thanks. The main difference I see is that your code creates a model and sets it. My code uses Gtk.DropDown.new_from_strings to create an implicit Gtk.StringList. I’ll make a small Python app equivalent to your sample and play with that.

Thanks for the StackOverflow link too.

I’ve tested a small Python app equivalent to @Holger C code. It shows the same problem - the first item in the dropdown is pre-selected as soon as the app starts. Thanks for the help - I’m going to stick with pre-pending a dummy entry to my list of valid values.

Here’s my test code showing the issue:

import gi

gi.require_version('Gtk', '4.0')
gi.require_version('Gio', '2.0')

from gi.repository import Gtk, Gio


class DropTest(Gtk.ApplicationWindow):
    def __init__(self, application):
        super().__init__(application=application, title='Drop Test')
        self.set_size_request(100, 100)
        dropdown = Gtk.DropDown.new(None, None)
        string_list = Gtk.StringList.new(['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8'])
        dropdown.set_model(string_list)
        dropdown.set_selected(Gtk.INVALID_LIST_POSITION)
        dropdown.connect('notify::selected-item', self._on_dropdown_selected)
        main_pane = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        main_pane.append(dropdown)
        self.set_child(main_pane)
        self.set_visible(True)

    def _on_dropdown_selected(self, dropdown: Gtk.DropDown, _pspec):
        if self.get_visible():
            selected = dropdown.get_selected_item()
            if selected is None:
                print('nothing selected')
            else:
                text = selected.get_string()
                print('selected', text)


class DropApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id=None, flags=Gio.ApplicationFlags.NON_UNIQUE)
        self.connect('activate', self.on_activate)

    def on_activate(self, _app: Gtk.Application):
        DropTest(self)


app = DropApp()
app.run()

FWIW, you exact code works fine, when run from WorkBench (flatpak)

gtk-drop-down

Thanks!

Results on my system:

  1. Running from Workbench (flatpak) - works fine as @Sid says.
  2. Running from PyCharm or running from command line (with no venv) - I see the issue.

So I have a problem somewhere in my system. I’ll go do some digging.

This issue is related to the following commits:

which were introduced in GTK 4.16.0. Workbench still uses GTK 4.14.5 so it works there.

@patknight: You can report an issue at https://gitlab.gnome.org/GNOME/gtk/-/issues with above information.

Thanks!

Thanks once again, @Sid. You’ve saved me some time - I’m just going through the diffs between 4.14.5 and 4.16.5 :grinning:

I’ll report the issue.

Cheers,
Pat

1 Like

Issue In Gtk 4.16.5 cannot prevent DropDown from preselecting the first item (#7168) · Issues · GNOME / gtk · GitLab created.

1 Like