Reputation: 129
This is simple program using c++11 but with GTK+ (not GTKmm) , i'm kind obliged to use GTK+ for some compatibility issues. Obviously there are some things there that are wrong....
Like changing the label from a global callback function "update_link(...)" .
I would like to create a signal that is emitted as the counter in the computing function is incremented, so that the GUI display this incrementation as it happens.
#include <gtk/gtk.h>
#include<glib.h>
#include<glib/gstdio.h>
#include<iostream>
#include <thread>
#include<string>
#include<mutex>
#include<time.h>
#include<regex.h>
#define BUILDER_GLADE_FILE "t_tool.glade"
using namespace std;
typedef struct GUI_data
{
GtkBuilder *gtkBuilder;
GtkWidget *window;
GtkWidget *quit_button;
GtkWidget *txtview;
gchar *filename;
GtkLabel *lab6;
GtkLabel *lab7;
GtkLabel *lab8;
GtkLabel *lab9;
GtkTextBuffer *buffview;
GtkTextIter start , iter, end;
} GUI_data;
static void GUI_stuff(GUI_data *d,int);
void quit_gtk(GUI_data *d);
void computing(int&, GUI_data*);
void updateLink(GtkWidget *label, gpointer data);
int main (int argc, char *argv[])
{
int count(0);
gtk_init(&argc, &argv);
GUI_data d;
thread first (GUI_stuff, &d, ref(count));
thread second (computing,ref(count),&d);
first.join();
second.join();
return 0;
}
void computing(int& count, GUI_data *d)
{
for (int i=0; i<=100; i++)
{
count++;
cout<<" Counter i is : "<<i<<endl;
gtk_signal_emit_by_name(G_OBJECT(d->lab6), "Link_up");
}
}
static void GUI_stuff(GUI_data *d, int count)
{
GtkBuilder *gtkBuilder;
gtkBuilder = gtk_builder_new();
gtk_builder_add_from_file(gtkBuilder, BUILDER_GLADE_FILE , NULL);
d->window = GTK_WIDGET(gtk_builder_get_object(gtkBuilder,"window1"));
gtk_window_set_title(GTK_WINDOW(d->window),"T Tool");
d->quit_button = GTK_WIDGET(gtk_builder_get_object(gtkBuilder,"Quit"));
d->txtview = GTK_WIDGET(gtk_builder_get_object(gtkBuilder,"textview1"));
d->lab6 = GTK_LABEL(gtk_builder_get_object(gtkBuilder,"label6"));
d->lab7 = GTK_LABEL(gtk_builder_get_object(gtkBuilder,"label7"));
d->lab8 = GTK_LABEL(gtk_builder_get_object(gtkBuilder,"label8"));
d->lab9 = GTK_LABEL(gtk_builder_get_object(gtkBuilder,"label9"));
GtkTextBuffer *buffview;
GtkTextIter start , iter, end;
// gtk_label_set_text(lab6,std::to_string(count).c_str());
gtk_label_set_text(d->lab6, " fills P status ");
gtk_label_set_text(d->lab7, " fills P counter ");
gtk_label_set_text(d->lab8, " fills R status ");
gtk_label_set_text(d->lab9, " fills R counter ");
buffview= gtk_text_view_get_buffer(GTK_TEXT_VIEW(d->txtview));
gtk_text_buffer_get_iter_at_offset(buffview,&iter, 0);
gtk_text_buffer_insert(buffview,&iter," This to show things",-1);
g_signal_new("Link_up",G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST,0, NULL, NULL,g_cclosure_marshal_VOID__POINTER,G_TYPE_NONE, 1, G_TYPE_POINTER);
g_signal_connect(G_OBJECT(d->lab6),"Link_up", G_CALLBACK(updateLink), &count);
g_signal_connect(G_OBJECT(d->window), "destroy", G_CALLBACK(quit_gtk), NULL);
g_signal_connect(G_OBJECT(d->quit_button), "activate", G_CALLBACK(quit_gtk), NULL);
g_object_unref(G_OBJECT(gtkBuilder)) ;
gtk_widget_show(d->window);
gtk_main();
}
void updateLink(Gtklabel *label, gpointer data)
{
int *p =data;
gtk_label_set_text(label,std::to_string(*p).c_str());
}
void quit_gtk(GUI_data *d)
{
gtk_main_quit();
}
The error i get
$ g++ -std=c++11 -Wall `pkg-config --libs --cflags gtk+-3.0` main.cpp -o gtkcpp
main.cpp: In function ‘void computing(int&, GUI_data*)’:
main.cpp:68:55: error: ‘gtk_signal_emit_by_name’ was not declared in this scope
gtk_signal_emit_by_name(G_OBJECT(d->lab6), "Link_up");
^
main.cpp: In function ‘void GUI_stuff(GUI_data*, int)’:
main.cpp:94:14: warning: unused variable ‘start’ [-Wunused-variable]
GtkTextIter start , iter, end;
^
main.cpp:94:28: warning: unused variable ‘end’ [-Wunused-variable]
GtkTextIter start , iter, end;
^
main.cpp: At global scope:
main.cpp:125:17: error: variable or field ‘updateLink’ declared void
void updateLink(Gtklabel *label, gpointer data)
^
main.cpp:125:17: error: ‘Gtklabel’ was not declared in this scope
main.cpp:125:27: error: ‘label’ was not declared in this scope
void updateLink(Gtklabel *label, gpointer data)
^
main.cpp:125:43: error: expected primary-expression before ‘data’
void updateLink(Gtklabel *label, gpointer data)
Upvotes: 0
Views: 321
Reputation: 11588
Your compiler errors are due to typos.
g_signal_emit_by_name()
, not gtk_signal_emit_by_name()
. GObject functions, such as those regarding signals, use g_
prefixes.updateLink()
you use Gtklabel
instead of GtkLabel
.Now we can talk about what you want to do: update the GtkLabel
from a different thread.
All signals have to be formally registered using g_signal_new()
. This is usually done in the class initialization function, which sets up everything shared by all instances of a class. I don't know if you can even add signals later like that.
However, even if you did manage to add your link_up
signal to GtkLabel
, a bigger question is whether your g_signal_emit_by_name()
call will run on the GUI thread. I myself and others have asked this question in different forms elsewhere in the past, and looking back at my logs, it appears there is no such guarantee.
So in general, you don't want to do what you want to do (update the label from another thread) that way.
You will want to instead use the gdk_threads_add_idle()
function (note the gdk_
prefix this time) to add a callback that will call gtk_label_set_text()
on the main thread. For example, you could do
gboolean updateLinks(gpointer data)
{
int *p =data;
gtk_label_set_text(label,std::to_string(*p).c_str());
return FALSE; // don't run this particular instance again
}
// in computing()
gdk_threads_add_idle(updateLinks, &count);
gdk_threads_add_idle()
specifically queues your function to run when no other events are pending. You can even schedule such a function to run repeatedly. Read the documentation for more details.
Note that gdk_threads_add_idle()
returns immediately; if you want computing()
to wait for the callback to finish running before it continues, you will need to write the synchronization code yourself.
Upvotes: 1