GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

How to do the "add remove" thing?

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming
Author Message
days_of_ruin
Familiar Face


Joined: 19 May 2008
Posts: 7

PostPosted: Mon May 19, 2008 10:54 pm    Post subject: How to do the "add remove" thing? Reply with quote

The one with a square area which has a list of selectable text.
And on the side there are "add" and "remove" buttons and sometimes more.
Is this a single widget or not?Regardless I would be grateful if someone posted
an example:D

EDIT:oops wrong board!sorry
Back to top
Micah Carrick
Never Seen the Sunlight


Joined: 21 Sep 2005
Posts: 505
Location: Portland, OR USA

PostPosted: Mon Jun 02, 2008 7:33 pm    Post subject: Reply with quote

There is not a widget for this... I don't think. At least not built into GTK+.

All you need to do though, is pack 2 tree views on either side of a vertical button box. So basically you would have:

Code: (Plaintext)
1
2
3
4
5
6
GtkVBox
    GtkScrolledWindow
        GtkTreeView
    GtkVButtonBox
    GtkScrolledWindow
        GtkTreeView


The buttons you would do would likely have "Add" and "Remove" as text with GTK_STOCK_NEXT or GTK_STOCK_ADD as the image for the "Add" button and GTK_STOCK_BACK or GTK_STOCK_REMOVE as the image for the "Remove" button.

And you would likely just use a simple GtkListStore for the model of the tree views.
Back to top
Nameless
Familiar Face


Joined: 28 Jun 2008
Posts: 7

PostPosted: Mon Aug 25, 2008 5:37 pm    Post subject: Reply with quote

I'm also trying to do this (although I have already found the List Store and Tree View objects). Although I think I know how to add and remove objects from List Store objects, I am a little lost on how I will get which object the user selected so I can move it from one list to the other.
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 526
Location: Falun, WI USA

PostPosted: Mon Aug 25, 2008 8:24 pm    Post subject: Reply with quote

Here's an implementation of an add-remove widget.
it's in three files, a widget source file, a widget header file and the file demonstrating the widget.
If there's something that isn't clear, just ask and I'll explain it.

gtkaddremove.c:
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <gtk/gtk.h>
#include "gtkaddremove.h"

enum
{
    PROP_0 = 0,
    PROP_S_VIEW,
    PROP_D_VIEW,
};

G_DEFINE_TYPE(GtkAddRemove, gtk_add_remove, GTK_TYPE_HBOX)

static void gtk_add_remove_add_button_clicked(GtkButton *button, GtkAddRemove *ar);
static void gtk_add_remove_remove_button_clicked(GtkButton *button, GtkAddRemove *ar);

static void gtk_add_remove_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
    GtkAddRemove *ob = GTK_ADD_REMOVE(object);

    switch(prop_id)
    {
        case PROP_S_VIEW:
           
ob->s_view = g_value_get_object(value);
            break;
        case PROP_D_VIEW:
           
ob->d_view = g_value_get_object(value);
            break;
        default:
            g_warning("Invalid prop id");
            return;
    }
}

static void gtk_add_remove_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    GtkAddRemove *ob = GTK_ADD_REMOVE(object);

    switch(prop_id)
    {
        case PROP_S_VIEW:
           
g_value_set_object(value, ob->s_view);
            break;
        case PROP_D_VIEW:
           
g_value_set_object(value, ob->d_view);
            break;
        default:
            g_warning("Invalid prop id");
            return;
    }
}

static void gtk_add_remove_class_init(GtkAddRemoveClass *klass)
{
    GObjectClass *oclass;

    oclass = G_OBJECT_CLASS(klass);

    oclass->set_property = gtk_add_remove_set_property;
    oclass->get_property = gtk_add_remove_get_property;

    g_object_class_install_property(oclass, PROP_S_VIEW, g_param_spec_object("s-view",
                                                                                "Source View",
                                                                                "The GtkTreeView that holds the source items",
                                                                                GTK_TYPE_TREE_VIEW,
                                                                                G_PARAM_READABLE));
    g_object_class_install_property(oclass, PROP_D_VIEW, g_param_spec_object("d-view",
                                                                                "Destination View",
                                                                                "The GtkTreeView that holds the destination items",
                                                                                GTK_TYPE_TREE_VIEW,
                                                                                G_PARAM_READABLE));
}

