So, I'm trying to achieve the following: The user shall be able to fill out multiple gtk_entry's and click Apply after that, on being clicked I want the Apply button to emit a signal, something like this:
g_signal_connect (G_OBJECT (Apply), "clicked",
G_CALLBACK(apply_clicked), # an argument #);
Afterwards, in apply_clicked(), I want the entered text to be saved.
My question is: How do I pass those gtk_entry's to my callback function apply_clicked?
If it were only one I'd just set it as # an argument #, but what should I do with multiple entries ?
The typical way of doing this is to do:
g_object_set_data (context_object, "entry1", entry1);
g_object_set_data (context_object, "entry2", entry2);
g_signal_connect (G_OBJECT (Apply), "clicked", G_CALLBACK (apply_clicked), context_object);
and then in apply_clicked:
GtkEntry *entry1 = g_object_get_data (context_object, "entry1");
...
Usually the context_object will be the GtkDialog or whatever these widgets exist on.
Alternatively, if you subclass the GtkDialog, you can do:
struct _MyDialog {
GtkDialog parent_object;
GtkEntry *entry1;
GtkEntry *entry2;
...
};
Then, when constructing your dialog, just set entry1, 2, 3, etc... and you don't need to use the g_object_[g,s]et_data() hack.
create a data structure (a linked list perhaps) to contain pointers to the gtk_entrys and pass that instead. Or better yet, why not just pass a pointer to the object which contains all of thise gtk_entrys?
Related
Suppose I have some widgets that I want to reuse their pointers, as
they are dynamically allocated and removed.
Example:
GtkWidget *widget1;
GtkWidget *widget2;
GtkWidget *widget3;
int main()
{
widget1 = gtk_new_type1_widget();
widget2 = gtk_new_type2_widget();
widget3 = gtk_new_type3_widget();
gtk_init(0, NULL);
//All other GTK initializing stuff, window
//creation and widgets loading from file...
gtk_main();
return 0;
}
Now suppose that I want to reuse widget1, widget2 and widget3 to point to a new widget. What is the proper to way to "free" the widgets before I allocate a new one? Do I need to call gtk_widget_destroy to clean all references? Or I can call something like g_clear_object?
Example:
gtk_widget_destroy(widget1);
g_clear_object(&widget1);
widget1 = gtk_new_type1_widget();
gtk_widget_destroy(widget2);
g_clear_object(&widget2);
widget2 = gtk_new_type2_widget();
gtk_widget_destroy(widget3);
g_clear_object(&widget3);
widget3 = gtk_new_type3_widget();
Also, a second question related to this one. If I create a function that wraps another gtk object creating function and set some properties for the objects, do I need to call g_object_unref ? Since the reference count will grow.
Example:
GtkWidget *create_widget_with_properties()
{
GtkWidget *widget;
widget = gtk_new_type1_widget();
set_widget_specific_properties(widget);
g_object_unref(widget);
return widget;
}
Appreciate any help.
EDIT: I solved my problem. For those who have the same doubts can
look my post at Gnome discourse. Here are some tips:
Understand reference counting
Understand floating reference concept in GTK
Understand memory management in GTK
If you understand the concepts above you will know how to handle widgets object pointers. There are useful links in the post.
Gtk version: 3.24.20
I have the following line in my GTK code:
gtk_container_add(GTK_CONTAINER(main_wind_ob->stack),
GTK_WIDGET(main_wind_ob->product_ob->swindow));
Where main_wind_on->stack is a GtkStack acquired this way
main_wind_ob->stack = GTK_STACK(
gtk_builder_get_object (
main_wind_ob->builder,
"stack"
)
);
Where main_wind_ob->builder is a GtkBuilder object associated with a .ui file where a GtkStack container is declared with the ID stack.
main_wind_ob->product_ob->swindow is a GtkScrolledWindow acquired like this:
main_wind_ob->product_ob->swindow =
gtk_scrolled_window_new(NULL, NULL);
I know neither main_wind_ob->product_ob->swindow or main_wind_ob->stack are not null as I've debugged and checked them.
What I wanted to do was make swindow be the child of the stack, but it just crashes when it reaches the gtk_container_add function call. I am not really sure why. Let me know if there is any extra details I can add to the post, thanks.
I have recently resurrected a project from a decade ago (https://github.com/clancyj4/z80sim) and I'm running into problems that are related to the transition from glade 2 to 3.
One problem is that I use a function lookup_widget which is defined in support.c by glade 2, but is not defined in glade 3. And I don't know how to replace it.
An example of how I use it is:
void init_Code(GtkWidget *Main)
{
GtkWidget *widget;
PangoFontDescription *codefont;
codetext = lookup_widget(Main, "Code_Text");
code_textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(codetext));
I have looked the problem up, of course, but I don't understand the answer which was:
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
which was referring to:
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
Any clarification would be most helpful.
EDIT:
I'm pretty sure that the signals are all connected because I use this:
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "z80em2.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "Main"));
gtk_builder_connect_signals(builder, NULL);
As I understand it codetext = lookup_widget(Main, "Code_Text") returns a pointer to the GtkWidget referred to as Code_Text under the Main widget and I don't see how to do that in GTK3.
I haven't used Glade, but if you have "manual" code that connects the signal handler, you should pass a pointer to that other widget in that call. That will then be stored inside GTK+, and passed as the user_pointer argument to the event handler.
So it would become just:
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
// This assumes the entry was passed to g_signal_connect() as 'data'
GtkWidget *entry = GTK_WIDGET(user_data);
See g_signal_connect().
If you are planning to rewrite this codebase heavily anyway, you may find it helpful to reorganize the widgets into composite widget templates, which Glade 3 supports, and use gtk_widget_class_bind_template_child() to make all the widgets that you would have otherwise looked up with lookup_widget() into members of your widget class. But it's not a good short-term fix, because it would involve a lot of refactoring.
In gtk2 the following code snippet works to pack widgets into a gtk_dialog window, using the vbox and action_area of the GtkDialog structure:
window=gtk_dialog_new();
gtk_container_set_border_width((GtkContainer *)window, 0);
scrolled_window=gtk_scrolled_window_new(NULL,NULL);
gtk_container_set_border_width((GtkContainer *)scrolled_window, 10);
gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)scrolled_window, GTK_SHADOW_IN);
gtk_scrolled_window_set_policy((GtkScrolledWindow *)scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start((GtkBox *) (GtkDialog *)window->vbox), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show(scrolled_window);
label=gtk_label_new(text);
gtk_label_set_use_markup((GtkLabel *)label, TRUE);
gtk_label_set_selectable((GtkLabel *)label, TRUE);
gtk_label_set_line_wrap((GtkLabel *)label, FALSE);
gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *)scrolled_window, label);
gtk_widget_show(label);
button=gtk_button_new_with_label("close");
g_signal_connect_swapped(button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_widget_set_can_default(button, TRUE);
gtk_box_pack_start((GtkBox *) (GtkDialog *)window->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show (button);
gtk_widget_show(window);
However in gtk3 this is not completely valid code any more. And it will not compile.
If I replace instances of:
(GtkBox *) (GtkDialog *)window->vbox
with:
(GtkBox *) (GtkDialog *)window
And do the same with instances of action_area the code will compile but the window will not show the extra packed widgets, just the ones the dialog comes with by default.
More information, which to me is a bit contradictory https://developer.gnome.org/gtk3/stable/GtkDialog.html#GtkDialog-struct
The GtkDialog contains only private fields and should not be directly
accessed.
But when I read this on the same page it seems to contradict the previous quote https://developer.gnome.org/gtk3/stable/GtkDialog.html#gtk-dialog-add-action-widget
If you want to add a non-activatable widget, simply pack it into the
action_area field of the GtkDialog struct.
Earlier in that document it states under GtkDialog as GtkBuildable
The GtkDialog implementation of the GtkBuildable interface exposes the
vbox and action_area as internal children with the names “vbox” and
“action_area”.
But I don't really know how to do that using the GtkBuildable interface neither do I want to. Or perhaps that is exactly what I did in gtk2 and it stopped working in gtk3...?
My question is how can I convert the gtk2 code to work with gtk3 with as few changes as possible. I have been searching for quite a while but found no answer yet. The existing gtk3 documentation leaves me going in circles. Maybe I just miss something totally obvious. Or perhaps you are not supposed to do this anymore and have to use a window instead of a dialog?
Thanks to the answer below I was able to change the code to this working one, it will also eliminate a deprecated warning about gtk_dialog_get_action_area() by using gtk_dialog_add_button()
window=gtk_dialog_new();
gtk_container_set_border_width((GtkContainer *)window, 0);
scrolled_window=gtk_scrolled_window_new(NULL,NULL);
gtk_container_set_border_width((GtkContainer *)scrolled_window, 10);
gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)scrolled_window, GTK_SHADOW_IN);
gtk_scrolled_window_set_policy((GtkScrolledWindow *)scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start((GtkBox *) (GtkDialog *) (gtk_dialog_get_content_area(window)), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show(scrolled_window);
label=gtk_label_new(text);
gtk_label_set_use_markup((GtkLabel *)label, TRUE);
gtk_label_set_selectable((GtkLabel *)label, TRUE);
gtk_label_set_line_wrap((GtkLabel *)label, FALSE);
gtk_container_add((GtkContainer *)scrolled_window, label);
gtk_widget_show(label);
button=gtk_dialog_add_button((GtkDialog *)window, "close", GTK_RESPONSE_CLOSE);
g_signal_connect_swapped(button, "response", (GCallback *)gtk_widget_destroy, window);
gtk_widget_set_can_default(button, TRUE);
gtk_widget_grab_default(button);
gtk_widget_show(button);
gtk_widget_show(window);
gtk_dialog_run((GtkDialog*)window);
gtk_widget_destroy(window);
For the top section you gtk_dialog_get_content_area. This will return a VBox, where you can pack your own widgets.
For the bottom section you either gtk_dialog_add_button or gtk_dialog_add_action_widget.
The GtkDialog contains only private fields and should not be directly accessed.
If you want to add a non-activatable widget, simply pack it into the action_area field of the GtkDialog struct.
You should obtain a pointer to action_area with deprecated (!)gtk_dialog_get_action_area, but that will not allow to register a response id.
Can someone provide a sample how to access to callbacks with Gnome-db libgda-ui, using this demo https://github.com/GNOME/libgda/blob/master/libgda-ui/demos/grid.c and I want to call a callback when I double click on a row like in gtktree with liststore
I think I've found a solution using the raw-grid
GtkWidget *grid;
GdauiRawGrid *raw_grid;
g_object_get (G_OBJECT (grid), "raw-grid", &raw_grid, NULL);
Then the raw_grid has the callback needed and it have methods like gtk treeview