Gtk change multiple labels on button click - c

How can i change multible label values on single button click.Normally on a button click signal connect we can give only one user data.
Example code
void show_loop(GtkWidget *widget, gpointer user_data)
{
char buf[5];
int no = TxBuf.plBuf[7];
sprintf(buf, "%d",no);
gtk_label_set_text(GTK_LABEL(user_data), buf);
}
ID_label=GTK_WIDGET (gtk_builder_get_object (builder, "label24"));
DLC_label=GTK_WIDGET (gtk_builder_get_object (builder, "label25"));
check = GTK_WIDGET (gtk_builder_get_object (builder, "button3"));
g_signal_connect (check, "clicked", G_CALLBACK (show_loop), DLC_label);
I want to change both the labels on single button click.

Typically you would define, allocate and fill a struct that contains all the widgets that may have to be changed dynamically in your initialization code:
typedef struct AppData {
GtkWidget *id_label;
GtkWidget *dlc_label;
} AppData;
...
AppData *app_data = g_new0 (AppData, 1);
app_data->id_label = GTK_WIDGET (gtk_builder_get_object (builder, "label24"));
app_data->dlc_label = GTK_WIDGET (gtk_builder_get_object (builder, "label25"));
The you use the app_data as userdata parameter and can access the widgets inside the signal handler as e.g. app_data->id_label.

Related

GTK get multiple range value segmentation error

So, I'm trying to create an rgb selector with gtk in C.
I follow the documentation to learn how to put in place a glade project and use it with gtk, so I made an UI in glade, but I have some trouble with the GTK part. I need to have access to multiple slider in the change-value signal because I want to get their value to print them, so I have created a struct to stock them, and I send this struct in the signal. But my problem is when I try to get the value of the range which his stock in the struct I have a segmentation error and I don't know why. I tried without the struct and I can correctly get the slider value, but it didn't work with the struct. How can I fix it?
Ask me if you need the glade file too.
//Compil : gcc -rdynamic -o ColorPicker colorPicker.c `pkg-config --cflags --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <glib/gstdio.h>
#include <gdk/gdk.h>
typedef struct
{
GObject *redSlider;
GObject *blueSlider;
GObject *greenSlider;
GObject *label;
}Data;
static void changeLabel (GtkWidget *range, Data *data)
{
gdouble red = gtk_range_get_value(GTK_RANGE(data->redSlider));
g_print("%.0lf\n",red);
//g_print("R : %d, G : %d, B : %d",red,green,blue);
}
static void activate(GtkApplication *app, gpointer user_data)
{
Data *data;
data = malloc(sizeof(*data));
GtkBuilder *builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "colorPicker.glade",NULL);
GObject *window = gtk_builder_get_object (builder, "window");
gtk_window_set_application (GTK_WINDOW (window), app);
data->redSlider = gtk_builder_get_object (builder, "redSlider");
g_signal_connect (data->redSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->blueSlider = gtk_builder_get_object (builder, "blueSlider");
g_signal_connect (data->blueSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->greenSlider = gtk_builder_get_object (builder, "greenSlider");
g_signal_connect (data->greenSlider, "change-value", G_CALLBACK (changeLabel), (gpointer) data);
data->label = gtk_builder_get_object (builder, "cpChooseLabel");
/*GObject *colorBtn = gtk_builder_get_object (builder, "colorBtn");
g_signal_connect (colorBtn, "clicked", G_CALLBACK (getColor), (gpointer) data);*/
gtk_widget_show (GTK_WIDGET (window));
/* We do not need the builder any more */
g_object_unref (builder);
free(data);
}
int main(int argc, char **argv)
{
#ifdef GTK_SRCDIR
g_chdir(GTK_SRCDIR);
#endif
GtkApplication *app = gtk_application_new("com.github.XXXXXX.rgbSelector", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
You end the structure's lifetime by freeing it at the end of activate. When the callback changeLabel is invoked at some time later, it tries to access the no longer existing structure. You could just drop the free(data); if you don't care that the space occupied by the four pointers can't be freed then; another possibility is to simply use a static structure and pass its address.

GTK in C: Segmentation Fault when using key-release or key-press

For context, I'm trying to make a program that changes stylized label text in response to some physical inputs on a beaglebone black (eg. get a signal, if high/low, show this text). In lieu of those inputs, which I don't have access to right now, I decided to use key-release as a substitute.
I've been basing my code off of this combo-box tutorial, which changes label text based on the text of a combo-box selection. I've modified that code to use stylized text as in the code below.
#include <gtk/gtk.h>
void combo_selected(GtkWidget *widget, gpointer window) {
gchar *text = g_strjoin(NULL,"<span font='48' weight='bold' color='#DDDDDD'>",gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)),"</span>",NULL); //label text, uses pango markup
gtk_label_set_markup(GTK_LABEL(window), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *combo;
GtkWidget *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GtkComboBox");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
hbox = gtk_hbox_new(FALSE, 0);
vbox = gtk_vbox_new(FALSE, 15);
combo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Arch");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian");
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), str); //add pango str to label
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), hbox);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(combo), "changed",
G_CALLBACK(combo_selected), (gpointer) label);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
That works, however when attempting to use a key-release or key-press instead of the combo box options, I get a segmentation fault. Below is the further-modified code (with some things commented out).
#include <gtk/gtk.h>
#include <unistd.h>
#include <stdio.h>
void fpcheck(GtkWidget *window, gpointer lbl) {
gchar *text = "<span font='48' weight='bold' color='#DDDDDD'>Press index finger firmly on sensor.</span>";
gtk_label_set_markup(GTK_LABEL(lbl), text);
//sleep(2); //placeholder -> fp detection
//text = "<span font='48' weight='bold' color='#DDDDDD'>Fingerprint recognized!</span>";
//gtk_label_set_markup(GTK_LABEL(lbl), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window; //main window
GtkWidget *align; //alignment settings
GtkWidget *lbl; //text
GdkColor color = {0, 0x0, 0x0, 0x0}; //window color
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //init window
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); //window pos on screen
gtk_window_set_default_size(GTK_WINDOW(window), 800, 480); //window size
//gtk_window_set_resizable(GTK_WINDOW(window), FALSE); //user cant resize
gtk_window_set_title(GTK_WINDOW(window),"User Display"); //window title
gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); //set color to window
align = gtk_alignment_new(.5,.5,0,0); //x,y alignment
lbl = gtk_label_new(NULL); //label init
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
gtk_container_add(GTK_CONTAINER(align), lbl); //add label to alignment
gtk_container_add(GTK_CONTAINER(window), align); //add label to window
gtk_label_set_markup(GTK_LABEL(lbl), str); //add pango str to label
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(fpcheck), (gpointer) lbl); //calls fpcheck to change label
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window); //build the window all at once
gtk_main();
return 0;
}
If I comment out the gtk_label_set_markup line and g_free(text) line in fpcheck, there's no error but it doesn't do anything, of course. From looking at other online resources, I think this error is being cause by trying to access the GTK_LABEL(lbl) because of the first argument in fpcheck being incorrect, but thats just a guess and I don't know what I'd put there instead. In the example, it's just "Widget," referring to the combo-box, I think, since it gets the text from the selected option.
On that note, I tried removing that argument, and now instead of a segmentation error, I get the following error without even pressing/releasing.
(test:6698): GLib-GObject-WARNING **: invalid cast from 'GtkWindow' to 'GtkLabel'
(test:6698): Gtk-CRITICAL **: IA__gtk_label_set_markup: assertion 'GTK_IS_LABEL (label)' failed
I did a few gdb backtraces, but none of them seem to be particularly helpful. If anyone wants 'em, I can post them.
Any ideas on the problems I'm having?
Thanks.
key-release-event handler has this signature
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
Your fpcheck() needs to look like that.
It's easier to find problems like this early if you learn the habit of doing e.g. g_assert (GTK_IS_LABEL (user_data)) as the first thing in every handler where the userdata definitely always has to be a label.

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

