Creating grid with GTK buttons - c

I want to create a grid with buttons. When a button is clicked I want it to change color, and 0 or 1 get stored in an array depending on the current state of the button.
Now I do this by creating the buttons with two for loops (rows, and columns).
Inside the for loops;
/*Create an ID number for the button being created*/
btn_nr ++;
char btn_nr_str[3];
sprintf(btn_nr_str,"%d",btn_nr); //convert nr to string
/*Create button*/
button = gtk_button_new();
/* When the button is clicked, we call the "callback" function
* with a pointer to the ID */
gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (callback)(gpointer) btn_nr_str);
/* Insert button into the table */
gtk_table_attach_defaults (GTK_TABLE(table), button, col, col+1, row, row+1);
gtk_widget_show (button);
The callback function;
void callback( GtkWidget *widget, gpointer nr)
{
GdkColor buttonColor;
gdk_color_parse ("black", &buttonColor);
gtk_widget_modify_bg ( GTK_WIDGET(widget), GTK_STATE_NORMAL, &buttonColor);
g_print ("Hello again - %s was pressed\n", (char *) nr);
}
The buttons are created like wanted, and when clicked they turn black.
However, all buttons print the last created button's ID.
How do I pass the right ID on?

You are accessing a local array (btn_nr_str) from outside (the callback) its scope (the for cycle). The idea is correct (using user_data) but the implementation is not.
For your specific case, you can use the type conversion macros provided by GLib. They are meant for exactly this purpose:
/* In the for cycle */
g_signal_connect(button, "clicked", G_CALLBACK(callback), GINT_TO_POINTER(btn_nr);
/* In the callback */
gint btn_nr = GPOINTER_TO_INT(user_data);
P.S.: gtk_signal_connect has been deprecated years ago.

Related

Should I use a global variable in gtk callback functions? [duplicate]

This question already has answers here:
Passing additional arguments to gtk function
(3 answers)
GTK passing structure to callback function in C
(1 answer)
Closed 3 years ago.
Hi I'm trying to program with GTK+ 2 and when I need to create a popup window after the "clicked' signal of a button, I use " gtk_widget_set_sensitive(button, FALSE) " so as not to be able to launch another popoup window from the same button when one is already launched. Yet the only way to close the popup with another callback function containing " gtk_widget_destroy(popup) " also means this callback can't "see" the first button to turn it sensitive again. Should I use a global variable and asign the popup window to it so my second callback function will see it? Or do I define more global widgets ?
What I'm really getting at is using global variables in something like GTK a common thing to do?, such as in header files, or is it bad practice at all?
Here is a sample program (with less stuff in the first callback than normal!)
#include <gtk/gtk.h>
// Is it good to set a temporary global GtkWidget * so I can asign it to
// button1 later and then use this temporary variable to set the widget sensitive again.
// GtkWidget * temp;
static void popup_win(GtkWidget *, gpointer data);
static void close_up(GtkWidget *, GtkWidget *);
int main(int argc, char * argv[])
{
GtkWidget * window, * button1, * vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "EXAMPLE PROGRAM");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_widget_set_size_request(window, 800, 300);
button1 = gtk_button_new_with_label("Click here");
g_signal_connect(G_OBJECT(button1), "clicked",
G_CALLBACK(popup_win), NULL);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), button1, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static void popup_win(GtkWidget * btn, gpointer data)
{
gtk_widget_set_sensitive(btn, FALSE);
// I could use temp here. Then get to it in close_up function.
// temp = btn
GtkWidget * window2, * button2, * hbox;
window2 = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_set_title(GTK_WINDOW(window2), "POPUP WINDOW");
gtk_container_set_border_width(GTK_CONTAINER(window2), 10);
gtk_widget_set_size_request(window2, 100, 200);
button2 = gtk_button_new_with_label("Click me too");
g_signal_connect(G_OBJECT(button2), "clicked",
G_CALLBACK(close_up), (gpointer) window2);
hbox = gtk_hbox_new(TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button2, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window2), hbox);
gtk_widget_show_all(window2);
}
static void close_up(GtkWidget * btn, GtkWidget * win)
{
// can't get at button1 so I can't set widget sensitve again.
// gtk_widget_set_sensitive(button1, TRUE);
// Unless I'm using temp variable.
// gtk_widget_set_sensitive(temp, TRUE);
gtk_widget_destroy(win);
}```

Update or Change the button label in C

For my GUI having some buttons. If I were to change or update the label of any random button I select from the list what should I do?
The initial name of the button is written in button properties. My GUI is designed in Glade.
And now I will enter the new name in entry-text in my GUI.
I have created an update button for this. How to do it in Gtk ofcourse.
The related codes are as follows:
Creation of button in the window and find it.
UpdateButton = GTK_WIDGET( gtk_builder_get_object( builder, "UpdateButton" ) );
gtk_signal_connect (GTK_OBJECT (UpdateButton), "clicked", GTK_SIGNAL_FUNC (Update_Data), NULL);
On update button clicked.
void Update_Data( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
const gchar *entry_text3;
g_print ("You have clicked Update... - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
entry_text3 = gtk_entry_get_text (GTK_ENTRY (entry3));
char sql[300];
sprintf(sql, "UPDATE DEVICES set NAME='%s ',\nUSERNAME='%s ',\nPASSWORD='%s '\nwhere ID=%s;"
, entry_text1, entry_text2, entry_text3, updateid);
//updateid is the ID taken from the array when a button is clicked
inserDatabase("myDatabase.db", sql);
getlastEntry(); //for taking the last entered info
updateData(sql); //for updating in database
}
If more information is required I will get you. Please do ask!
Your question is unclear, but if I understand you correctly...
You get the buttons...
GtkButton *click_button; // Button to click
GtkButton *change_button; // Button that changes label
click_button = GTK_BUTTON (gtk_builder_get_object (builder, "click_button"));
change_button = GTK_BUTTON (gtk_builder_get_object (builder, "change_button"));
Define a function for the click event to set the label...
static void
change_button_label (GtkWidget *click_button,
gpointer user_data)
{
GtkButton *change_button = (GtkButton *) user_data;
gtk_button_set_label (change_button, "New Label");
}
Connect the click signal function to the button, and pass it the change button...
g_signal_connect (click_button, "clicked", G_CALLBACK (change_button_label), change_button);

GtkCellRendererPixbuf and signals

Could anyone please give me a hint on how to attach a "double clicked" signal
to the pixbuf that is in the GtkTreeView? GtkCellRendererPixbuf
doesn't have any signals?
I managed to set the GTK_CELL_RENDERER_MODE_ACTIVATABLE switch to the
renderer, but I don't know how to work.
I checked the header file and in fact there is the "activate" method; could you please
demonstrate how to use it?
renderer = gtk_cell_renderer_pixbuf_new();
g_object_set(renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
column = gtk_tree_view_column_new_with_attributes(NULL,
renderer,
"pixbuf",
0,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
OK I try this:
Tree view's 'row-activated' will send the path and column as arguments
to the callback. With 'cursor-changed' just need to call
gtk_gtk_treeview_get_cursor to find out the path and column. With
gtk Widget's 'button-press-event' I get the event as an argument for
the callback and just need to call gtk_treeview_get_path_at_pos with
event x and event y to get the path and column.
A cell renderer is only supposed to draw the contents of the data model over a portion of the widget. Interaction with the user is in most cases realized using the widget itself.
In other words, simply connect to the button-press-event of the tree view and handle the case when the type is GDK_2BUTTON_PRESS. You can get the row/column under the mouse using gtk_tree_view_get_path_at_pos, as you do in your other question.
Check this:
void on_treeview_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_tree_view_get_model( treeview );
if ( gtk_tree_model_get_iter(model, &iter, path) )
{
gtk_tree_model_get(model, &iter,
ITEM, &dhd_contaItem2,
CODIGO, &dhd_G_CodProduto2 ,
DESCRICAO, &dhd_G_NomeProduto2 ,
QTD, &dhd_quantidade2,
VALOR, &dhd_valorItem2,
-1);
g_print( "Current row: %s %s %s %s %s\n", dhd_contaItem2, dhd_G_CodProduto2, dhd_G_NomeProduto2, dhd_quantidade2, dhd_valorItem2 );
}
}
I use that in one of my codes to print in terminal the selected row from a TreeView (with ListStore) when double clicked or when you press enter on it. On the gtk_tree_model_get notice that I'm using my own columns and variables, as i do in g_print. And I attach this function with row-activated signal on the TreeView. I don't know if is that what you want exactly but I hope it helps you out. Sorry for my bad english.

GTK Linux C Get Input from Entry Box via Button Widget

I have a table that is filled with entry boxes, labels, and buttons.
Currently, if I compile the code, I can get input from a text box but only if the users presses the enter key, and the text only comes from the box they are currently typing in.
I would like to be able to get input from both text boxes when the "Login" button is pushed. I've tried using the same callback function that's used for enter key on the entry box, but GTK gives me an error.
If anyone could show me some code that would allow for me to get text from my entry boxes that are within tables (I know the method for retrieving data from tables and v/boxes is different) it would be greatly appreciated, as I can't seem to find it in any tutorials.
Will update w/working code.
Error when trying to attach status bar to table:
(Entry:5526): Gtk-CRITICAL **: gtk_table_attach: assertion `child->parent == NULL' failed
(Entry:5526): GLib-GObject-WARNING **: invalid cast from GtkTable' toGtkStatusbar'
Your callback function (named callback) needs to access both GtkEntry widgets in order to obtain their values. There are several ways this can be accomplished. Many GTK C programs use global variables, or global variables with file scope (ie a variable declared as static outside of any function within a file).
Remove your entry1 and entry2 variables near the top of the file before any functions:
static GtkWidget *entry1 = 0;
static GtkWidget *entry2 = 0;
And then modify the callback like so:
/* Our callback.
* The data passed to this function is printed to stdout */
static void callback( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
g_print ("Hello again - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
You should additionally make similar modifications to the enter_callback function, and don't forget to remove the GtkWidget pointers to both GtkEntry from main.
As an alternative to using (static) global variables, create a data structure to hold the entries:
typedef struct login_data
{
GtkWidget *entry1;
GtkWidget *entry2;
} login_data;
This then gets passed to the callback (rather than text string as before), and the callback changes like so:
static void callback( GtkWidget *widget, gpointer data)
{
login_data* ld = (login_data*)data;
const gchar *entry_text1;
const gchar *entry_text2;
entry_text1 = gtk_entry_get_text (GTK_ENTRY (ld->entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (ld->entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
The data structure is dynamically allocated to prevent it going out of scope (not strictly necessary in simple applications) and this is done before using g_signal_connect to connect the callback to the entries:
login_data* ld = g_malloc(sizeof(*ld));
// callback function to execute when login is clicked
g_signal_connect (LoginButton, "clicked", G_CALLBACK (callback), (gpointer) ld);
Using this method, you must change all references to entry1 and entry2 to ld->entry1 and ld->entry2. Lastly, before the program exits, you should call g_free on the dynamically allocated struct ie g_free(ld).
BTW, for this program you don't need two separate callbacks, remove enter_callback and just use callback for both.

What's the GTK header I need to include so I can use lookup_widget?

As shown in the example below, this callback function is when the user clicks an OK button. I can get window (the top level widget) from button by using gtk_widget_get_toplevel, but I'm stuck trying to get a widget pointer for a GtkEntry widget with name ENTRY.
/* Called when OK button is clicked */
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" );
gchar *text1, *text2;
text1 = gtk_entry_get_text( GTK_ENTRY(entry));
text2 = g_strconcat("Hello, ", text1, NULL);
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET(button));
GtkWidget *dialog = gtk_message_dialog_new( window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
text2);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
But I get the error "undefined reference to lookup_widget." I can find a billion examples of snippets of code using lookup_widget, but not a single one full source code example showing the headers that enable the use of it. I'm using Anjuta3.2.0 and the latest Glade plugin.
As Basile Starynkevitch says, lookup_widget() was a function generated by Glade 2. However, code generation by Glade has been deprecated for quite a long time now, in favor of (first) libglade and (later) GtkBuilder. In fact, Glade 3 won't even do it.
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.
However, if you must use lookup_widget(), here's the source that Glade 2 generated as of about 6 years ago:
GtkWidget*
lookup_widget (GtkWidget *widget,
const gchar *widget_name)
{
GtkWidget *parent, *found_widget;
for (;;)
{
if (GTK_IS_MENU (widget))
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
else
parent = widget->parent;
if (!parent)
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
if (parent == NULL)
break;
widget = parent;
}
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
For this to work, you have to do the following for every widget contained within a toplevel window:
g_object_set_data_full (G_OBJECT (toplevel), "name-of-widget", gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref);
and then the following once for each toplevel window:
g_object_set_data (G_OBJECT (toplevel), "name-of-toplevel", toplevel);
Seems to me to be more trouble than it's worth.
Glade-2 implements lookup_widget() in support.c and the header is support.h
Once the GLADE GUI is converted to C codes these files are generated automatically.

Resources