如何解决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
相关产品推荐
相关产品推荐

