GTK+/C Avoid preserving space for hidden widgets inside a GtkGrid - c

A GtkGrid contains some widgets. When I hide some of this widgets there is still their space, instead I want to have all visible widgets re-aligned in a "natural way" (without preserving the space of the hidden widgets).
A little example:
#include <gtk/gtk.h>
GtkWidget *label2, *label3;
static gboolean on_button_click (GtkButton *button, gpointer data) {
gtk_widget_hide (label2);
gtk_widget_hide (label3);
return TRUE;
}
int main (int argc, char **argv) {
gtk_init(&argc, &argv);
GtkWidget *window;
GtkWidget *label1 = gtk_label_new("Widget1");
label2 = gtk_label_new("Widget2");
label3 = gtk_label_new("Widget3");
GtkWidget *label4 = gtk_label_new("Widget4");
GtkWidget *button = gtk_button_new_with_label ("Hide widget2 and widget3");
g_signal_connect(button, "clicked", G_CALLBACK (on_button_click), NULL);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
GtkGrid *grid = (GtkGrid*)gtk_grid_new ();
gtk_grid_set_row_spacing((GtkGrid*)grid, 50);
gtk_grid_set_column_spacing((GtkGrid*)grid, 50);
// 2 columns
gtk_grid_insert_column (grid, 0);
gtk_grid_insert_column (grid, 1);
// 2 rows
gtk_grid_insert_row (grid, 0);
gtk_grid_insert_row (grid, 1);
//Add widgets to the grid
gtk_grid_attach(GTK_GRID(grid), label1, 1, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), label2, 2, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), label3, 1, 1, 1, 1);
gtk_grid_attach(GTK_GRID(grid), label4, 2, 1, 1, 1);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), (GtkWidget*)grid, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
this program compiled with:
gcc `pkg-config --cflags gtk+-3.0` test.c `pkg-config --libs gtk+-3.0` -o test
give this window:
clicking on the button, I get this result:
but I want this result:
What is the simplest way to do this?
p.s. I also need to show again the hidden widgets in the same position where they were when happen some events. Imagine to have another button that shows widget2 and widget3 again obtaining the same initial window.

