I have following declarations:
typedef struct window_and_search_entry
{
GtkWidget *window;
GtkWidget *search_entry;
} WINDOW_AND_SEARCH_ENTRY;
and then in main:
GtkWidget *window;
GtkWidget *search_entry;
...
WINDOW_AND_SEARCH_ENTRY window_and_search_entry;
window_and_search_entry.window = window;
window_and_search_entry.search_entry = search_entry;
and that two:
g_signal_connect_swapped(G_OBJECT(search_entry), "activate", G_CALLBACK(analyse), (gpointer) &window_and_search_entry);
g_signal_connect_swapped(G_OBJECT(do_it_button), "clicked", G_CALLBACK(analyse), (gpointer) &window_and_search_entry);
And I want to create function which takes text, and window, makes some operations on it and if an error occurs print it out with other function which takes window as parameter
ELEMENT *analyse(GtkWidget *widget, gpointer user_data)
{
//((WINDOW_AND_SEARCH_ENTRY *) user_data)->search_entry;
GtkWidget *a = ((WINDOW_AND_SEARCH_ENTRY*)(user_data))->search_entry;
const char *text = gtk_entry_get_text(GTK_ENTRY(a));
g_print("%s\n", text);
ELEMENT *heap[100];
int index = 0;
return heap[1];
}
I tried many variants but I get "Segmentation fault" after having something typed in entry_box followed by enter or button. I want to print the text to console. Please help me, thanks.
Your analyse callback requires g_signal_connect, not g_signal_connect_swapped. Also there is no need to cast pointers: the G_CALLBACK() macro already cast the whole function, so this would suffice:
ELEMENT *analyse(GtkWidget *widget, WINDOW_AND_SEARCH_ENTRY *data)
With g_signal_connect_swapped it would be:
ELEMENT *analyse(WINDOW_AND_SEARCH_ENTRY *data, GtkWidget *widget);
This swapped version is only a C convenience for already existing functions, e.g. you can do something like this:
g_signal_connect_swapped(G_OBJECT(search_entry), "activate",
G_CALLBACK(g_print), "Activate signal called");
Related
I have seen people pass a widget like this
static void on_button_click(GtkWidget *button, gpointer data) {
gtk_label_set_label(GTK_LABEL(data), "Hello, World!");
}
...
g_signal_connect(button, "clicked", G_CALLBACK(on_button_click), label);
but how do you pass 2 widgets like a label and an entry?
I want to write a calculator so I need to read from the entry, parse and write the results to the label when the user click (on) the button.
Thanks in advance for helping this noob.
The last argument (gpointer data) can point to whatever you want, so options are basically limitless.
I think in order from "quick hack for a demo app" up to "scalable/maintainable for large, complex applications", some of these options might be:
For a simple program with only a handful of widgets, I might be inclined to just store the GtkWidget pointers in global memory:
GtkWidget *window;
GtkWidget *label;
GtkWidget *btnEnter;
GtkWidget *btnClear;
GtkWidget *entry;
// copy entry to label for simple demo purposes
static void on_enter_button_click(GtkWidget *button, gpointer data) {
// data unused, just get global references to label + entry
gtk_label_set_label(GTK_LABEL(label), gtk_entry_get_text(entry));
}
// clear the label. maybe this is another function your calculator has
static void on_clear_button_click(GtkWidget *button, gpointer data) {
// data unused, just get global references...
gtk_label_set_label(GTK_LABEL(label), "");
}
int main(int argc, char**argv){
// Initialize all the widgets here
// register unique callbacks
g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), NULL);
g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), NULL);
}
You can group these into a struct if uncomfortable using global memory or want slightly more ability to scale/refactor/reuse your code:
struct MyWidgets {
GtkWidget *window;
GtkWidget *label;
GtkWidget *btnEnter;
GtkWidget *btnClear;
GtkWidget *entry;
};
// copy entry to label for simple demo purposes
static void on_enter_button_click(GtkWidget *button, gpointer data) {
struct MyWidgets *widgets = (struct MyWidgets*) data;
gtk_label_set_label(GTK_LABEL(widgets->label), gtk_entry_get_text(widgets->entry));
}
// clear the label... maybe this is another function your calculator has?
static void on_clear_button_click(GtkWidget *button, gpointer data) {
struct MyWidgets *widgets = (struct MyWidgets*) data;
// data unused, just get global references...
gtk_label_set_label(GTK_LABEL(widgets->label), "");
}
int main(int argc, char**argv){
struct MyWidgets widgets;
// Initialize all the widgets here
// register unique callbacks
g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), &widgets);
g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), &widgets);
}
But for something really simple, above is basically same as first example, but with extra steps :).
Another alternative could be to group widgets within any GtkContainer "class",which may fall out naturally in grouping objects into a particular layout, and then use something like gtk_widget_get_parent() to get parent container, then any one of the several methods on GtkContainer that allows iterating through children.
ANOTHER alternative is composite widgets. This tutorial demonstrates some of the concepts there and implements a single callback function for handling multiple widgets: https://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-20.html
I have a program written in C using the GTK library. In the GUI I have a set of radio buttons, and depending on what button is selected changes if an entry can be edited (or sensitive as gtk calls it).
I have made a struct with all the widgets that I need to pass to my signal handlers. It looks like this (with other widgets removed for simplicity).
typedef struct _gui_ctx {
// more widgets in here
GtkWidget *entry;
} gui_ctx;
And in main I define one like so
gui_ctx ctx;
My entry looks like
GtkWidget *entry = gtk_entry_new();
ctx.entry = entry; //add it to the ctx
My radio buttons look like
GtkWidget *radio_key = gtk_radio_button_new_with_label(NULL, "Key");
GtkWidget *radio_password = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Password");
GtkWidget *radio_random = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Random");
I attach the signal handlers as such
g_signal_connect(radio_key, "toggled", G_CALLBACK(use_key), &ctx);
g_signal_connect(radio_password, "toggled", G_CALLBACK(use_password), &ctx);
g_signal_connect(radio_random, "toggled", G_CALLBACK(use_random), &ctx);
The signal handlers are all basically the same. They are all the same type like so
void use_key(GtkWidget *widget, GdkEvent *event, gpointer data){
gui_ctx *ctx = (gui_ctx *) data;
GtkWidget *entry = ctx->entry;
gtk_widget_set_sensitive(entry, TRUE); // crashes here
}
The program crashes on the last line of the handler function. It says
Segmentation fault (core dumped)
I have tried to find why the issue is happening but it always crashes on that line. Both data and entry are not null so I don't know what's going wrong.
Hey guys so I would like to return value of filename from function (or pointer) but Im to sure how to do it. My filename stores path to file name /home/username/file. So here is my main
gchar *filename = NULL;
button = GTK_WIDGET( gtk_builder_get_object( builder, "button1" ) );
g_signal_connect (button, "clicked", G_CALLBACK (show_dialog), &filename);
And show dialog look like this
static void
show_dialog ( GtkWidget *button,
gint response_id,
gpointer user_data )
/* Init filechoosedialog, builder etc */
{
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechoosedialog));
}
Do I need to change static void show_dialog to gchar show_dialog and at end do I need to do return filename; and what else do I need to declare because Im getting compile error
warning: return makes integer from pointer without a cast
So I would like to add code like this to my main and to get value of filename
if filename != NULL
g_print ("Selected filename: %s\n", filename);
This sounds like a misunderstanding of event driven programming. You don't do things like this in main(), you do it in the event handler. In your example you would call g_print() from show_dialog().
If you want to do something more complex you'll need to know some application state: that's what the g_signal_connect() userdata pointer is for. As an example, if you want to set the filename as the text of a label, you would set a pointer to the label as the user data pointer and can then set the label text in the event handler.
More generically, the userdata pointer can be anything: e.g. a data structure that you can use to store the filename string. Typical usage is an application data struct that is allocated in main: The struct contains all "application global" variables (like filename) and a pointer to the struct is given to all GTK+ callbacks so all functions can access and modify the struct contents.
If the problem was using the userdata pointer, here's an example using just a pointer to the filename as userdata:
g_signal_connect (button, "clicked", G_CALLBACK (button_clicked_cb), &filename);
static void
button_clicked_cb (GtkWidget *button,
gint response_id,
gpointer user_data)
{
char **filename_ptr = (char**)user_data;
*filename_ptr = g_strdup ("newly allocated string that the filename pointer in main() stack will now point to");
}
I'm trying to make a test version of a C program in which the user can load a game level using the GTK file selector. It seems to work, and does open the fileselector window, but crashes when the user tries to select a file. The issue seems to be that the GtkWindow is not being recognized as a GtkWindow, despite being declared as:
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //initialize window
I then save it to the window pointer in the gui struct:
typedef struct gui gui_t;
struct gui {
GtkWidget *window;
GtkWidget *frame;
GtkWidget *menu_bar;
GtkWidget *drawing_area;
GtkWidget *vbox;
level_t *game;
};
Which is then passed to the load_menu callback below, which currently just attempts to print the selected filename:
void gui_load_menu(gpointer data) {
gui_t *gui = (gui_t *)data;
GtkWindow *window = (GtkWindow *)(gui->window);
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new("Load Level", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
fprintf(stdout, "%s", filename);
}
}
These were the particular runtime errors:
(guitest:4445): GLib-GObject-WARNING **: invalid uninstantiatable type guchar' in cast toGtkWindow'
(guitest:4445): Gtk-CRITICAL **: gtk_window_set_transient_for: assertion `parent == NULL || GTK_IS_WINDOW (parent)' failed
Any ideas?
Thanks!
You need to use the correct signature for the callback, which should be
void gui_load_menu(GtkWidget *widget, gpointer data)
Each callback can have a different signature and you need to look at the documentation for the signal you use to see what it is. I'm presuming in this case load is a GtkMenuItem, the documentation is here: http://developer.gnome.org/gtk3/3.2/GtkMenuItem.html#GtkMenuItem-activate
I'm trying to find a way to find out which key is pressed down in C. This will be in a graphical environment, written in GTK2, but I don't think the answer lies there. I think I might be able to do this using Xlib, but I haven't been able to find anything conclusive on this.
Does anyone have any suggestions on how to do this?
I've managed to catch a keypress using the follow code:
GtkWidget *window;
void gtk_widget_set_events(window,GDK_KEY_RELEASE_MASK);
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),NULL);
However, I would like to identify which key is pressed. From the link posted by Aditya Kumar, I know the answer lies with using GdkEventKey, since it is a structure which has a keyval field, but I cannot seem to get the syntax right. What is the correct way of getting this number?
This is a method I've tried:
static void hello( GtkWidget *widget,
guint data ){
g_print ("Hello World, %d was pressed\n",data);}
I tried supplying "data" by doing this when I catch the key_release_event:
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),GdkEventKey.keyval);
However, I get a compiler error like so:
hello.c:85:5: error: expected ‘)’ before ‘.’ token
hello.c:85:5: error: expected expression before ‘,’ token
You are correct with your original syntax.
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
Where the key_event function looks something like (note I am using the gdk_keyval_name to convert the keyval int value to a string for printing):
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
Here's a complete example program:
#include <gtk/gtk.h>
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
while looking at the gdk reference manual i think you can capture the keyboard events using this unless you specifically want to have a 'C' program.
Here is the link to help you out.
http://www.gtk.org/api/2.6/gdk/gdk-Keyboard-Handling.html
event->keyval is a pointer to a struct, where keyval contains a integer value for the key pressed, this has been used above in a function gdk_keyval_name (event->keyval) which gets a actual name for the key.