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

如何用Vala/C创建可按需拖拽的Gtk4 GridView图片组件?

创建可动态控制拖拽的GtkGridView(纯C代码,无UI文件)

假设你用的是GTK4(C语言桌面UI开发最常用的库),下面直接给可运行的示例代码,同时拆解构造参数的核心逻辑:

核心参数说明

GtkGridView的构造只需要两个必填参数:

  • model:存储图片数据的列表模型(比如GListStore),负责提供要展示的内容
  • factory:列表项工厂(GtkSignalListItemFactory),定义每个网格项的UI渲染逻辑和交互行为

拖拽控制可以通过在工厂的绑定阶段,根据上下文数据动态开启/关闭拖拽功能实现。

完整示例代码

#include <gtk/gtk.h>

// 自定义数据结构:存储图片路径和是否可拖拽的标志
typedef struct {
    gchar *image_path;
    gboolean draggable;
} ImageItem;

// 释放自定义数据的函数
static void image_item_free(gpointer data) {
    ImageItem *item = data;
    g_free(item->image_path);
    g_free(item);
}

// 列表项工厂的setup函数:创建网格项的基础UI
static void list_item_setup(GtkSignalListItemFactory *factory, GtkListItem *list_item) {
    // 创建图片部件
    GtkWidget *image = gtk_picture_new();
    gtk_picture_set_content_fit(GTK_PICTURE(image), GTK_CONTENT_FIT_COVER);
    gtk_widget_set_hexpand(image, TRUE);
    gtk_widget_set_vexpand(image, TRUE);
    
    // 将图片设为列表项的子部件
    gtk_list_item_set_child(list_item, image);
}

// 列表项工厂的bind函数:绑定数据到UI,并动态控制拖拽
static void list_item_bind(GtkSignalListItemFactory *factory, GtkListItem *list_item) {
    ImageItem *item = gtk_list_item_get_item(list_item);
    GtkWidget *image = gtk_list_item_get_child(list_item);
    
    // 设置图片路径
    gtk_picture_set_filename(GTK_PICTURE(image), item->image_path);
    
    // 先移除已有的拖拽源(防止重复绑定)
    GtkDragSource *existing_drag = g_object_get_data(G_OBJECT(image), "drag-source");
    if (existing_drag) {
        gtk_widget_remove_controller(GTK_WIDGET(image), GTK_EVENT_CONTROLLER(existing_drag));
        g_object_unref(existing_drag);
        g_object_set_data(G_OBJECT(image), "drag-source", NULL);
    }
    
    // 根据上下文决定是否开启拖拽
    if (item->draggable) {
        // 创建拖拽源
        GtkDragSource *drag_source = gtk_drag_source_new();
        gtk_drag_source_set_actions(drag_source, GDK_ACTION_COPY);
        
        // 设置拖拽内容(这里简单传图片路径)
        g_signal_connect(drag_source, "prepare", G_CALLBACK(
            (GCallback)gtk_drag_source_set_content), g_strdup(item->image_path));
        
        // 将拖拽源添加到图片部件
        gtk_widget_add_controller(GTK_WIDGET(image), GTK_EVENT_CONTROLLER(drag_source));
        g_object_set_data(G_OBJECT(image), "drag-source", drag_source);
    }
}

int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);
    
    // 1. 创建窗口
    GtkWidget *window = gtk_application_window_new();
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
    gtk_window_set_title(GTK_WINDOW(window), "可拖拽图片GridView");
    
    // 2. 创建列表模型,添加测试数据
    GListStore *store = g_list_store_new(G_TYPE_POINTER);
    // 添加可拖拽的图片
    ImageItem *item1 = g_new(ImageItem, 1);
    item1->image_path = g_strdup("/path/to/your/image1.jpg");
    item1->draggable = TRUE;
    g_list_store_append(store, item1);
    // 添加不可拖拽的图片
    ImageItem *item2 = g_new(ImageItem, 1);
    item2->image_path = g_strdup("/path/to/your/image2.jpg");
    item2->draggable = FALSE;
    g_list_store_append(store, item2);
    // 添加更多测试项...
    
    // 3. 创建列表项工厂
    GtkSignalListItemFactory *factory = gtk_signal_list_item_factory_new();
    g_signal_connect(factory, "setup", G_CALLBACK(list_item_setup), NULL);
    g_signal_connect(factory, "bind", G_CALLBACK(list_item_bind), NULL);
    
    // 4. 创建GridView
    GtkWidget *grid_view = gtk_grid_view_new(G_LIST_MODEL(store), factory);
    // 设置列数自适应
    gtk_grid_view_set_max_columns(GTK_GRID_VIEW(grid_view), 3);
    gtk_grid_view_set_min_columns(GTK_GRID_VIEW(grid_view), 1);
    
    // 5. 添加滚动容器(GridView需要放在滚动窗里)
    GtkWidget *scrolled_window = gtk_scrolled_window_new();
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolled_window), grid_view);
    gtk_window_set_child(GTK_WINDOW(window), scrolled_window);
    
    // 窗口关闭时释放数据
    g_signal_connect(window, "destroy", G_CALLBACK(
        (GCallback)g_list_store_foreach), image_item_free);
    g_signal_connect(window, "destroy", G_CALLBACK(g_object_unref), store);
    
    // 显示窗口并启动主循环
    gtk_widget_show(window);
    gtk_main();
    
    return 0;
}

关键逻辑说明

  1. 数据结构:用ImageItem存储图片路径和draggable标志,你可以根据实际上下文(比如用户权限、当前场景)动态修改这个标志
  2. 拖拽控制:在list_item_bind函数中,根据draggable值决定是否为图片添加GtkDragSource,实现动态开关拖拽
  3. 构造参数:gtk_grid_view_new只需要传入模型和工厂,其他属性(比如列数)可以后续通过setter函数配置

编译运行

将代码保存为gridview_drag.c,然后用以下命令编译(确保已安装GTK4开发库):

gcc -o gridview_drag gridview_drag.c `pkg-config --cflags --libs gtk4`

运行时替换代码中的图片路径为你本地的图片路径即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:42:30