Programicaly moving through list box, C, gtk4

,

Hello all,
I again need help.

I have app written in c/c++ in gtk4. In App is list box with quite a lot rows and I would like that app after pressing some letter (e.g. a) move to first row which start with this letter.

In my code I have function “keyPress” where I can recognize what letter was pressed (switch will be enhanced in real app). I can find index of row which starts with pressed letter.
But I can not find any gtk function which moves me to this row. Exists this function?

Thanks for any advice!

my testing code:

#include <gtk/gtk.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm> //to make string lowercases


using namespace std;

GtkWidget *lBox;

gboolean
keyPress (GtkWidget             *drawing_area,
                      guint                  keyval,
                      guint                  keycode,
                      GdkModifierType        state,
                      GtkEventControllerKey *event_controller)
{
    string comparedString;
    switch (keyval)
    {
        case GDK_KEY_a:
            std::cout << "Pressed - a" << std::endl;
            comparedString = "a";
            break;
        case GDK_KEY_b:
            std::cout << "Pressed - b" << std::endl;
            comparedString = "b";
            break;
        case GDK_KEY_c:
            std::cout << "Pressed - c" << std::endl;
            comparedString = "c";
            break;
        case GDK_KEY_d:
            std::cout << "Pressed - d" << std::endl;
            comparedString = "d";
            break;
        case GDK_KEY_e:
            std::cout << "Pressed - e" << std::endl;
            comparedString = "e";
            break;
    }

    int index = 0;
    GtkListBoxRow* testedRow;
    string rowText;
    //loop for finding row begining with pressed letter
    while ( (testedRow = gtk_list_box_get_row_at_index (GTK_LIST_BOX(lBox),index++)) != NULL ) {
        rowText = gtk_label_get_text(GTK_LABEL(gtk_list_box_row_get_child (GTK_LIST_BOX_ROW(testedRow))));

        transform(rowText.begin(), rowText.end(), rowText.begin(),[](unsigned char c){ return tolower(c); });
        //cout << "row" << index << ": " << rowText << " -find result=" << rowText.find(comparedString) << endl;
        if (rowText.find(comparedString) == 0)
        {
            break;
        }
    }

    if (testedRow == NULL)
    {
        cout << "this letter is not in listbox" << endl;
    }
    else
    {
        cout << "fist row with letter " << comparedString << " is at row " << index << endl;


        //FOCUS at row index
    }

    return TRUE;
}

static void appActivate (GApplication *app, gpointer user_data) {
    GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
    gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);

    GtkWidget  *hBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,10);
    gtk_box_set_homogeneous(GTK_BOX(hBox),true);
    gtk_window_set_child (GTK_WINDOW (win), hBox);

    GtkWidget *skrollBox = gtk_scrolled_window_new();
    gtk_box_append (GTK_BOX (hBox), skrollBox);

    lBox = gtk_list_box_new();
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW (skrollBox), lBox);
    gtk_list_box_set_selection_mode (GTK_LIST_BOX(lBox), GTK_SELECTION_MULTIPLE);

    //prepare many rows in list box
    vector<string> startLetter = {"x", "a", "r" ,"B", "g", "c"};
    for ( unsigned int x =0; x < startLetter.size(); ++x )
    {
        for (int i = 0; i < 40; i++) {
            string  jmeno = startLetter.at(x) + "test " + to_string(i);
            GtkWidget* lab = gtk_label_new(jmeno.c_str());
            gtk_list_box_append(GTK_LIST_BOX(lBox),  lab);
        }
    }

    //key shortcut
    GtkEventController *event_controller = gtk_event_controller_key_new ();
    g_signal_connect_object (event_controller, "key-pressed", G_CALLBACK (keyPress), NULL, G_CONNECT_SWAPPED);
    gtk_widget_add_controller (GTK_WIDGET (win), event_controller);
    //end - key shortcut

    gtk_widget_show (win);
}


int main(int argc, char **argv) {
    GtkApplication *app;
    app = gtk_application_new ("testing.app", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (appActivate), NULL);
    return g_application_run (G_APPLICATION (app), NULL, NULL);
    g_object_unref (app);

    return 0;
}

If what you want is to highlight a row of the ListBox you can apply select_row.

Another option (which I don’t know if it’s useful for your project) is to set a GtkListBoxFilterFunc with set_filter_func to display, for example, all rows starting with ‘a’ or the key you press.

thank you for reply.
I do not neet selecting but I would like to list box alone scroll down to show certain row

It sounds like using GtkWidget.grab_focus() on the row you are interested in would do what you want.

I understand, what you need is to change the GtkAdjustment value of the listbox to position it at the row.

Changing the focus does not move the scrolled :confused:

thank you! it is working, I added into function keyPress:

else
    {
        cout << "fist row with letter " << comparedString << " is at row " << index << endl;

        //FOCUS at row index

        gtk_widget_grab_focus(GTK_WIDGET(testedRow));
    }

and list box is moved to the first row which start with pressed letter.
Thank you

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