You'll have to remove widget4 and re-pack it into widget2's space. (You attached the widgets to those particular cells in the grid, and so they'll stay there.)
It would be better still to use a different widget than GtkGrid, such as GtkFlowBox, to achieve what you want.

Related

How to add a GtkWidget in a custom one?

I made a custom GTK widget and I need to add a GTK Button to it so to inherit its signals in the custom one. The custom widget is a timeline so I thought to use GTK Buttons to avoid messing with mouse coordinates. When the user wants to move the picture represented by the button or just extend its delay on the timeline itself, signals will be emitted from the button widget and my life will be much easier.
The button of course is not shown on the timeline. that's my problem. I know I have to put the button inside a container but how to do it in the draw function? Does anyone have a clue on how to do it? I googled and looked here but with no luck.
This is the custom widget draw function:
static gboolean img_timeline_draw(GtkWidget *da, cairo_t *cr)
{
GtkWidget *button;
ImgTimelinePrivate *priv = img_timeline_get_instance_private((ImgTimeline*)da);
gint width = gtk_widget_get_allocated_width(da);
cairo_translate (cr, 0 , 12);
img_timeline_draw_time_ticks(da, cr, width);
//Video timeline
cairo_translate (cr, 0 , 20);
cairo_set_source_rgba(cr, priv->video_background[0], priv->video_background[1], priv->video_background[2], priv->video_background[3]);
cairo_set_line_width(cr, 1);
cairo_rectangle(cr, 0,10, width - 2, 59);
cairo_fill(cr);
//separator
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_rectangle(cr, 0,69, width - 2, 3);
cairo_fill(cr);
//Audio timeline
cairo_set_source_rgba(cr, priv->audio_background[0], priv->audio_background[1], priv->audio_background[2], priv->audio_background[3]);
cairo_rectangle(cr, 0,72, width - 2, 59);
cairo_fill(cr);
button = gtk_button_new_with_label("I'm invisible...");
gtk_widget_set_realized(button, TRUE);
gtk_widget_show(button);
return FALSE;
}
And this is the main:
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Imagination timeline widget");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 200);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *timeline = img_timeline_new();
g_object_set(timeline, "total_time", 300, NULL);
g_object_set(timeline, "video_background", "#0084ff", NULL);
g_object_set(timeline, "audio_background", "#0084ff", NULL);
gtk_widget_add_events( timeline, GDK_BUTTON1_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_SCROLL_MASK
| GDK_KEY_PRESS_MASK );
GtkWidget *scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *viewport = gtk_viewport_new(NULL,NULL);
g_signal_connect( G_OBJECT(timeline), "scroll-event", G_CALLBACK(img_timeline_scroll), scrolledwindow1);
gtk_widget_set_hexpand(viewport, TRUE);
gtk_widget_set_vexpand(viewport, TRUE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
gtk_container_add (GTK_CONTAINER(viewport), timeline);
gtk_container_add (GTK_CONTAINER(scrolledwindow1), viewport);
gtk_container_add (GTK_CONTAINER (window), scrolledwindow1);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Ok, the solution was to subclass GtkLayout rather than GtkDrawingArea and use gtk_container_propagate_draw() in the custom widget draw function!

pass string from inputfield to function fails - GTK c-language

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!

gtk 3.4 resize widget and label attached to entry widget

I'm trying to give a GTK+3 gui to a my future project (client FTP) but I've some problems.
This is my first code:
#include <gtk/gtk.h>
/* When "connect" button is clicked a message will appear */
static void print_hello (GtkWidget *widget, gpointer data)
{
g_print ("Connect button clicked\n");
}
int main (int argc, char *argv[]){
/* Declare widgets */
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
GtkWidget *u_name;
GtkWidget *h_name;
GtkWidget *pass;
GtkWidget *label_user;
GtkWidget *label_host;
GtkWidget *label_pass;
/*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, set its title and put it on center */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "FTP Client");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
//gtk_window_set_resizable(GTK_WINDOW(window), FALSE); /* window is NOT resizable */
/* Here we construct the container that is going pack our buttons */
grid = gtk_grid_new ();
/* Pack the container in the window */
gtk_container_add (GTK_CONTAINER (window), grid);
/* Add labels */
label_user = gtk_label_new("Username ");
label_host = gtk_label_new("Hostname ");
label_pass = gtk_label_new("Password ");
/* Add hostname entry and label */
h_name = gtk_entry_new();
gtk_grid_attach (GTK_GRID (grid), label_host, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), h_name, 1, 0, 1, 1);
/* Add username entry and label */
u_name = gtk_entry_new();
gtk_grid_attach (GTK_GRID (grid), label_user, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), u_name, 1, 1, 2, 1);
/* Add password entry and label (visibility set to 0 = not visible */
pass = gtk_entry_new();
gtk_grid_attach (GTK_GRID (grid), label_pass, 0, 2, 1, 1);
gtk_entry_set_visibility (GTK_ENTRY (pass), 0);
gtk_grid_attach (GTK_GRID (grid), pass, 1, 2, 1, 1);
/* Add connect button */
button = gtk_button_new_with_label ("Connect");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
gtk_grid_attach (GTK_GRID (grid), button, 0, 3, 2, 1);
/* Add quit button */
button = gtk_button_new_with_label ("Quit");
g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
gtk_grid_attach (GTK_GRID (grid), button, 0, 4, 2, 1);
/* Now that we are done packing our widgets, we show them all in one go, by calling gtk_widget_show_all() on the window.*/
gtk_widget_show_all (window);
/* All GTK applications must have a gtk_main(). Control ends here and waits for an event to occur (like a key press or a mouse event),
* until gtk_main_quit() is called. */
gtk_main ();
return 0;
}
The problem in that code is that I cannot resize widget if window will be resized. I think that is a gtk_grid problem so I cannot understand how to make "widget fit the window".
How can I do?
PS: i prefer to use the gtk_grid because with GTK+3.4 gtk_table has been deprecated
Set the "hexpand" and/or "vexpand" properties to TRUE on the widgets you want to be expanded. For example, add this code and you'll see u_name fill the available space:
gtk_widget_set_hexpand(u_name, TRUE);
gtk_widget_set_vexpand(u_name, TRUE);

Textbox with a label in a GTK+ program

