You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决GtkListView设置默认选中项后无法自动滚动的问题?

解决GtkListView设置默认选中项后无法自动滚动的问题

问题原因

你绑定的show信号触发时机过早,此时GtkListView尚未完成布局计算,滚动操作无法正确定位到目标项;同时原代码中创建的GtkScrollInfo未释放,存在内存泄漏。

解决方案

1. 修复内存泄漏

在scroll_set函数末尾添加GObject资源释放代码:

static void
scroll_set(GtkListView *listview, gpointer user_data)
{
  GtkScrollInfo *scrinfo = gtk_scroll_info_new ();
  gtk_scroll_info_set_enable_vertical (scrinfo, TRUE);
  gtk_list_view_scroll_to (listview, 10, GTK_LIST_SCROLL_FOCUS, scrinfo);
  g_object_unref(scrinfo); // 释放创建的GtkScrollInfo资源
}

2. 延迟执行滚动操作

将原代码中绑定show信号的代码,替换为使用g_idle_add延迟执行滚动,确保UI完成布局后再触发滚动逻辑:

// 替换原有的 g_signal_connect(lv, "show", G_CALLBACK(scroll_set), NULL);
g_idle_add((GSourceFunc)scroll_set, lv);

修改后的完整代码

#include <gtk/gtk.h>
static void
setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data)             
{
  GtkWidget *lb = gtk_label_new (NULL);
  gtk_list_item_set_child (listitem, lb);
}

static void
bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
  GtkWidget *lb = gtk_list_item_get_child (listitem);
  GtkStringObject *strobj = gtk_list_item_get_item (listitem);
  gtk_label_set_text (GTK_LABEL (lb), gtk_string_object_get_string (strobj));
}

static void
scroll_set(GtkListView *listview, gpointer user_data)
{
  GtkScrollInfo *scrinfo = gtk_scroll_info_new ();
  gtk_scroll_info_set_enable_vertical (scrinfo, TRUE);
  gtk_list_view_scroll_to (listview, 10, GTK_LIST_SCROLL_FOCUS, scrinfo);
  g_object_unref(scrinfo);
}


static void
app_activate (GApplication *application) {
  GtkApplication *app = GTK_APPLICATION (application);
  GtkWidget *win = gtk_application_window_new (app);
  gtk_window_set_default_size (GTK_WINDOW (win), 200, 100);
  GtkWidget *scr = gtk_scrolled_window_new ();
  gtk_window_set_child (GTK_WINDOW (win), scr);

  char *array[] = {
    "one", "two", "three", "four", "five" ,"six"," seven", 
    "eight" ,"nine", "ten", "eleven", "twelve", "thirteen",NULL
  };

  GtkWidget *lv = gtk_list_view_new(NULL,NULL); 

  GtkStringList *sl =  gtk_string_list_new ((const char * const *) array);
  GtkSingleSelection *selection = gtk_single_selection_new(G_LIST_MODEL(sl));
  gtk_single_selection_set_autoselect(selection, TRUE);
  gtk_list_view_set_model(GTK_LIST_VIEW(lv),GTK_SELECTION_MODEL(selection));

  GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
  g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
  g_signal_connect (factory, "bind", G_CALLBACK (bind_cb), NULL);

  gtk_list_view_set_factory (GTK_LIST_VIEW (lv),factory);
  gtk_single_selection_set_selected ((GtkSingleSelection *)selection, 10);

  gtk_widget_set_visible(lv, TRUE);
  
  // 延迟执行滚动操作,确保布局完成
  g_idle_add((GSourceFunc)scroll_set, lv);

  gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
  gtk_window_present (GTK_WINDOW (win));
}


int
main (int argc, char **argv) {
  GtkApplication *app;
  int stat;
  app = gtk_application_new ("com.gtk.listview.test", G_APPLICATION_DEFAULT_FLAGS);
  g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
  stat =g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);
 return stat;
}

额外说明

如果你的GTK版本≥4.14,可以直接使用gtk_list_view_scroll_to_selected()函数替代手动指定位置,代码会更简洁:

static void
scroll_set(GtkListView *listview, gpointer user_data)
{
  GtkScrollInfo *scrinfo = gtk_scroll_info_new ();
  gtk_scroll_info_set_enable_vertical (scrinfo, TRUE);
  gtk_list_view_scroll_to_selected (listview, GTK_LIST_SCROLL_FOCUS, scrinfo);
  g_object_unref(scrinfo);
}

内容的提问来源于stack exchange,提问作者dibyendu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:55:13