static void gtk_add_remove_init(GtkAddRemove *ob)
{
    GtkCellRenderer *cell;
    GtkWidget *vbox;
    GtkWidget *button;
    GtkSizeGroup *sg;

    cell = gtk_cell_renderer_text_new();

    sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);

    /* left tree view */
   
ob->s_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtk_list_store_new(1, G_TYPE_STRING)));
    gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ob->s_view), -1, "Source", cell, "text", 0, NULL);
    gtk_box_pack_start(GTK_BOX(ob), ob->s_view, TRUE, TRUE, 0);
    gtk_widget_show(ob->s_view);
    gtk_size_group_add_widget(sg, ob->s_view);

    /* center pane */
   
vbox = gtk_vbutton_box_new();
    gtk_box_pack_start(GTK_BOX(ob), vbox, FALSE, FALSE, 0);
    gtk_button_box_set_layout(GTK_BUTTON_BOX(vbox), GTK_BUTTONBOX_CENTER);
    gtk_widget_show(vbox);

    button = gtk_button_new_from_stock(GTK_STOCK_ADD);
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_add_remove_add_button_clicked), (gpointer)ob);
    gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
    gtk_widget_show(button);

    button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_add_remove_remove_button_clicked), (gpointer)ob);
    gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, FALSE, 0);
    gtk_widget_show(button);

    /* right tree view */
   
ob->d_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtk_list_store_new(1, G_TYPE_STRING)));
    gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ob->d_view), -1, "Destination", cell, "text", 0, NULL);
    gtk_box_pack_start(GTK_BOX(ob), ob->d_view, TRUE, TRUE, 0);
    gtk_widget_show(ob->d_view);
    gtk_size_group_add_widget(sg, ob->d_view);
}

GtkWidget *gtk_add_remove_new(void)
{
    return g_object_new(GTK_TYPE_ADD_REMOVE, NULL);
}

gboolean gtk_add_remove_add_source(GtkAddRemove *ar, const gchar *text)
{
    GtkListStore *store;
    GtkTreeIter iter;

    g_return_val_if_fail(GTK_IS_ADD_REMOVE(ar), FALSE);

    store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ar->s_view)));

    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, 0, text, -1);

    return TRUE;
}

gboolean gtk_add_remove_add_destination(GtkAddRemove *ar, const gchar *text)
{
    GtkListStore *store;
    GtkTreeIter iter;

    g_return_val_if_fail(GTK_IS_ADD_REMOVE(ar), FALSE);

    store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ar->s_view)));

    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, 0, text, -1);

    return TRUE;
}

static void gtk_add_remove_add_button_clicked(GtkButton *button, GtkAddRemove *ar)
{
    GtkTreeSelection *sel;
    GtkTreeModel *model;
    GtkTreeIter iter;

    gchar *text;

    g_return_if_fail(GTK_IS_ADD_REMOVE(ar));

    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(ar->s_view));
    if(gtk_tree_selection_get_selected(sel, &model, &iter) == FALSE)
        return;

    gtk_tree_model_get(model, &iter, 0, &text, -1);
    gtk_list_store_remove(GTK_LIST_STORE(model), &iter);

    model = gtk_tree_view_get_model(GTK_TREE_VIEW(ar->d_view));
    gtk_list_store_append(GTK_LIST_STORE(model), &iter);
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, text, -1);
}

static void gtk_add_remove_remove_button_clicked(GtkButton *button, GtkAddRemove *ar)
{
    GtkTreeSelection *sel;
    GtkTreeModel *model;
    GtkTreeIter iter;

    gchar *text;

    g_return_if_fail(GTK_IS_ADD_REMOVE(ar));

    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(ar->d_view));
    if(gtk_tree_selection_get_selected(sel, &model, &iter) == FALSE)
        return;

    gtk_tree_model_get(model, &iter, 0, &text, -1);
    gtk_list_store_remove(GTK_LIST_STORE(model), &iter);

    model = gtk_tree_view_get_model(GTK_TREE_VIEW(ar->s_view));
    gtk_list_store_append(GTK_LIST_STORE(model), &iter);
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, text, -1);
}