I am new to GTK+ programming.I wrote a simple GTK+ program where i display a label and a textbox in a window, the label should be to the left of the textbox and i should be able to specify the horizontal length of the textbox. Below is my code so far,the program runs fine but im unable to align the label to the left of the textbox and also set the textbox horizontal length.
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
static void destroy(GtkWidget *widget,gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
GtkWidget *window,*table,*label,*entry;
gtk_init(&argc, &argv);
void initialize_window(GtkWidget *);
//Create the main window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
initialize_window(window);
gtk_widget_show(window);
/* Create a 1x2 table */
table = gtk_table_new (1, 2, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
gtk_widget_show (table);
/* create a new label. */
label = gtk_label_new ("Enter some text: ");
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
gtk_table_attach_defaults (GTK_TABLE (table),label, 0, 1, 0, 1);
gtk_widget_show (label);
//create a text box
entry = gtk_entry_new ();
gtk_entry_set_max_length (GTK_ENTRY (entry),0);
gtk_table_attach_defaults (GTK_TABLE (table),entry, 0, 1, 0, 1);
gtk_widget_show (entry);
gtk_main ();
return 0;
}
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
}
How can i fix this problem ?
Please help
Thank You.
You messed with the table position and don't set aligin if you do not know what it does, it may be a bit missleading.
Here is working code (I think this is what you wanted):
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
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,*entry;
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 (1, 2, 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_max_length (GTK_ENTRY (entry),0);
gtk_table_attach_defaults (GTK_TABLE (table), entry, 0, 1, 0, 1);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
For alignment one can use hbox for horizontal arrangement or vbox for vertical arrangement.

Inserting newlines into a GtkTextView widget (GTK+ programming)

I've got a button which when clicked copies and appends the text from a GtkEntry widget into a GtkTextView widget. (This code is a modified version of an example found in the "The Text View Widget" chapter of Foundations of GTK+ Development.)
I'm looking to insert a newline character before the text which gets copied and appended, such that each line of text will be on its own line in the GtkTextView widget. How would I do this? I'm brand new to GTK+.
Here's the code sample:
#include <gtk/gtk.h>
typedef struct
{
GtkWidget *entry, *textview;
} Widgets;
static void insert_text (GtkButton*, Widgets*);
int main (int argc,
char *argv[])
{
GtkWidget *window, *scrolled_win, *hbox, *vbox, *insert;
Widgets *w = g_slice_new (Widgets);
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Text Iterators");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, -1, 200);
w->textview = gtk_text_view_new ();
w->entry = gtk_entry_new ();
insert = gtk_button_new_with_label ("Insert Text");
g_signal_connect (G_OBJECT (insert), "clicked",
G_CALLBACK (insert_text),
(gpointer) w);
scrolled_win = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (scrolled_win), w->textview);
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start_defaults (GTK_BOX (hbox), w->entry);
gtk_box_pack_start_defaults (GTK_BOX (hbox), insert);
vbox = gtk_vbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (window);
gtk_main();
return 0;
}
/* Insert the text from the GtkEntry into the GtkTextView. */
static void
insert_text (GtkButton *button,
Widgets *w)
{
GtkTextBuffer *buffer;
GtkTextMark *mark;
GtkTextIter iter;
const gchar *text;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w->textview));
text = gtk_entry_get_text (GTK_ENTRY (w->entry));
mark = gtk_text_buffer_get_insert (buffer);
gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
gtk_text_buffer_insert (buffer, &iter, text, -1);
}
You can compile this code using the following command (assuming the file is named file.c):
gcc file.c -o file `pkg-config --cflags --libs gtk+-2.0`
Thanks everybody!
Perhaps you could just insert the newline character the same way you insert other characters:
...
mark = gtk_text_buffer_get_insert (buffer);
gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
/* Insert newline (only if there's already text in the buffer). */
if (gtk_text_buffer_get_char_count(buffer))
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
gtk_text_buffer_insert (buffer, &iter, text, -1);
...
"\n" is a string containing the newline character in C, and it works just fine in GTK (unless it doesn't in Windows for some weird reason).
Unhelpful blurb: The 1 can just as easily be -1 here; it just tells GTK it only needs to read 1 character, which might be a little faster. Granted, that line of code should almost never be a bottleneck :-)

Resources