I want to ask the user in a GTK+ assistant for his name, save this name in a global variable and use this variable in the same assistant on a different site. My problem is that the assistant is completly created and changes on new sites have no effect.
Example:
I initialisize the global variable "name" with "empty". Now, the assistant create all sites but displays only the first site. The user writes down his name in the "entryfield" and the variable "name" now contains his name.
The assistant now displays the second site which should contain the users name, but it displays the string "empty".
I need to "refresh" this already created entry with the new variable.
Sorry for my bad english, I hope I can explain my problem a little bit. :)
Complete sample code:
#include <gtk/gtk.h>
#include <string.h>
static void entry_changed (GtkEditable*, GtkAssistant*);
static void assistant_cancel (GtkAssistant*, gpointer);
static void assistant_close (GtkAssistant*, gpointer);
char *name = "empty";
typedef struct {
GtkWidget *widget;
gint index;
const gchar *title;
GtkAssistantPageType type;
gboolean complete;
} PageInfo;
int main (int argc,
char *argv[])
{
GtkWidget *assistant, *entry, *label;
guint i;
PageInfo page[5] = {
{ NULL, -1, "Introduction", GTK_ASSISTANT_PAGE_INTRO, TRUE},
{ NULL, -1, NULL, GTK_ASSISTANT_PAGE_CONTENT, FALSE},
{ NULL, -1, NULL, GTK_ASSISTANT_PAGE_CONTENT, TRUE},
{ NULL, -1, "Confirmation", GTK_ASSISTANT_PAGE_CONFIRM, TRUE},
};
gtk_init (&argc, &argv);
/* Create a new assistant widget with no pages. */
assistant = gtk_assistant_new ();
gtk_widget_set_size_request (assistant, 450, 300);
gtk_window_set_title (GTK_WINDOW (assistant), "GtkAssistant Example");
g_signal_connect (G_OBJECT (assistant), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
page[0].widget = gtk_label_new ("This is an example of a GtkAssistant. By\n"\
"clicking the forward button, you can continue\n"\
"to the next section!");
page[1].widget = gtk_hbox_new (FALSE, 5);
page[2].widget = gtk_entry_new();
page[3].widget = gtk_label_new ("finish!");
/* Create the necessary widgets for the second page. */
label = gtk_label_new ("Your Name: ");
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (page[1].widget), label, FALSE, FALSE, 5);
gtk_box_pack_start (GTK_BOX (page[1].widget), entry, FALSE, FALSE, 5);
gtk_entry_set_text(GTK_ENTRY(page[2].widget), name);
/* Add four pages to the GtkAssistant dialog. */
for (i = 0; i < 4; i++)
{
page[i].index = gtk_assistant_append_page (GTK_ASSISTANT (assistant),
page[i].widget);
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant),
page[i].widget, page[i].title);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant),
page[i].widget, page[i].type);
/* Set the introduction and conclusion pages as complete so they can be
* incremented or closed. */
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant),
page[i].widget, page[i].complete);
}
/* Update whether pages 2 through 4 are complete based upon whether there is
* text in the GtkEntry, the check button is active, or the progress bar
* is completely filled. */
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (entry_changed), (gpointer) assistant);
g_signal_connect (G_OBJECT (assistant), "cancel",
G_CALLBACK (assistant_cancel), NULL);
g_signal_connect (G_OBJECT (assistant), "close",
G_CALLBACK (assistant_close), NULL);
gtk_widget_show_all (assistant);
gtk_main ();
return 0;
}
/* If there is text in the GtkEntry, set the page as complete. Otherwise,
* stop the user from progressing the next page. */
static void
entry_changed (GtkEditable *entry,
GtkAssistant *assistant)
{
const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
gint num = gtk_assistant_get_current_page (assistant);
GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
gtk_assistant_set_page_complete (assistant, page, (strlen (text) > 0));
name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
}
/* If the dialog is cancelled, delete it from memory and then clean up after
* the Assistant structure. */
static void
assistant_cancel (GtkAssistant *assistant,
gpointer data)
{
gtk_widget_destroy (GTK_WIDGET (assistant));
}
/* This function is where you would apply the changes and destroy the assistant. */
static void
assistant_close (GtkAssistant *assistant,
gpointer data)
{
g_print ("You would apply your changes now!\n");
gtk_widget_destroy (GTK_WIDGET (assistant));
}
in entry_changed, you will have to call gtk_entry_set_text(GTK_ENTRY(page[2].widget), name); again, as you only set the entry text once, which is the only thing that matters. Otherwise the default value you set when setting up the 3rd page sticks.
Related
I am receiving this error and not sure why...Please take a look at my buttons array, maybe I messed smth there, I am not sure...
The error i get is: Xlib: extension "RANDR" missing on display ":24.0".
and nothing happens after that, meaning my program doesnt run at all....
#include <gtk/gtk.h>
/* Our new improved callback. The data passed to this function
* is printed to stdout. */
static void callback (GtkWidget *widget, gpointer data)
{
system ((gchar *) data);
}
/* another callback */
static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
return FALSE;
}
int main (int argc, char *argv[])
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *box1;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* This is a new call, which just sets the title of our
* new window to "My Assignments" */
gtk_window_set_title (GTK_WINDOW (window), "My Assignments");
/* Here we just set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 50);
/* We create a box to pack widgets into. This is described in detail
* in the "packing" section. The box is not really visible, it
* is just used as a tool to arrange widgets. */
box1 = gtk_vbox_new (FALSE,0);
/* Put the box into the main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/*array is here*/
GtkWidget *button[2];
int i;
for (i=0; i<2; i++)
{
button[i]=gtk_button_new();
}
button[0] = gtk_button_new_with_label ("Run shellscript");
g_signal_connect (button[0], "clicked",
G_CALLBACK (callback), "shellscript");
gtk_box_pack_start (GTK_BOX (box1), button[0], TRUE, TRUE, 0);
gtk_widget_show(button[0]);
button[1] = gtk_button_new_with_label ("Run program2 ");
g_signal_connect (button[1], "clicked",
G_CALLBACK (callback), "program");
gtk_box_pack_start (GTK_BOX (box1), button[1], TRUE, TRUE, 0);
gtk_widget_show(button[1]);
gtk_widget_show (box1);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
I have one issue with gtk in c . I tried to follow the tutorial but I am not able to pass a text-entry to a function when one clicks on the button in the widget.
The code compiles fine but when I press the button I get several warnings and the string from text-entry that was supposed to be printed are null
What did I do wrong?
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
static GtkWidget *asset_label;
static GtkWidget *frame;
static GtkWidget *entry;
static void entry_Submit(GtkWidget *widget, GtkWidget *entry)
{
const gchar *text = gtk_entry_get_text(GTK_ENTRY (entry));
printf ("Result: %s\n", text);
gtk_widget_destroy(GTK_WIDGET(asset_label));
asset_label = gtk_label_new (text);
gtk_container_add (GTK_CONTAINER (frame), asset_label);
gtk_widget_show_all(frame);
}
static void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
static void initialize_window(GtkWidget* window)
{
gtk_window_set_title(GTK_WINDOW(window),"My Window"); //Set window title
gtk_window_set_default_size (GTK_WINDOW (window), 400, 200); //Set default size for the window
g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL); //End application when close button clicked
}
int main (int argc, char *argv[])
{
GtkWidget *window,*table,*label, *button;
gtk_init(&argc, &argv);
//Create the main window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
initialize_window(window);
/* Create a 1x2 table */
table = gtk_table_new (3, 3, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
/* create a new label. */
label = gtk_label_new ("Enter some text:" );
//gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
gtk_table_set_homogeneous(GTK_TABLE (table), TRUE);
gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 0, 1);
//create a text box
entry = gtk_entry_new ();
//gtk_entry_set_text (GTK_ENTRY (entry), "");
gtk_entry_set_max_length (GTK_ENTRY (entry),0);
gtk_table_attach_defaults (GTK_TABLE (table), entry, 0, 1, 0, 1);
button = gtk_button_new_with_label("Calculate");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (entry_Submit), entry);
gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
//gtk_widget_show (button);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
And when the button is clicked I get this result:
Result: (null)
There is a problem in the callback or the way you are registering the callback (as fixing either one of them should fix your problem).
By default the clicked callback takes GtkButton as the first parameter and gpointer data as the second. By using g_signal_connect_swapped you are saying that in the callback function, the parameters will be swapped i.e., the first parameter will be gpointer data (GtkEntry in your code) and second GtkButton. But in your callback function you are treating second parameter entry which is in fact GtkButton as GtkEntry. Either use g_signal_connect instead of g_signal_connect_swapped or use the first parameter widget as GtkEntry in your callback function.
Side note: Regarding the warning, if the code which you have posted is the full code then in the callback function entry_Submit during first execution asset_label is null and thus gtk_widget_destroy(GTK_WIDGET(asset_label)); will throw a warning. Also, frame is unassigned before use in the callback function.
Hope this helps!
I've tried a few things and may be nearing a solution but here goes ...
on a (possibly realised) widget, has anyone got a good example of say an
GtkEntry widget receiving a ALT+ Down or CTRL + n key press which will raise
a "new" signal e.g. SIG-NEW on the widget. which I know how to catch with g_signal_connect.
I appended a minimal working example.
The important point is to connect the key-press-event of an GtkEntry-instance to a suitable callback. In that callback you have to extract the GdkEventKey struct that is a member of the GdkEvent struct which is a parameter of the callback function.
GdkEventKey contains all information you need to check which key+modifier was pressed.
Since i tested the code with gtk+-3.0 you may have to modify the GdkEventMask of the widget to receive key-press-event's. For gtk+-3.0 it seems that is already the default setting. If the callback isn't invoked you should enable it with gdk_window_set_events () (of course you have to invoke it upon the gdk window of the widget).
#include <gtk/gtk.h>
#include <glib.h>
gboolean
key_press_event_cb (GtkWidget * widget, GdkEvent * event,
gpointer data)
{
GdkEventKey key = event->key;
/* check modifier key */
/* on most keyboards GDK_MOD1_MASK is the Alt key */
if (key.state == GDK_MOD1_MASK) {
/* check for key that was pressed */
switch (key.keyval) {
case GDK_KEY_d:
g_print
("`Alt-d` deletes the content in the entry box\n");
gtk_entry_set_text (GTK_ENTRY (widget), "");
break;
}
}
/* check for unmodified key presses */
switch (key.keyval) {
case GDK_KEY_x:
g_print
("`x` deletes the content in the entry box\n");
gtk_entry_set_text (GTK_ENTRY (widget), "");
return TRUE;
break;
}
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *entry;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
entry = gtk_entry_new ();
gtk_container_add (GTK_CONTAINER (window), entry);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (entry, "key-press-event",
G_CALLBACK (key_press_event_cb), NULL);
gtk_main ();
return 0;
}
I've looked all over the place. Either I didn't look hard enough, or it is my lack of knowledge in C and GTK+. I am making a program similar to the program invoked when Alt+F2 is pressed. This is just for the learning experience. I have made a button called "button" in which you click it after typing in the program you want to run. I've been trying all day to program the button to also work when the "enter key" is pressed. Here is a part of my program responsible for invoking action to assigned widgets.
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
static GtkWidget *entry;
static gboolean kill_window(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit();
return FALSE;
}
static void button_press(GtkWidget *widget, gpointer data)
{
const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
//system("cd" text);
//printf("%s\n", text);
const char *text2 = "&";
char *concatenation;
concatenation = malloc(strlen(text)+2);
strcpy(concatenation, text);
strcat(concatenation, text2);
system(concatenation);
gtk_main_quit();
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button1;
GtkWidget *hbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("Run");
button1 = gtk_button_new_with_label("Cancel");
entry = gtk_entry_new();
hbox = gtk_vbox_new(FALSE, 2);
gtk_window_set_title(GTK_WINDOW(window), "Run");
g_signal_connect(window, "delete_event", G_CALLBACK(kill_window), NULL)
g_signal_connect(button, "clicked", G_CALLBACK(button_press), NULL);
g_signal_connect(button1, "clicked", G_CALLBACK(kill_window), NULL);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 100);
gtk_window_set_decorated(GTK_WINDOW(window), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), button1, FALSE, FALSE, 2);
gtk_container_add(GTK_CONTAINER(window), hbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
All I need now is to get "button" to be invoked when pressing the "enter key". (Sorry if i sound redundant.)
So as I see you need to add "Enter Button" signal handler to the text box, not to the button.
Try to add
g_signal_connect(entry, "activate", G_CALLBACK(button_press), NULL);
(Sorry I cant check it right now)
You should catch the activate signal of your entry, and have the callback do the same as your button click handler.
g_signal_connect(entry, "activate", G_CALLBACK(button_press), NULL);
When you have a dialog like this GTK provides the concept of a default widget which is activated when you press Enter on any GtkEntry that has the activates-default property set to true. There is no need to explicitly connect a signal and the default widget is highlighted so the user can see which button will be activated when they press enter. To set it up add the following
g_object_set (G_OBJECT (button), "can-default", TRUE, "has-default", TRUE, NULL);
g_object_set (G_OBJECT (entry), "activates-default", TRUE, NULL);
/* Could do this instead of the second g_object_set
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); */
You could also use gtk_button_new_from_stock rather than gtk_button_new. You might want to check out g_spawn_command_line_async as well.
Maybe I am misunderstanding the question but capturing the "enter key" in C. Is done in the following way.
int enter_key = getch(stdin);
if(enter_key == '\r')
{
//Do whatever is necessary.
}
The '\r' is called a carriage return and can also be referenced using it's octagonal value '\015'. Also a newline('\n' '\012') may be returned instead of a carriage return so you might want to do the following instead.
if(enter_key == '\r' || enter_key == '\n')
{
//Do whatever is necessary
}
I am developing an application that has a numeric keypad and a text box when clicked on a button, text box shows the number.
I need to write a function to each button? Or you can pass a text and a widget as parameter?
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
void callback( GtkWidget *widget,
gpointer data )
{
gtk_entry_append_text(entry, text);
}
void create_button(GtkWidget* table,GtkWidget* entry,
int start_r,int end_r,
int start_c,int end_c,
char* label)
{
GtkWidget *button;
button = gtk_button_new_with_label (label);
g_object_set_data( G_OBJECT( button ),
"char", (gpointer)label );
g_signal_connect (button, "clicked",
G_CALLBACK (callback), entry);
gtk_table_attach_defaults (GTK_TABLE(table), button, start_c, end_c, start_r, end_r);
gtk_widget_show (button);
}
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit ();
return(FALSE);
}
int main(int argc,char* argv[]){
GtkWidget *window;
//GtkWidget *button;
GtkWidget *table;
GtkWidget *entry;
//GtkWidget *label;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Armario");
g_signal_connect (GTK_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
table = gtk_table_new (2, 2, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
entry = gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(entry),10);
gtk_entry_set_placeholder_text(GTK_ENTRY(entry),"Teste");
gtk_table_attach_defaults (GTK_TABLE(table), entry, 0, 2, 1, 2);
gtk_widget_show(entry);
create_button(table,entry,0,1,0,1,"Botao");
gtk_widget_show (table);
gtk_widget_show (window);
gtk_main ();
return 0;
}
The answer to your question is yes, you can pass a widget in Gtk+ to a callback. Actually, the first parameter of the callback for the clicked signal is the button which received the signal (ie. usually the button that was clicked). As you can see in the sample code below, you can extract from the button its label and use it as text.
[...] /* In create_button... */
/* Make your buttons be notified when they are clicked */
g_signal_connect (button, "clicked", G_CALLBACK (on_button_clicked), entry);
[...]
/* Append the text in the button to the text entry */
void on_button_clicked (GtkButton *button, gpointer user_data)
{
GtkEntry *entry = user_data;
const gchar *text = gtk_button_get_label (button);
gint position = 0;
gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &position);
}
I'm using gtk_editable_insert_text because gtk_entry_append_text has been deprecated for a long time. Passing the "entry" parameter to the callback is possible by using the last parameter of g_signal_connect which allows you to specify some data that you need to access in your callback. This info is then made available to the callback in the "user_data" parameter.
Your exemple could also be improved by using gtk_widget_show_all, and I also don't see the point in calling g_object_set_data on the "char" property, as the text is already set in the label property (and retrieved with gtk_button_get_label).
Two options, that I can think of:
GTK widgets are really GObjects, so you can attach to them arbitrary pieces of data. See the functions g_object_set_data/g_object_set_data_full/g_object_get_data. So you can just add the text to the button as an attached data and retrieve it when needed.
You can pass any data you need to a callback by defining a struct with all the fields, and passing a pointer to it. If the struct cannot be declared statically, you can malloc it and use g_signal_connect_data to specify the function to release the data:
For example:
struct entry_and_text;
{
GtkWidget *w;
char *text;
};
void free_data(gpointer data, GClosure *closure)
{
free(data);
}
entry_and_text *data = (entry_and_text *)malloc(sizeof(entry_and_text));
data->w = entry;
data->text = label;
g_signal_connect_data (button, "clicked",
G_CALLBACK (callback), data, free_data, 0);