How to Implement a button-press-event on GtkTable

Searching the web for answers dosen't get me through my problem:
I wan't my GtkTable to throw an event, if i click one cell.
Since there is no click event, accept for GtkButton's, i wanted to implement a GDK_BUTTON_PRESS_MASK and GDK_BUTTON_RELEASE_MASK to catch the position of the mouse on the Table during click.
Works great with GtkDrawingArea!
Tryed the snipet bellow, but nothing happend, maybe someone can give me a clue :)
little sample:
static void table_press(GtkWidget *widget, GdkEventButton *event)
{
printf("table pressed");
}
int main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget* table;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "table click");
table = gtk_table_new(2, 5, TRUE);
gtk_container_add(GTK_CONTAINER (window), table);
gtk_widget_add_events(table, GDK_BUTTON_PRESS_MASK);
g_signal_connect(GTK_OBJECT (table), "button-press-event",
G_CALLBACK (table_press), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
main_exit();
return 0;
}
You don't receive events because GtkTable does not have a GdkWindow associated with it. You can use GtkEventBox which lets you accept events on widgets that would not normally accept events. This is derived from GtkBin so the interesting code would look like this.
table = gtk_table_new(2, 5, TRUE);
event_box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER (window), event_box);
gtk_container_add(GTK_CONTAINER (event_box), table);
g_signal_connect(GTK_OBJECT (event_box), "button-press-event",
G_CALLBACK (table_press), NULL);

Duplicate GtkWidget in C

I want to duplicate a GtkWidget loaded through GtkBuilder
My problem is that telling Gtk to pack it into the same vbox it's already in causes an error, and I don't know how to duplicate it. I imagine it involves messing with pointers and references which is probably why I'm missing the point.
static GtkWidget *my_widget(){
GtkBuilder *builder;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "widget.glade", NULL);
return GTK_WIDGET (gtk_builder_get_object (builder, "widget"));
}
int
main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
GtkWidget *widget;
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "userinterface.glade", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "mainwindow"));
gtk_builder_connect_signals (builder, NULL);
// Load widget into box
int i;
for (i=0; i<5; i++){
gtk_box_pack_start( GTK_BOX (gtk_builder_get_object (builder, "widget_vbox")),
my_widget(),
FALSE,
TRUE,
0);
if(i!=4){ // Don't add a seperator at the last loop
widget = gtk_hseparator_new();
gtk_box_pack_start( GTK_BOX (gtk_builder_get_object (builder, "solo_mission_vbox")),
widget,
FALSE,
TRUE,
0);
gtk_widget_show(widget);
}}}
This populates the box with the widget 5 times with seperators in between. The problem lies in that the program is opening and closing the same file 5 times over just to get put it in place.
How can I take the builder output and "Copy" it into 5 completely different instances? It probably involves something with a lot of *s and &s.
You can't "copy" widgets, no matter how many pointers you use. The way you are doing it in your example above is correct. One improvement is that you could move the widget into its own, smaller, builder file. If the widget is small, you might consider making your own widget class and constructing it manually, instead of from a builder file.
PS. If you want to program an application in C, you'd better learn not to be afraid of pointers!

Resources