GTK+ 示例/树视图/DnD
本节比其他任何部分都需要修改。如果您了解有关树视图拖放的任何信息,您可能比本文作者更了解。在这种情况下,请提供一些反馈。
如果您想深入了解树视图拖放,您可能想查看 Owen Taylor 关于此主题的邮件。它可能与实际实现的内容不完全相同,但它提供了很好的概述,并提供了比文档更多信息。
除了与任何窗口小部件一起使用的标准 Gtk+ 拖放机制外,还有专门用于树视图窗口小部件的特殊拖放机制。您通常希望使用特定于树视图的拖放框架。
从树视图窗口小部件中拖放一般信息或拖放到树视图窗口小部件中,与其他任何窗口小部件的工作方式相同,并且涉及标准的 Gtk+ 拖放机制。如果您使用此功能,您可以接收从树视图中的任何位置(包括空部分)拖放到该位置,或从该位置启动拖放操作。这不是特定于行或列的,很可能不是您想要的。然而,这是一个树视图的小示例,您可以在其中从其他应用程序(例如浏览器)拖放 URI,并将拖放的 URI 附加到列表中(请注意,通常您可能更愿意将整个窗口设置为目标,而不仅仅是树视图窗口小部件)。
#include <gtk/gtk.h>
enum
{
COL_URI = 0,
NUM_COLS
} ;
void
view_onDragDataReceived(GtkWidget *wgt, GdkDragContext *context, int x, int y,
GtkSelectionData *seldata, guint info, guint time,
gpointer userdata)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = GTK_TREE_MODEL(userdata);
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_URI, (gchar*)seldata->data, -1);
}
static GtkWidget *
create_view_and_model (void)
{
GtkTreeViewColumn *col;
GtkCellRenderer *renderer;
GtkListStore *liststore;
GtkWidget *view;
liststore = gtk_list_store_new(NUM_COLS, G_TYPE_STRING);
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
g_object_unref(liststore); /* destroy model with view */
col = gtk_tree_view_column_new();
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_set_title(col, "URI");
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
gtk_tree_view_column_pack_start(col, renderer, TRUE);
gtk_tree_view_column_add_attribute(col, renderer, "text", COL_URI);
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
GTK_SELECTION_SINGLE);
/* Make tree view a destination for Drag'n'Drop */
if (1)
{
enum
{
TARGET_STRING,
TARGET_URL
};
static GtkTargetEntry targetentries[] =
{
{ "STRING", 0, TARGET_STRING },
{ "text/plain", 0, TARGET_STRING },
{ "text/uri-list", 0, TARGET_URL },
};
gtk_drag_dest_set(view, GTK_DEST_DEFAULT_ALL, targetentries, 3,
GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK);
g_signal_connect(view, "drag_data_received",
G_CALLBACK(view_onDragDataReceived), liststore);
}
return view;
}
int
main (int argc, char **argv)
{
GtkWidget *window, *vbox, *view, *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "delete_event", gtk_main_quit, NULL); /* dirty */
gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
label = gtk_label_new("\nDrag and drop links from your browser into the tree view.\n");
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
view = create_view_and_model();
gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
如果您接收拖放到树视图中,您可以连接到视图的“drag-motion”信号以跟踪鼠标指针,同时它在树视图上的拖放操作中。这对于例如当鼠标在拖放操作期间在节点上悬停一段时间时,您希望展开树中折叠的节点时非常有用。这是一个实现此目的的示例。
/***************************************************************************
*
* onDragMotion_expand_timeout
*
* Timeout used to make sure that we expand rows only
* after hovering about them for a certain amount
* of time while doing Drag'n'Drop
*
***************************************************************************/
gboolean
onDragMotion_expand_timeout (GtkTreePath **path)
{
g_return_val_if_fail ( path != NULL, FALSE );
g_return_val_if_fail ( *path != NULL, FALSE );
gtk_tree_view_expand_row(GTK_TREE_VIEW(view), *path, FALSE);
return FALSE; /* only call once */
}
/***************************************************************************
*
* view_onDragMotion: we don't want to expand unexpanded nodes
* immediately when the mouse pointer passes across
* them during DnD. Instead, we only want to expand
* the node if the pointer has been hovering above the
* node for at least 1.5 seconds or so. To achieve this,
* we use a timeout that is removed whenever the row
* in focus changes.
*
***************************************************************************/
static gboolean
view_onDragMotion (GtkWidget *widget, GdkDragContext *context, gint x,
gint y, guint time, gpointer data)
{
static GtkTreePath *lastpath; /* NULL */
GtkTreePath *path = NULL;
if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), x, y, &path, NULL, NULL, NULL))
{
if (!lastpath || ((lastpath) && gtk_tree_path_compare(lastpath, path) != 0))
{
(void) g_source_remove_by_user_data(&lastpath);
if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
{
/* 1500 = 1.5 secs */
g_timeout_add(1500, (GSourceFunc) onDragMotion_expand_timeout, &lastpath);
}
}
}
else
{
g_source_remove_by_user_data(&lastpath);
}
if (lastpath)
gtk_tree_path_free(lastpath);
lastpath = path;
return TRUE;
}
连接到视图的“drag-drop”信号,以便在发生拖放时调用它。您可以使用 gtk_tree_view_get_path_at_pos 将提供的坐标转换为树路径。
GtkListStore 和 GtkTreeStore 都实现了 GtkTreeDragDest 和 GtkTreeDragSource 接口,这意味着它们内置支持行重新排序。您需要调用 gtk_tree_view_set_reorderable 来激活此功能,然后连接到树模型的信号以捕获发生的重新排序操作。
以下示例所示
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DESCRIPTION "Drag and Drop within a Treeview - by Pierre-Louis Malatray"
/* Row data structure */
struct DATA {
char *row;
char *item;
int qty;
float price;
};
/* A convenience enumerator to tag data types */
enum {
TARGET_STRING,
TARGET_INTEGER,
TARGET_FLOAT
};
/* A convenience enumerator to count the columns */
enum {
ROW_COL=0,
ITEM_COL,
QTY_COL,
PRICE_COL,
NUM_COLS
};
/* Some sample data for treeview 1. A NULL row is added so we dont
need to pass around the size of the array */
static struct DATA row_data[] = {
{ "row0","item 12", 3, 4.3 },
{ "row1","item 23", 44,34.4},
{ "row2","item 33", 34,25.4},
{ "row3","item 43", 37,64.4},
{ "row4","item 53", 12,14.4},
{ "row5","item 68", 42,34.4},
{ "row6","item 75", 72,74.4},
{NULL}
};
gboolean dndactive = FALSE;
/* Convenience function to deallocated memory used for DATA struct */
void free_DATA(struct DATA *data){
if(data){
free(data->row);
free(data->item);
}
free(data);
}
/* Convenience function to print out the contents of a DATA struct onto stdout */
void print_DATA(struct DATA *data){
printf("DATA @ %p\n",data);
printf(" |->row = %s\n",data->row);
printf(" |->item = %s\n",data->item);
printf(" |->qty = %i\n",data->qty);
printf(" +->price = %f\n",data->price);
}
void on_drag_data_deleted(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
{
/* useless for DnD operations */
printf("on_drag_data_deleted\n");
}
void on_drag_data_inserted(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
{
printf("on_drag_data_inserted\n");
/* activate DnD operation */
dndactive = TRUE;
}
void on_drag_data_changed(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
{
/* Always initialise a GValue with 0 */
GValue value={0,};
char *cptr, *spath;
gint prof;
printf("on_drag_data_changed\n");
if (!dndactive) {
/* No DnD active here */
printf("on_drag_data_changed : DND off\n");
return;
}
/* Manage DnD operation */
/* Get the GValue of a particular column from the row, the iterator currently points to*/
gtk_tree_model_get_value(tree_model, iter, ROW_COL, &value);
cptr = (char*) g_value_get_string(&value);
spath = gtk_tree_path_to_string(path);
prof = gtk_tree_path_get_depth(path);
printf("on_drag_data_changed : cell=%s, path=%s, prof=%d\n", cptr, spath, prof);
g_value_unset(&value);
}
/* Creates a scroll window, puts a treeview in it and populates it */
GtkWidget *add_treeview(GtkWidget *box, struct DATA array[])
{
GtkWidget *swindow;
GtkWidget *tree_view;
GtkTreeStore *tree_store;
GtkTreeModel *tree_model;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
int i;
char column_names[NUM_COLS][16] = {"Row #", "Description", "Qty", "Price"};
swindow = gtk_scrolled_window_new(NULL, NULL);
/* Both Vertical and Horizontal scroll set to Auto (NULL) */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow),
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
/* Add this window to the box */
gtk_box_pack_start(GTK_BOX(box),swindow,TRUE,TRUE,2);
/* Create the treeview and its tree store */
tree_store = gtk_tree_store_new(NUM_COLS,
G_TYPE_STRING,G_TYPE_STRING,G_TYPE_INT,G_TYPE_FLOAT);
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
/* Add the treeview to the scrolled window */
gtk_container_add(GTK_CONTAINER(swindow), tree_view);
/* Add the columns */
for(i = 0; i < 4; i++) {
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes (
column_names[i],renderer,"text",i,NULL);
gtk_tree_view_column_set_sort_column_id (column, i);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree_view), column);
}
/* Tell the theme engine we would like differentiated row colour */
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_view),TRUE);
/* Add the data */
GtkTreeIter iter;
i = 0;
while(array[++i].row != NULL) {
gtk_tree_store_append(tree_store, &iter, NULL);
gtk_tree_store_set(tree_store, &iter,
ROW_COL,array[i].row,
ITEM_COL,array[i].item,
QTY_COL,array[i].qty,
PRICE_COL,array[i].price,-1);
}
/* Prepare treeview for DnD facility */
/* Set treeview reorderable */
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree_view), TRUE);
/* Get treeview model to connect events on it */
tree_model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
// Attach a "drag-data-deleted" signal - useless here
g_signal_connect(GTK_WIDGET(tree_model),"row-deleted", G_CALLBACK(on_drag_data_deleted), NULL);
// Attach a "drag-data-inserted" signal to start DnD operation
g_signal_connect(GTK_WIDGET(tree_model), "row-inserted", G_CALLBACK(on_drag_data_inserted), NULL);
// Attach a "drag-data-changed" signal to manage data
g_signal_connect(GTK_WIDGET(tree_model), "row-changed", G_CALLBACK(on_drag_data_changed), NULL);
return tree_view;
}
int main(int argc, char **argv)
{
GtkWidget *window;
GtkTreeModel *model;
gtk_init(&argc,&argv);
/* Create the top level window and setup the quit callback */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),666,266);
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_exit),NULL);
/* Build up the GUI with some boxes */
GtkWidget *vbox = gtk_vbox_new(FALSE,10);
gtk_container_add(GTK_CONTAINER(window),vbox);
/* Add a title */
GtkWidget *title = gtk_label_new(DESCRIPTION);
gtk_box_pack_start(GTK_BOX(vbox),title,FALSE,FALSE,1);
GtkWidget *hbox = gtk_hbox_new(TRUE,1);
gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,1);
/* Create treeview */
GtkWidget *view1;
view1 = add_treeview(hbox, row_data);
/* Rock'n Roll */
gtk_widget_show_all(window);
gtk_main();
return 0;
}
编译
gcc -g `pkg-config --cflags --libs gtk+-2.0` -o DnD_Example example.c
这实际上比设置来自任意来源的拖放功能要容易得多。数据通过 GtkSelectionData 对象从一个树视图传递到另一个树视图。把它想象成一个邮箱。当发出“drag-data-get”时,您将一些东西放入其中,当发出“drag-data-received”时,您取出您的东西。
以下示例是使用许多不同的来源放在一起的,但基本设计来自 php-gtk2 食谱文章
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DESCRIPTION "Drag and Drop Between 2 Treeviews - by Vikram Ambrose"
/* Row data structure */
struct DATA {
char *row;
char *item;
int qty;
float price;
};
/* A convenience enumerator to tag data types */
enum {
TARGET_STRING,
TARGET_INTEGER,
TARGET_FLOAT
};
/* A convenience enumerator to count the columns */
enum {
ROW_COL=0,
ITEM_COL,
QTY_COL,
PRICE_COL,
NUM_COLS
};
/* Some sample data for treeview 1. A NULL row is added so we dont
need to pass around the size of the array */
static struct DATA row_data[] = {
{ "row0","item 12", 3, 4.3 },
{ "row1","item 23", 44,34.4},
{ "row2","item 33", 34,25.4},
{ "row3","item 43", 37,64.4},
{ "row4","item 53", 12,14.4},
{ "row5","item 68", 42,34.4},
{ "row6","item 75", 72,74.4},
{NULL}
};
/* Sample data for treeview 2 */
static struct DATA row2_data[] = {
{"row7", "item 127", 105, 115.5},
{"row8","item 124", 117, 118.6},
{"row9", "item 123", 120, 121.73},
{NULL}
};
static const GtkTargetEntry drag_targets = {
"STRING", GTK_TARGET_SAME_APP,TARGET_STRING
};
static guint n_targets = 1;
/* Could be used instead, if GtkTargetEntry had more than one row */
//static guint n_targets = G_N_ELEMENTS (drag_targets);
/* Convenience function to deallocated memory used for DATA struct */
void free_DATA(struct DATA *data){
if(data){
free(data->row);
free(data->item);
}
free(data);
}
/* Convenience function to print out the contents of a DATA struct onto stdout */
void print_DATA(struct DATA *data){
printf("DATA @ %p\n",data);
printf(" |->row = %s\n",data->row);
printf(" |->item = %s\n",data->item);
printf(" |->qty = %i\n",data->qty);
printf(" +->price = %f\n",data->price);
}
/* User callback for "get"ing the data out of the row that was DnD'd */
void on_drag_data_get( GtkWidget *widget, GdkDragContext *drag_context,
GtkSelectionData *sdata, guint info, guint time,
gpointer user_data){
GtkTreeIter iter;
GtkTreeModel *list_store;
GtkTreeSelection *selector;
gboolean rv;
printf("on_drag_data_get: ");
/* Get the selector widget from the treeview in question */
selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
/* Get the tree model (list_store) and initialise the iterator */
rv = gtk_tree_selection_get_selected(selector,&list_store,&iter);
/* This shouldn't really happen, but just in case */
if(rv==FALSE){
printf(" No row selected\n");
return;
}
/* Always initialise a GValue with 0 */
GValue value={0,};
char *cptr;
/* Allocate a new row to send off to the other side */
struct DATA *temp = malloc(sizeof(struct DATA));
/* Go through the columns */
/* Get the GValue of a particular column from the row, the iterator currently points to*/
gtk_tree_model_get_value(list_store,&iter,ROW_COL,&value);
cptr = (char*) g_value_get_string(&value);
temp->row = malloc(strlen(cptr)*sizeof(char)+1);
strcpy(temp->row,cptr);
g_value_unset(&value);
gtk_tree_model_get_value(list_store,&iter,ITEM_COL,&value);
cptr = (char*)g_value_get_string(&value);
temp->item = malloc(strlen(cptr)*sizeof(char)+1);
strcpy(temp->item,cptr);
g_value_unset(&value);
gtk_tree_model_get_value(list_store,&iter,QTY_COL,&value);
temp->qty = g_value_get_int(&value);
g_value_unset(&value);
gtk_tree_model_get_value(list_store,&iter,PRICE_COL,&value);
temp->price = g_value_get_float(&value);
g_value_unset(&value);
/* Send the data off into the GtkSelectionData object */
gtk_selection_data_set(sdata,
gdk_atom_intern ("struct DATA pointer", FALSE),
8, /* Tell GTK how to pack the data (bytes) */
(void *)&temp, /* The actual pointer that we just made */
sizeof (temp)); /* The size of the pointer */
/* Just print out what we sent for debugging purposes */
print_DATA(temp);
}
/* User callback for putting the data into the other treeview */
void on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context,
gint x, gint y, GtkSelectionData *sdata, guint info,
guint time, gpointer user_data){
GtkTreeModel *list_store;
GtkTreeIter iter;
printf("on_drag_data_received:\n");
/* Remove row from the source treeview */
GtkTreeSelection *selector;
selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data));
gtk_tree_selection_get_selected(selector,&list_store,&iter);
gtk_list_store_remove(GTK_LIST_STORE(list_store),&iter);
/* Now add to the other treeview */
GtkTreeModel *list_store2;
GtkTreeIter iter2;
list_store2 = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
gtk_list_store_append(GTK_LIST_STORE(list_store2),&iter2);
/* Copy the pointer we received into a new struct */
struct DATA *temp = NULL;
const guchar *my_data = gtk_selection_data_get_data (sdata);
memcpy (&temp, my_data, sizeof (temp));
/* Add the received data to the treeview model */
gtk_list_store_set(GTK_LIST_STORE(list_store2),&iter2,
ROW_COL,temp->row,
ITEM_COL,temp->item,
QTY_COL,temp->qty,
PRICE_COL,temp->price,-1);
/* We dont need this anymore */
free_DATA(temp);
}
/* User callback just to see which row was selected, doesnt affect DnD.
However it might be important to note that this signal and drag-data-received may occur at the same time. If you drag a row out of one view, your selection changes too */
void on_selection_changed (GtkTreeSelection *treeselection,gpointer user_data){
GtkTreeIter iter;
GtkTreeModel *list_store;
gboolean rv;
printf("on_selection_changed: ");
rv = gtk_tree_selection_get_selected(treeselection,
&list_store,&iter);
/* "changed" signal sometimes fires blanks, so make sure we actually
have a selection/
http://library.gnome.org/devel/gtk/stable/GtkTreeSelection.html#GtkTreeSelection-changed */
if (rv==FALSE){
printf("No row selected\n");
return;
}
GValue value={0,};
char *cptr;
int i;
/* Walk throw the columns to see the row data */
for(i=0;i<NUM_COLS;i++){
gtk_tree_model_get_value(list_store,&iter,i,&value);
cptr = (gchar *) g_strdup_value_contents (&value);
g_value_unset(&value);
if(cptr)printf("%s|",cptr);
free(cptr);
}
printf("\n");
}
/* Creates a scroll windows, puts a treeview in it and populates it */
GtkWidget *add_treeview(GtkWidget *box, struct DATA array[]){
GtkWidget *swindow;
swindow = gtk_scrolled_window_new(NULL,NULL);
/* Both Vertical and Horizontal scroll set to Auto (NULL) */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow),
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
/* Add this window to the box */
gtk_box_pack_start(GTK_BOX(box),swindow,TRUE,TRUE,2);
/* Create the treeview and its list store */
GtkListStore *list_store;
list_store = gtk_list_store_new(NUM_COLS,
G_TYPE_STRING,G_TYPE_STRING,G_TYPE_INT,G_TYPE_FLOAT);
GtkWidget *tree_view;
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
/* Add the treeview to the scrolled window */
gtk_container_add(GTK_CONTAINER(swindow),tree_view);
/* Add the columns */
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
char column_names[NUM_COLS][16] = {
"Row #", "Description", "Qty", "Price"};
int i;
for(i=0;i<4;i++){
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes (
column_names[i],renderer,"text",i,NULL);
gtk_tree_view_column_set_sort_column_id (column, i);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree_view), column);
}
/* Tell the theme engine we would like differentiated row colour */
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_view),TRUE);
/* Add the data */
GtkTreeIter iter;
i=0;
while(array[++i].row!=NULL){
gtk_list_store_append(list_store,&iter);
gtk_list_store_set(list_store,&iter,
ROW_COL,array[i].row,
ITEM_COL,array[i].item,
QTY_COL,array[i].qty,
PRICE_COL,array[i].price,-1);
}
/* Attach the "changed" callback onto the tree's selector */
g_signal_connect(
gtk_tree_view_get_selection (GTK_TREE_VIEW(tree_view)),
"changed",G_CALLBACK(on_selection_changed),NULL);
return tree_view;
}
int main(int argc, char **argv){
GtkWidget *window;
gtk_init(&argc,&argv);
/* Create the top level window and setup the quit callback */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),666,266);
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(exit),NULL);
/* Build up the GUI with some boxes */
GtkWidget *vbox = gtk_vbox_new(FALSE,10);
gtk_container_add(GTK_CONTAINER(window),vbox);
/* Add a title */
GtkWidget *title = gtk_label_new(DESCRIPTION);
gtk_box_pack_start(GTK_BOX(vbox),title,FALSE,FALSE,1);
GtkWidget *hbox = gtk_hbox_new(TRUE,1);
gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,1);
/* Create treeview 1 */
GtkWidget *view1;
view1 = add_treeview(hbox,row_data);
/* Set treeview 1 as the source of the Drag-N-Drop operation */
gtk_drag_source_set(view1,GDK_BUTTON1_MASK, &drag_targets,n_targets,
GDK_ACTION_COPY|GDK_ACTION_MOVE);
/* Attach a "drag-data-get" signal to send out the dragged data */
g_signal_connect(view1,"drag-data-get",
G_CALLBACK(on_drag_data_get),NULL);
/* Create treeview 2 */
GtkWidget *view2;
view2 = add_treeview(hbox,row2_data);
/* Set treeview 2 as the destination of the Drag-N-Drop operation */
gtk_drag_dest_set(view2,GTK_DEST_DEFAULT_ALL,&drag_targets,n_targets,
GDK_ACTION_COPY|GDK_ACTION_MOVE);
/* Attach a "drag-data-received" signal to pull in the dragged data */
g_signal_connect(view2,"drag-data-received",
G_CALLBACK(on_drag_data_received),view1);
/* Rock'n Roll */
gtk_widget_show_all(window);
gtk_main();
return 0;
}
编译
gcc -g example.c `pkg-config --cflags --libs gtk+-2.0` -o DnD_Example
GTK 通过 GtkSelectionData 支持大量数据类型。但在本例中,我们只发送一个指针的值。一个指向行数据结构的指针,该结构包含填充目标树视图所需的所有数据。