I want to create a window in Gtk that looks something like this.
widgets in glade
The left pane in the top window has a button labelled "Add to list". I have configured the callback for this button to add the widget "list_entry" into the GtkListBox in the right pane. It does so after changing the label of the widget from "label" to the text present in a text entry present just above it.
So, basically this button add a new entry into a list placed in the right pane(might be seen empty). This entry is a simple widget consisting of an icon and a label( at the bottom).
Now, I want the button "Add to list" to create new copies of this entry every time I click it and append that entry to the list in the right pane. But every time I add a new entry to the list, it simply overwrite the previous entry of the list and gives a warning ->
Attempting to add a widget with type GtkBox to a container of type GtkListBoxRow, but the widget is already inside a container of type GtkListBoxRow, please remove the widget from its existing container first.
I am using GtkListBox for the list in the right pane and the GtkBox for the new entry that I am supposed to add.
This is the code for the "click" callback of the button "Add to list"
static void
dw_left_add_btn_cb(CcPrintersPanel * self){
GtkLabel* row_list_label = (GtkLabel*) gtk_builder_get_object (self->builder, "list_entry_label");
GtkEntry* text_entry_to_add = (GtkEntry*) gtk_builder_get_object (self->builder, "dw_left_enter_text");
// debug
if ( self->list_serv == NULL || row_list_label == NULL) g_debug ("One of object for generating the list did'nt load up in the builder");
gtk_label_set_label (row_list_label, gtk_entry_get_text (text_entry_to_add));
gtk_entry_set_text(text_entry_to_add,"");
GtkWidget* row_list = (GtkWidget*) gtk_builder_get_object (self->builder, "list_entry");
gtk_list_box_insert (self->list_serv, row_list, -1);
}
I wanted to ask you how to create an entirely new widget( for every new entry ) from a widget that was loaded into Builder using a .ui file. Please also advise me if you have some other way of implementing this.
GtkBuilder is not a factory of widgets. It's more like a carton of widgets. Some pseudocode:
GtkWidget *widget1, *widget2;
builder = gtk_builder_new();
widget1 = gtk_builder_get_object(builder, "label");
widget2 = gtk_builder_get_object(builder, "label"); // this will not produce another label but return existing one
// (widget1 == widget2), they point to same object
// let's unpack another carton of widgets...
builder2 = gtk_builder_new();
widget2 = gtk_builder_get_object(builder2, "label");
// (widget1 != widget2), now that's really 2 distinct widgets
Hence the warning. You try to add widget to a ListBoxRow, but this exact widget is already in a ListBoxRow. When you want to dynamically create another widget, you must create another GtkBuilder.
static void
dw_left_add_btn_cb(CcPrintersPanel * self){
GtkBuilder *b = gtk_builder_new();
GtkLabel* w = (GtkLabel*) gtk_builder_get_object (b, "list_entry_label");
gtk_list_box_insert (self->list_serv, w, -1);
}
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 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.
I have a completely hardcoded GtkTreeView and I am trying to use Pango Markup on one of the columns in the Treeview. This requires the use of a cell data function on the text renderer for that column. The cell data function has the form:
// This function uses pango markup on the Gtklabels shown in the TreeView
// A cell data function is a function that is called for a specific cell renderer for each single row before that row is rendered.
static void cell_data_func_label (__attribute__((unused)) GtkTreeViewColumn *column, GtkCellRenderer *renderer,
GtkTreeModel *model, GtkTreeIter *iter, __attribute__((unused)) gpointer user_data)
{
gchar *label;
gchar *markuptxt;
// Retrieve the current label
gtk_tree_model_get (model, iter, CURRENT, &label, -1);
markuptxt = g_strdup_printf("<i>%s</i>", label);
g_object_set(renderer, "markup", markuptxt, "text", NULL, NULL); // markup isn't showing and text field is blank due to "text" == NULL
g_free(markuptxt);
}
and within the function GtkWidget *create_view_and_model() I set the cell data function via:
// Sets the GtkTreeCellDataFunc to use for the column
gtk_tree_view_column_set_cell_data_func(column4, text, cell_data_func_label, NULL, NULL);
The problem is that the text cell renderer is now blank. I suspect it might have to do with passing NULL after "text" in g_object_set. The following link:
https://en.wikibooks.org/wiki/GTK%2B_By_Example/Tree_View/Columns_and_Renderers
states that:
When using the "markup" property, you need to take into account that the "markup" and "text" properties do not seem to be mutually exclusive (I suppose this could be called a bug). In other words: whenever you set "markup" (and have used the "text" property before), set the "text" property to NULL, and vice versa.
It may be that this is no longer the case (i.e. it is for GTK+ 2), but I am not sure what needs to be changed in order to render the column with markup, since anything other than NULL ends up being rendered without markup, and using NULL leaves the renderer empty. Any assitance would be appreciated.
What ended up working was simply not including any reference to "text" whatsoever in g_object_set:
g_object_set(renderer, "markup", markuptxt, NULL);
What i'm trying to achieve is that when a popup is displayed, the input panel (keyboard) appears as well, and when the user start typing it also update the entry content that is on the panel content.
Unfortunately this appear to be quite complex in Tizen.
What I obtained so far is that the popup is displayed, the kepad too, but when I press buttons on the keypad they are not updating the entry.
In order to start real typing even if the keypad is displayed, i have to tap on the entry.
I did many different tries, without success. The following is the first version of the code and i try to list all the changes i tested:
Evas_Object *popup, *layout;
popup = elm_popup_add(parent);
elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_part_text_set(popup, "title,text", "Use energy");
layout = elm_layout_add(popup);
elm_layout_theme_set(layout, "layout", "drawer", "panel");
evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_content_set(popup, layout);
Evas_Object *entry = elm_entry_add(layout);
set_number_on_entry(entry, 0);
elm_entry_input_panel_layout_set(entry, ELM_INPUT_PANEL_LAYOUT_NUMBERONLY);
elm_entry_input_panel_show(entry);
elm_object_part_content_set(layout, "elm.swallow.content" , entry);
dlog_print(DLOG_INFO, APP_TAG, elm_entry_entry_get(entry));
container->entry = entry;
Evas_Object *button1;
button1 = elm_button_add(popup);
elm_object_text_set(button1, "OK");
elm_object_part_content_set(popup, "button1", button1);
elm_object_style_set(button1, "popup");
evas_object_smart_callback_add(button1, "clicked", ok_pressed_energy, container);
/* Add a "Cancel" button to popup */
button1 = elm_button_add(popup);
elm_object_text_set(button1, "Cancel");
elm_object_part_content_set(popup, "button2", button1);
evas_object_smart_callback_add(button1, "clicked", dismissed_cb, popup);
evas_object_smart_callback_add(popup, "dismissed", dismissed_cb, NULL);
container->popup = popup;
evas_object_show(popup);
elm_object_focus_set(entry, EINA_TRUE);
elm_entry_cursor_end_set(entry);
The first version of the code (the one above) was trying to display the panel while the popup was still creating. So maybe the show call could have impacted on the focus status for the entry.
The following are the changes i tried in order:
I tried to explicitly allow the focus on the entry using:
elm_object_focus_allow_set(entry, EINA_TRUE);
without luck. I also tried to explicitly give the focus to the entry just after the focus allow was set to true, again no success.
I tried to show the panel after the entry was focused (then after the show function for popup was called. Again not working.
Added:
elm_entry_input_panel_enabled_set(entry, EINA_TRUE);
The documentation for that function says:
If true, the input panel is appeared when entry is clicked or has a focus.
Not working
Tried to display the code using the context obtained from the entry with the following code:
Ecore_IMF_Context *imf_context = (Ecore_IMF_Context*)
elm_entry_imf_context_get(entry);
if(imf_context){
dlog_print(DLOG_INFO, APP_TAG , "Imf context");
ecore_imf_context_input_panel_show(imf_context);
}
I tried to post the question also on the Tizen foru, but i still didn't get an answer that solve my problem, this is the link: https://developer.tizen.org/forums/native-application-development/entry-on-popup-focus#comment-27748
What i'm doing wrong? I tried everything but at the moment with no luck. And unfortunately the documentation is not covering this use case (that i think is quite common).
Any help?
I am writing a piece of software where my user should be able to add data to a table-like editing widget, which I managed to render by using a GtkTreeView. I was able to render my cell editable by setting its editable property via this call
g_object_set(content_renderer,
"editable", TRUE,
NULL);
However, my GtkTreeView not only doesn't retain values entered as it's not even showing the data I've added before rendering. I saw a few examples in the web where the developer manually set the user input data to the model but all of these were either written in Python or C++ using offered bindings for these languages and therefore don't address my issue directly.
I've written this (not so) small example where the problem is successfully shown.
How can I make user input data persistent in a GtkTreeView?
P.S.: my problem is somehow related to this one, however this solution doesn't apply to me.
EDIT:
I followed #PhillipWood hint and connected my GtkCellRendererText to the edited signal, and also set by hand the new data into the model.
HOWEVER, neither the data I've entered prior to the edition nor the data I've entered during the edition appear in the grid.
I am under Fedora 19, with GTK+ 3.8.8.
You need to connect to the 'edited' signal of the cell renderer. This is emitted when the user finishes editing, it is up to the application (i.e. your code) to store the new value in the correct column of the model.
Update:
Looking at your updated code there are a few things that stand out.
Firstly when you use a GtkListStore or a GtkTreeStore it is a good idea to create an enum for indexing the columns.
enum {COLUMN_LABEL, COLUMN_CONTENT, COLUMN_LAST};
Then when you create the list store do
list_store = gtk_list_store_new(COLUMN_LAST, G_TYPE_STRING, G_TYPE_INT);
When you create a tree column you need to tell it which column(s) of the model to display with the cellrenderer. You do this by binding properties of the cellrenderer to columns in the model
label_col = gtk_tree_view_column_new_with_attributes ("Layer",
gtk_cell_renderer_text_new(),
"text", COLUMN_LABEL,
NULL);
Now the content column the model stores an int so we cannot just bind the text property of the renderer as it expects a string. We need to map the column contents onto the text property using
content_column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_cell_data_func (content_column,
gtk_cell_renderer_text_new (),
content_column_data_func,
NULL, NULL);
with
static void
content_column_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
int value;
gchar text;
gtk_tree_model_get (tree_model, iter, COLUMN_CONTENT, &value, -1);
text = g_strdup_printf ("%d", value);
g_object_set (cell, "text", text);
g_free (text);
}
Finally in the edited callback you need to convert the string to an integer before you store it
int value = atoi (new_text);
gtk_list_store_set (list_store, &iter, COLUMN_CONTENT, value, -1);