Search code examples
cgtkgtk3gdkgtkscrolledwindow

How to Scroll a ScrolledWindow with arrow keys in Gtk 3.24.5?


I have a gtk entry right below the scrolled window which has the default focus , left and right keys move the cursor in the entry ,I am able to catch the key press events for up and down arrow keys but don't know how to scroll the scrolled window, referred many websites none of them were clear or explained only in parts.

Below are some of the pages I went through: https://mail.gnome.org/archives/gtk-devel-list/2002-February/msg00104.html

https://developer.gnome.org/gtkmm-tutorial/stable/sec-keyboardevents-overview.html.en

tried using gtk_scrolled_window_set_vadjustment() couldn't get it working. The official page says GTK_SCROLL_STEP_UP is deprecated but doesn't say what should be used instead.

Every answer would be very appreciated.Thanks

bool Method::cb_MPWindow(GtkWidget *wgt, GdkEventKey *event, MethodSelect *ms)
{
    if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down)
    {  
  
        g_signal_emit_by_name(ms->ScrolledWindow, "scroll-child",(event->keyval == GDK_KEY_Up)?GTK_SCROLL_STEP_UP:GTK_SCROLL_STEP_DOWN);
//The above line works in gtk 3.14.5 but crashes the app in 3.24.5 
        return TRUE;
    }

    return FALSE;
}

Solution

  • In order to scroll the window with the keyboard, you need to:

    • Get the scrolled window's vertical or horizontal adjustment with gtk_scrolled_window_get_vadjustment() or gtk_scrolled_window_get_hadjustment().
    • From the adjustment object, get the following properties: value (the current scroll position), step-increment (how much to scroll by line), and page-increment (how much to scroll by page).
    • Then, according to the key that was pressed, you add or subtract the increment to value and then set the new value with gtk_adjustment_set_value().

    The the window will scroll when change when you set the value. Typically the line increment is used when navigating with the arrow keys, while the page increment when using the Page Up/Down keys. You add them when scrolling down, and subtract while scrolling down. It is worth noting that the increments change dynamically based on the window size, so you do not need to set them manually.

    Here is my code (in C). First setting up the callback:

    // Create a scrolled window
    GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
    
    // Get the vertical adjustment object
    GtkAdjustment *page_vertical_adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window));
    
    // Connect to the key press event
    g_signal_connect(
        GTK_SCROLLED_WINDOW(scrolled_window),
        "key-press-event",
        G_CALLBACK(keyboard_scrolling),
        page_vertical_adjustment
    );
    

    And then the callback function:

    void keyboard_scrolling(GtkScrolledWindow *widget, GdkEventKey event, GtkAdjustment *adjustment)
    {
        // Get the vertical position of the page
        gdouble position = gtk_adjustment_get_value(adjustment);
    
        // Get the scrolling increments
        gdouble step = gtk_adjustment_get_step_increment(adjustment);  // Amount to be scrolled by the arrows (roughly a line)
        gdouble page = gtk_adjustment_get_page_increment(adjustment);  // Amount to be scrolled by the Page keys (roughly the visible area)
    
        // printf("step: %f, page: %f, key: %d\n", step, page, event.keyval);
    
        // Check which key was pressed    
        switch (event.keyval)
        {
        case GDK_KEY_Page_Down:
            gtk_adjustment_set_value(adjustment, position + page);
            break;
        
        case GDK_KEY_Page_Up:
            gtk_adjustment_set_value(adjustment, position - page);
            break;
        
        case GDK_KEY_Down:
            gtk_adjustment_set_value(adjustment, position + step);
            break;
        
        case GDK_KEY_Up:
            gtk_adjustment_set_value(adjustment, position - step);
            break;
        
        default:
            break;
        }
    }
    

    For convenience, here is a list of keyboard macros that GTK accepts: https://github.com/GNOME/gtk/blob/main/gdk/gdkkeysyms.h