gtkaddremove.h:
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef GTK_ADD_REMOVE_H_INCLUDED
#define GTK_ADD_REMOVE_H_INCLUDED

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define GTK_TYPE_ADD_REMOVE (gtk_add_remove_get_type())
#define GTK_ADD_REMOVE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GTK_TYPE_ADD_REMOVE, GtkAddRemove))
#define GTK_ADD_REMOVE_CLASS(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GTK_TYPE_ADD_REMOVE))
#define GTK_IS_ADD_REMOVE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GTK_TYPE_ADD_REMOVE))
#define GTK_IS_ADD_REMOVE_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE((o), GTK_TYPE_ADD_REMOVE))
#define GTK_ADD_REMOVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTK_TYPE_ADD_REMOVE, GtkAddRemoveClass))

typedef struct _GtkAddRemove GtkAddRemove;
typedef struct _GtkAddRemoveClass GtkAddRemoveClass;

struct _GtkAddRemove
{
    GtkHBox parent_instance;

    /* <private> */
   
GtkWidget *s_view;
    GtkWidget *d_view;
};

struct _GtkAddRemoveClass
{
    GtkHBoxClass parent_class;
};

GType gtk_add_remove_get_type(void);

GtkWidget *gtk_add_remove_new(void);

gboolean gtk_add_remove_add_source(GtkAddRemove *ar, const gchar *text);
gboolean gtk_add_remove_add_destination(GtkAddRemove *ar, const gchar *text);

G_END_DECLS

#endif /* GTK_ADD_REMOVE_H_INCLUDED */

main.c (example program):
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <gtk/gtk.h>

#include "gtkaddremove.h"

static const gchar *sources[] = {
    "Item 1",
    "Item 2",
    "Item 3",
    "Item 4",
    "Item 5",
    NULL,
};

int main(int argc, char **argv)
{
    GtkWidget *win;
    GtkWidget *ar;

    gint i;

    gtk_init(&argc, &argv);

    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(G_OBJECT(win), "delete-event", G_CALLBACK(gtk_main_quit), NULL);

    ar = gtk_add_remove_new();
    gtk_container_add(GTK_CONTAINER(win), ar);
    gtk_widget_show(ar);
    for(i = 0; sources[i] != NULL; i++)
        gtk_add_remove_add_source(GTK_ADD_REMOVE(ar), sources[i]);

    gtk_widget_show(win);

    gtk_main();

    return 0;
}
Back to top
Nameless
Familiar Face


Joined: 28 Jun 2008
Posts: 7

PostPosted: Mon Aug 25, 2008 10:17 pm    Post subject: Reply with quote

Thanks, will try that later.

Edit: I tried using some of your code in my program (mainly from gtk_add_remove_remove_button_clicked), and my problem is that this test always fails:

Code: (Plaintext)
1
2
 if(gtk_tree_selection_get_selected(sel, &model, &iter) == FALSE)
        return;


Any ideas why?
Back to top
Nameless
Familiar Face


Joined: 28 Jun 2008
Posts: 7

PostPosted: Tue Aug 26, 2008 9:12 am    Post subject: Reply with quote

Bump (because apparently my edit doesn't mark this thread as changed).
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 526
Location: Falun, WI USA

PostPosted: Tue Aug 26, 2008 2:55 pm    Post subject: Reply with quote

for gtk_tree_selection_get_selected to work, there needs to be an activated row in the tree view (i.e. a double-clicked row),
also, if the selection mode is set to GTK_SELECTION_MULTIPLE, the function won't work
http://library.gnome.org/devel/gtk/stable/GtkTreeSelection.html#gtk-tree-selection-get-selected
do either of these problems apply to your program?
Back to top
Nameless
Familiar Face


Joined: 28 Jun 2008
Posts: 7

PostPosted: Wed Aug 27, 2008 12:26 am    Post subject: Reply with quote

Actually, I used it wrong :) Thank you for the help, it works now.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP