Difficulty in editable GtkTreeView - c

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);

Related

Gtk.Combobox displays two columns (instead of 1), Why?

I realize GTK-2 is now 'antique'. I have an old program I have to modify, and it's just too large to convert to GTK-3 for the time I have. This is the issue:
I added a ComboBox to which I assign a ListBox with 2 columns (G_TYPE_INT and G_TYPE_STRING).
For some reason, both columns are shown on the ComboBox, though I think the code shown below only assigns one.
void
fill_list(GtkComboBox *cbbox)
{
GtkListStore *store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
GtkTreeIter iter;
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_combo_box_set_model(cbbox, GTK_TREE_MODEL(store));
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbbox), renderer, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cbbox), renderer,
"text", 0, NULL);
gtk_combo_box_set_entry_text_column(cbbox, 0);
gtk_list_store_append(store, &iter);
// Col 0 Col 1
gtk_list_store_set(store, &iter, 0, 0, 1, "Kind 1", -1);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, 1, 1, "Kind 2", -1);
gtk_list_store_append(store, &iter);
This is part of the function called on the 'realize' signal of the widget.
Changing ..."text", 0... to ..."text", 1... changes the second column of the
ComboBox to, as expected, the second column of the ListStore.
But, for unknown reason, I can't get rid of the first column. I've scanned the
entire project for signs of code that might influence - no luck. The interface was
generated using Glade-2.
For the last years, I've been working more from Python, so I'm suspecting there's something
I'm missing here. I even basically tested this code in Python, and had no problem there.
I'd appreciate suggestions!
The problem was solved!
I found out that Glade 2, when asked to add a GtkComboBox, actually inserted a GtkComboBoxText (even though in the Component editor it is shown as a GtkComboBox type). I've only detected this when browsing the automatically generated interface.c code.
This creates a widget with a 'model' in it, and (I suspect) the necessary code to render the single column in that model (for the 'text'). When adding a new column, by setting another model, the (original) renderer is rendering the first column.
To get rid of the original renderer, the solution seems to be to call gtk_cell_layout_clear, and only then add the new model + renderer:
gtk_cell_layout_clear(GTK_CELL_LAYOUT(cbbox));
Do this during a realize event handler for the ComboBox, don't modify interface.c, as it will be overwritten.
I'm not sure if this is enough to free any memory to the original renderer though.

How do I replace lookup_widget in Glade3/GTK3 code?

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.

Using Pango Markup within a GTK+ TreeView in C

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);

GtkSourceGutter - How to render icon or text on a specific line

I have inserted custom gtk source gutter renderer pixbuf and I want to render icon on a specific line.
The reference API states that the interface is very similar to that on GtkTreeView, but doesn't work with a tree model.
So... how am I supposed to render data to a specific line if the GtkSourceGutter doesn't work with a tree model?
I checked every function in the entire library, every suggested api and child objects and nothing even hints about that.
It just doesn't make sense. The man page says that the GtkSourceGutterRendererPixbuf is used to display icon IN A CELL.
Doing gtk_source_gutter_renderer_pixbuf_set_pixbuf(renderer, pixbuf); will render the icon for all cells in the gutter.
And if the only way is to draw the pixbuf manually using cairo..what's the point in those renderers ?
How do I render pixbuf in a specific line using the gtksourcegutterrenderer?
I haven't worked with GtkSourceView, but I can give you some clues.
How it's done by GtkSourceView's author
First of all, we need some links:
GtkSourceGutterRendererMarks source code
GtkSourceGutterRendererPixbuf source code
GtkSourceGutterRenderer documentation
Let's start with GtkSourceGutterRendererPixbuf. From it's class_init method we find out, that it overrides only draw method. It's only purpose is to render a pixbuf or icon. Pure drawing.
However, GtkSourceGutterRenderer documentation says, that there is a query-data signal which can be used to tune Renderer's internal state. At this point we should take a look at GtkSourceGutterRendererMarks which is inherited from RendererPixbuf. It doesn't override draw, but overrides query_data. (For some reason GtkSourceGutterRendererClass is not described in the documentation. I don't know why.)
/* Read my comments. */
static void
gutter_renderer_query_data (GtkSourceGutterRenderer *renderer,
GtkTextIter *start,
GtkTextIter *end,
GtkSourceGutterRendererState state)
{
GSList *marks;
GdkPixbuf *pixbuf = NULL;
view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
marks = gtk_source_buffer_get_source_marks_at_iter (buffer,
start,
NULL);
/* If there are marks, we find a pixbuf for one of them.
* Otherwise pixbuf is NULL. */
if (marks != NULL)
{
size = measure_line_height (view);
pixbuf = composite_marks (view, marks, size);
g_slist_free (marks);
}
/* Now tell parent class to render certain pixbuf
* It will render nothing if pixbuf is NULL. */
g_object_set (G_OBJECT (renderer),
"pixbuf", pixbuf,
NULL);
}
My recommendations.
You want to draw marks at certain lines (e.g. want to highlight current debugger line). If I were you, I would have inherited from RendererPixbuf, overriden query_data and use gtk_text_iter_get_line on GtkTextIter *start. Looks like that's the bare minimum.
Feel free to ask any further questions.
I personally cannot simply agree with the allegation that creating custom objects is easy. It isn't easy, not to everyone.
Mainly, because, this question is tagged c and people who don't know Object-Oriented programming might be unfamiliar with its concepts.
It is a matter of reading and practice.
So do not panic if you don't know how to, for instance create your own widget.
The easiest solution I can think of, doesn't involve creating your own renderer, but rather tell the renderer how to query rendering data.
Just connect the query-data signal on your GtkSourceGutterRenderer to a signal handler that looks like this:
G_MODULE_EXPORT void gutter_renderer_query_data (GtkSourceGutterRenderer *renderer, GtkTextIter *start, GtkTextIter *end, GtkSourceGutterRendererState state)
{
GtkSourceView* view = NULL;
GtkSourceBuffer* buffer = NULL;
GSList* marks = NULL;
GdkPixbuf* pixbuf = NULL;
view = GTK_SOURCE_VIEW(gtk_source_gutter_renderer_get_view(renderer));
buffer = GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)));
marks = gtk_source_buffer_get_source_marks_at_iter(buffer, start, NULL);
if(marks != NULL)
{
char *category = gtk_source_mark_get_category(marks->data);
if(!g_strcmp0(category, "CERTAIN_CATEGORY")) /* See note 1) */
pixbuf = gtk_image_get_pixbuf(gtk_image_new_from_file("icon_file_here")); /* See note 2) */
g_slist_free(marks);
}
g_object_set(G_OBJECT(renderer), "pixbuf", pixbuf, "yalign", 0.5, NULL);
}
Notes:
GtkSourceMark shares the GtkSourceGutterRenderer interface so you might want to filter your other source marks, by specifying the category of a source mark that is applied to the certain line. Otherwise your custom renderer pixbuf will also be rendered left to your other source marks.
You should specify the exact pixbuf you want to render internally. Doing this, you won't have to call gtk_source_gutter_renderer_pixbuf_set_pixbuf() . You let the API do the resource handling.

