Using GTK3 in C, I have an interface with buttons. I want a user with a mouse to be able to press a button OR use press a single button on the keyboard to do the same thing.
MWE (modified from GTK3 Hello World example):
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
In this program, the user can press the left arrow key to execute thing. The user can also click on the gui button to execute thing. However, hitting certain keyboard keys such as space or enter will "click" on the gui button to execute thing.
How do I prevent the keyboard from "clicking" on a button which the keyboard cursor is on in this case?
Fake Button Hack
I have hacked a workaround into my code for now using a useless button. I will not be marking this answer as solved since it is very sloppy, but it does the job until something better becomes available.
Description
This hack adds another button with no functions assigned. Using gtk_widget_grab_focus, we force this useless "fakebutton" to hold keyboard focus. We reissue this command every time a button is pressed.
Problems
Grabbing focus back to the fakebutton is slow. The user can issue a quick succession of commands (in the case of the MWE by pressing Left and Space to erroneously issue the otherthing function).
MWE
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
GtkWidget *fakebutton;
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
gtk_widget_grab_focus(fakebutton);
} else {
gtk_widget_grab_focus(fakebutton);
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
fakebutton = gtk_button_new();
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), fakebutton);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
Related
I have for example this code:
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("foo.bar", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
It looks like this:
How can I automatically resize the window, so it has the perfect size for the one button.
With Java Swing, you could simply call pack(), but I wasn't able to find a similar method for GTK.
For GtkWindow there would be gtk_window_resize, but it requires giving an height and width, so I would have to calculate it manually.
This would work with just one button, but anything more complex would be error-prone and prone to failure.
Is there any equivalent to pack?
I need to pick the user's choice and store the value in a global variable then after the user has chosen the vbox with the buttons should disappear and control be returned to create_window(). I don't know if it is the best method for such a task.
#include "test.h"
int number_players;
void create_window() {
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "test");
gtk_window_maximize (GTK_WINDOW (window));
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
get_number_players(window);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
gtk_widget_show_all (window);
g_print("%d\n", number_players);
gtk_main();
}
void get_number_players (GtkWidget *window) {
GtkWidget *vbox, *button_choice1, *button_choice2, *button_choice3;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
button_choice1 = gtk_button_new_with_label("six Players");
button_choice2 = gtk_button_new_with_label("Seven Players");
button_choice3 = gtk_button_new_with_label("nine Players");
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_container_add (GTK_CONTAINER (vbox), button_choice1);
gtk_container_add (GTK_CONTAINER (vbox), button_choice2);
gtk_container_add (GTK_CONTAINER (vbox), button_choice3);
g_signal_connect(G_OBJECT(button_choice1), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(6));
g_signal_connect(G_OBJECT(button_choice2), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(7));
g_signal_connect(G_OBJECT(button_choice3), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(9));
}
void read_choice (GtkWidget *window, gpointer data) {
number_players = GPOINTER_TO_INT(data);
}
void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
From some reason the global variable number_players is not printed correclty if I print in read_choice though I can see the right value.
I have worked recently with gtk+ in c language.
I have tried to communicate between two callbacks in a dialog and not in the main window (like here). But, unlike the solutions in the link, the program crushes (in the second callback when I try to use the widget I get from the parameters).
This is my code for This:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>
static void print_text (GtkWidget *widget, gpointer data)
{
GtkEntry* entry = data;
printf("%s", gtk_entry_get_text(entry));
}
static void open_dialog (GtkWidget *widget, gpointer data)
{
GtkWidget *window = data;
GtkWidget *dialog;
GtkWidget *content_area;
GtkWidget *grid;
GtkWidget *label;
GtkWidget *button;
static GtkEntry *textbox;
dialog = gtk_dialog_new_with_buttons ("Get Text",
window,
GTK_DIALOG_MODAL,
GTK_STOCK_OK,
GTK_RESPONSE_OK,
NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
grid = gtk_grid_new();
gtk_container_add (GTK_CONTAINER (content_area), grid);
label = gtk_label_new("Value: ");
gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
textbox = gtk_entry_new();
gtk_entry_set_text(textbox, "<Value>");
gtk_grid_attach(GTK_GRID(grid), textbox, 1, 0, 1, 1);
gtk_widget_show_all (dialog);
g_signal_connect (GTK_DIALOG (dialog), "response", G_CALLBACK (print_text), textbox);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *entry;
GtkWidget *grid;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Print Text");
g_signal_connect (button, "clicked", G_CALLBACK (open_dialog), window);
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1);
gtk_widget_show_all (window);
}
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
The program should have printed the value of the entry box which in the dialog after closing the dialog. Note: in the main window there is a button that opens the dialog.
Thanks for helping!
Problem is on the print_text function. The prototype for GtkDialog response signal is:
void user_function (GtkDialog *dialog,
gint response_id,
gpointer user_data)
So you must change your function to:
static void print_text (GtkWidget *widget, gint response_id, gpointer data)
{
GtkEntry* entry = data;
printf("%s", gtk_entry_get_text(entry));
gtk_widget_destroy (widget); // This will close the dialog
}
I have an App which as some point Opens a new Window and works fine.
Then After I'm done with it, I need to switch back to the main window.
I understood that I need the function:
gtk_widget_hide();
but I cant figure out how to hide the main Window, to print only the second one and again after I click the button in the second window to go back to the first one.
This is what I have so far:
#include <stdio.h>
#include <gtk/gtk.h>
static void crete_new_wind (GtkWidget *widget);
gboolean destroy (GtkWidget *window);
int main (int argc, char *argv[]){
GtkWidget *window, *button, *box;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "First Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Go to Window B");
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (crete_new_wind), (gpointer) window);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void crete_new_wind (GtkWidget *widget){
GtkWidget *window, *button, *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Second Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);;
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), widget);
button = gtk_button_new_with_label ("Go back to Window A");
g_signal_connect (G_OBJECT (button), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_hide(widget);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
}
gboolean destroy (GtkWidget *widget){
gtk_widget_destroy (widget);
return TRUE;
}
If I click on the button(Go to Window B) I have this:
But the main window is still there, avaible to the user which is not what I need.
Thats because the clicked callback wants two parameters
Change the prototype and the function to
static void crete_new_wind(GtkButton *dummy, gpointer widget);
static void crete_new_wind(GtkButton *dummy, gpointer widget) {
in order to use the second parameter in your function.
I want to set the position of the window using gtk_window_set_position
but it seems that after the window is created, the gtk_window_set_position will not take effect.
I'm wondering how to call gtk_window_set_position after the window shows up, i.e. a button event?
I just wrote a minimal working example that implements two approaches. One approach uses gtk_window_move and the other gtk_window_set_position.
If you have the gtk+ reference at hand the code should be self explanatory.
#include <gtk/gtk.h>
#include <glib.h>
void
button1_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
GdkWindow *root;
gint width, height, rwidth, rheight;
gtk_window_get_size (window, &width, &height);
root = gtk_widget_get_root_window (GTK_WIDGET (window));
gdk_window_get_geometry (root, NULL, NULL, &rwidth,
&rheight);
gtk_window_move (window, (rwidth - width) / 2,
(rheight - height) / 2);
}
void
button2_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
gtk_widget_hide (GTK_WIDGET (window));
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show_all (GTK_WIDGET (window));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *box;
GtkWidget *button1;
GtkWidget *button2;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
button1 = gtk_button_new_with_label ("approach 1");
button2 = gtk_button_new_with_label ("approach 2");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_box_pack_start (GTK_BOX (box), button1, TRUE, TRUE,
10);
gtk_box_pack_start (GTK_BOX (box), button2, TRUE, TRUE,
10);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (button1, "clicked",
G_CALLBACK (button1_clicked_cb),
window);
g_signal_connect (button2, "clicked",
G_CALLBACK (button2_clicked_cb),
window);
gtk_main ();
return 0;
}