GtkAboutDialog icon not loading?

I'm attempting to add an about dialog to my next bit of tutorial code, but I can't get the icon to load for some reason. Below is the entire function for creating and displaying the dialog.
static void help_clicked(GtkButton *button, GtkWindow *window)
{
const gchar *authors[] = { "me", NULL };
const gchar *license = "somestuff";
GdkPixbuf *logo = gdk_pixbuf_new_from_file("logo.png", NULL);
gtk_show_about_dialog(window,
"authors", authors, "license", license, "license-type", GTK_LICENSE_CUSTOM,
"logo", logo, "logo-icon-name", "Logo Icon",
"program-name", "Chapter 6, Exercise 1",
"version", "1.0",
"comments", "This is just an exercise from Chapter 6 of the book I'm reading.",
"website", "http://www.google.com", "website-label", "Application Homepage",
"copyright", "(C) 2014 Patrick Meyer",
"wrap-license", TRUE, NULL);
}
This results in an about dialog with every attribute successfully set except the icon.
The weird thing is, the exact same call to gdk_pixbuf_new_from_file() works in main() when I supply it to gtk_window_set_icon(). This is a single-file program with logo.png present in the directory of execution. What's missing?
as the API reference clearly states, the GtkAboutDialog:logo-icon-name property overrides the GtkAboutDialog:logo property:
https://developer.gnome.org/gtk3/stable/GtkAboutDialog.html#GtkAboutDialog--logo-icon-name
also, you're passing a value for the logo-icon-name property that does not mean anything; the logo-icon-name property requires a named icon according to the Icon Naming Specification.
just remove the logo-icon-name property and you'll see the correct icon.
as a side note from your example: you should release the reference on the GdkPixbuf object you create after gtk_show_about_dialog() returns, otherwise you will leak it. ideally, though, since you don't want to load the image file from disk every time you click the help button, you should use something like this:
static GdkPixbuf *logo_icon = NULL;
if (logo_icon == NULL)
logo_icon = gdk_pixbuf_new_from_file ("logo.png", NULL);
gtk_show_about_dialog (...);
which will keep the pixbuf around for the duration of your application.
another option is to use GResource and inject the image data into the application's binary.
The problem is you are setting logo-icon-name too which is supposed to be a symbolic name for an icon, not a human description.
So the internal image is being set correctly and then replaced internally a second time. This also explains why calling gtk_window_set_icon() afterwards works correctly.
The problem is with the logo-icon-name property. As it is stated inside the documentation, this overwrites the logo property. If you leave out the logo-icon-name property, the logo will show correctly.

Resources