How do I put a GTKScrolledWindow inside of another container? - c

I want to have a scrollable GtkTextView in my GtkWindow, but I only want the GtkTextView part to scroll instead of the whole window. I tried to put the GTKTextView inside of a GtkScrolledWindow and put the GtkScrolledWindow inside of a GtkFixed container, but then the GtkTextView doesn't show up. When I put the GtkTextView directly inside the GtkFixed container, though, it shows up.
#include <gtk/gtk.h>
GtkWidget *window, *scrolled_window, *fixed, *log_box, *button1;
GtkTextBuffer *log_box_buffer;
static void button1_clicked(GtkWidget *widget, gpointer data) {
printf("button1_clicked\n");
gtk_text_buffer_insert_at_cursor(log_box_buffer, "You clicked the button.\n", 24);
}
static void app_activate(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window Title Here");
gtk_window_set_default_size(GTK_WINDOW(window), 700, 400);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
fixed = gtk_fixed_new();
button1 = gtk_button_new_with_label("Button 1");
g_signal_connect(button1, "clicked", G_CALLBACK(button1_clicked), NULL);
log_box_buffer = gtk_text_buffer_new(NULL);
log_box = gtk_text_view_new_with_buffer(log_box_buffer);
gtk_fixed_put(GTK_FIXED(fixed), button1, 50, 50);
/* Here I tried to put the textview inside of the scrolled window and
add the scrolled window to the fixed container. The textview
doesn't show up when I do this. */
gtk_container_add(GTK_CONTAINER(scrolled_window), log_box);
gtk_fixed_put(GTK_FIXED(fixed), scrolled_window, 200, 50);
/* I also tried putting the textview directly in the fixed container.
This shows up, but obviously I can't scroll it. */
// gtk_fixed_put(GTK_FIXED(fixed), log_box, 200, 50);
gtk_container_add(GTK_CONTAINER(window), fixed);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("the.application.id", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

not sure why you want to use a fixed container. If so you must supply the width and height of the scrolled window, which contains the textview. I've compiled your code and it works. Just add:
gtk_widget_set_size_request (GTK_WIDGET(scrolled_window), 200, 200);
and this will set a size of 200 by 200, as an example, on your scrolled window.

Related

how to change multiple widgets property on button click GTK c

I am trying to make UI using GTK in c for raspberry pi 4. I want to change the visibility of different widgets based on button click just to simulate a new page. I have tried everything available on the internet but as I am not that good at coding I cant figure out what is wrong.
can someone please help ?
This program compiles but when I press the button it gives error " assertion failed on gtk_widget_show " and also on widget hide. Also a segmentation fault occurs and the program crashes.
I am using cmake to compile my code. I have attached the error screen shot.
#include <gtk/gtk.h>
typedef struct AppData
{
GtkWidget *label1;
GtkWidget *label2;
} AppData;
static void button1 (gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_hide(data2->label1);
gtk_widget_show(data2->label2);
}
static void button2 ( gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_show(data2->label1);
gtk_widget_hide(data2->label2);
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *btn1;
GtkWidget *btn2;
GtkWidget *box1;
GtkWidget *box2;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "ethercat test 1");
gtk_window_set_default_size(GTK_WINDOW(window), 1000,500);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
gtk_fixed_put(GTK_FIXED(fixed), box1, 0,0);
box2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
gtk_fixed_put(GTK_FIXED(fixed), box2, 100,100);
AppData *app_data = g_new0 (AppData, 2);
app_data->label1 = gtk_label_new("label1");
gtk_box_pack_start(GTK_BOX(box1),app_data->label1, TRUE,TRUE,0);
app_data->label2 = gtk_label_new("label2");
gtk_box_pack_start(GTK_BOX(box2),app_data->label2, TRUE,TRUE,0);
btn1 = gtk_button_new_with_label("ethercat 1");
gtk_fixed_put(GTK_FIXED(fixed), btn1, 10, 450);
gtk_widget_set_size_request(btn1, 80,30);
btn2 = gtk_button_new_with_label("ethercat 2");
gtk_fixed_put(GTK_FIXED(fixed), btn2, 110, 450);
gtk_widget_set_size_request(btn2, 80,30);
gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(btn1), "clicked", G_CALLBACK(button1), app_data);
g_signal_connect(G_OBJECT(btn2), "clicked", G_CALLBACK(button2), app_data);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
printf("program end\n");
return (0);
}
enter image description here
The function signature of your "clicked" callbacks is wrong. It should be of the form as described in the documentation:
void on_clicked(
GtkButton* self,
gpointer user_data
)
So for example, your button2() function becomes
static void button2 (GtkButton *btn2, gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_show(data2->label1);
gtk_widget_hide(data2->label2);
}

When is GtkTextView's preferred size updated?

I have noticed that GtkTextView's preferred size doesn't change immediately after its contents are changed, but only sometime later in event processing.
In following example, when you click the button, the text in GtkTextView is updated via gtk_text_buffer_set_text(). The new text is long enough to cause a line wrap, and so the preferred height of the control should change. But the gtk_widget_get_preferred_size() still reports old preferred height. Later, in 'size-allocate' event handler, the gtk_widget_get_preferred_size() is already reporting correct size for new contents.
I am trying to understand what happens between the return from button's 'clicked' event handler and 'size-allocate' event handler, that causes GtkTextView's preferred size to update to reflect its changed contents.
#include <gtk/gtk.h>
static bool button_clicked(GtkWidget* obj, GtkWidget* view)
{
// set text in GtkTextView to
const char* long_text="aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa";
printf("----------------------------\n");
printf("in button_clicked(): setting text\n");
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_set_text(buffer, long_text, -1);
GtkRequisition req;
gtk_widget_get_preferred_size(view, &req, NULL);
printf("in button_clicked(): preferred height = %u\n", req.height);
return false;
}
static bool on_size_allocate(GtkWidget* obj, GdkRectangle *allocation, GtkWidget* view)
{
GtkRequisition req;
gtk_widget_get_preferred_size(view, &req, NULL);
printf("in on_size_allocate(): preferred height = %u\n", req.height);
return false;
}
static void activate(GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW (window), "Wrapped text");
gtk_window_set_default_size(GTK_WINDOW (window), 200, 200);
gtk_widget_show_all(window);
GtkTextBuffer* buffer = gtk_text_buffer_new(NULL);
GtkWidget* view = GTK_WIDGET(gtk_text_view_new_with_buffer(buffer));
g_object_unref(buffer);
gtk_widget_set_size_request(view, 180, -1);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
g_signal_connect(view, "size-allocate", G_CALLBACK(on_size_allocate), view);
GtkWidget *button = gtk_button_new_with_label("Set Text");
g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), view);
GtkWidget* grid = gtk_grid_new();
gtk_container_add(GTK_CONTAINER(window), grid);
gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), view, 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;
}
This displays:
in on_size_allocate(): preferred height = 17
----------------------------
in button_clicked(): setting text
in button_clicked(): preferred height = 17
in on_size_allocate(): preferred height = 34

(Stack:7229): Gdk-CRITICAL **: 11:09:22.221: gdk_window_get_origin: assertion 'GDK_IS_WINDOW (window)' failed

I am trying to build an App in linux Ubuntu with C and GTK3 and I get an Error about gdk_window_get_origin and I can not figure out what I am doing wrong.
The app runs and the Window is indeed the size of my Screen, but there is this warning which I cannot fix it:
(Stack:7229): Gdk-CRITICAL **: 11:09:22.221: gdk_window_get_origin: assertion 'GDK_IS_WINDOW (window)' failed
Screen max: 1600W X 900H
Here is a sample code:
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
GtkWidget *window;
gint width, height;
gtk_init(&argc, &argv);
/// Creating the Window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/// Get window Size
GdkDisplay *dpy = gtk_widget_get_display( window );
GdkWindow *win = gtk_widget_get_window(window);
GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
/// Get window Geometry
GdkRectangle geometry;
gdk_monitor_get_geometry(monitor, &geometry);
width = geometry.width;
height = geometry.height;
g_print("Screen max: %dW X %dH\n", width, height);
// Setting the default size of the Window
gtk_window_set_default_size(GTK_WINDOW(window), width, height );
// Destroy the Window
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
}
TL;DR: You are trying to access GdkWindow before GtkWindow is realized.
From gtk_widget_get_window documentation:
Returns the widget’s window if it is realized, NULL otherwise
And gtk_widget_realize:
Creates the GDK (windowing system) resources associated with a widget.
For example, widget->window will be created when a widget is realized.
Normally realization happens implicitly; if you show a widget and all
its parent containers, then the widget will be realized and mapped
automatically.
You need to either call gtk_widget_realize before trying to access GdkWindow with gtk_widget_get_display or postpone the access until the window is realized (after the start of the Gtk main loop) using callback to realize signal:
#include <gtk/gtk.h>
void print_geometry(GtkWidget* widget, GdkRectangle* geometry)
{
GdkDisplay *dpy = gtk_widget_get_display(widget);
GdkWindow *win = gtk_widget_get_window(widget);
GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
gdk_monitor_get_geometry(monitor, geometry);
gint width = geometry->width;
gint height = geometry->height;
g_print("Screen max: %dW X %dH\n", width, height);
gtk_window_set_default_size(GTK_WINDOW(widget), width, height );
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GdkRectangle geometry;
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "realize", G_CALLBACK(print_geometry), &geometry);
gtk_widget_show_all(window);
gtk_main();
}

GTK3 resize attempt grows window exponentially

I have a C GTK3 program that has a notebook with two images. I want to be able to grab the corner of the window and adjust the size of the image currently displayed. What I currently have is a program that once started, the window keeps growing until I kill it from the terminal using ctrl-c. I put a sleep call in the callback to slow it down, but it still grows. How do I stop the window from growing unless I "grab" a corner of the window and adjust it myself?
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
GtkWidget *notebook;
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation,
gpointer user_data)
{
int w,h, pagenum;
GdkPixbuf *pxbscaled;
GtkWidget *image;
GdkPixbuf *pixbuf;
pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
image = gtk_notebook_get_nth_page (GTK_NOTEBOOK(notebook), pagenum);
// GtkImageType image_type = gtk_image_get_storage_type
// (GTK_IMAGE(image));
pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));
h = allocation->height;
w = (gdk_pixbuf_get_width(pixbuf) * h) / gdk_pixbuf_get_height(pixbuf);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR);
printf("Allocation height %d width %d.\n", h, w);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
sleep(2);
return FALSE;
}
static gboolean delete( GtkWidget *widget,
GtkWidget *event,
gpointer data )
{
gtk_main_quit ();
return FALSE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
GtkWidget *label;
GtkWidget *image;
int i;
char bufferl[32];
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
// gtk_widget_set_size_request (GTK_WIDGET(window), 800, 480);
g_signal_connect (window, "delete-event",
G_CALLBACK (delete), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
table = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), table);
/* Create notebook, place position of tabs */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_grid_attach (GTK_GRID (table), notebook, 0, 6, 3, 3);
gtk_widget_show (notebook);
/* Append pages to the notebook */
for (i = 0; i < 2; i++) {
sprintf(bufferl, "Page %d", i + 1);
if (i == 0) {
image = gtk_image_new_from_file("image1.jpg");
} else {
image = gtk_image_new_from_file("image2.jpg");
}
gtk_widget_set_halign(image, GTK_ALIGN_START);
gtk_widget_set_valign(image, GTK_ALIGN_START);
g_signal_connect(window, "size-allocate",
G_CALLBACK(resize_image), NULL);
label = gtk_label_new (bufferl);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook),
image, label);
}
/* Create a close button */
button = gtk_button_new_with_label ("close");
g_signal_connect (button, "clicked",
G_CALLBACK (delete), NULL);
gtk_grid_attach (GTK_GRID (table), button, 0, 10, 1, 1);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
A user will need to provide image1.jpg and image2.jpg. Edit out the sleep call will result in the program filling the screen extremely quickly.
EDIT: I have also asked this question on the gtk mailing list.
The window with the image was growing because I was applying the size of the window to the image. Hence the image got larger and thus made the window get larger. Which continued in an endless progression, the "size-allocate" signal was constantly being called.
I fixed it by limiting the allocation height in the call back, by multiplying it by 0.75.
Now I can expand and contract the window with ease and it does not grow out of control.
The image does get ugly quite quickly, but that is another problem.

C: How to replace GtkAlignment function with newer GtkWidget align property

I am a new C programmer coming from Java. After reading some old books and articles, I've written the following code:
#include <gtk/gtk.h>
static void activate(GtkApplication* app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button1;
GtkWidget *box;
box = gtk_alignment_new(0, 0, 0, 0);
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Calculator");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 400);
gtk_container_add(GTK_CONTAINER(window), box);
button1 = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button1), "1");
gtk_widget_set_size_request(button1, 40, 30);
gtk_container_add(GTK_CONTAINER(box), button1);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("me.test.calculator", 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 code compiles and runs correctly. The problem is that gtk_alignment_new is deprecated and I want to get rid of it.
I've tried replacing gtk_alignment_new with:
gtk_widget_set_halign(box, GTK_ALIGN_START);
gtk_widget_set_valign(box, GTK_ALIGN_START);
but the window does not show up when using this method. Thanks.
You want to set the halign/valign properties of the button (and then add the button straight into the window) to achieve the same functional results as your original code. 'box' is no longer needed at all.
Note that a GtkWindow is a GtkBin so only takes a single child: you will need to add additional containers in between to actually make a calculator. Maybe start by adding a GtkGrid as the sole window child and then attach all your buttons into the grid.
Using jku's advice I've written the following code which compiles and runs correctly without using gtk_alignment_new:
#include <gtk/gtk.h>
static void activate(GtkApplication* app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button1;
GtkWidget *fixed;
fixed = gtk_fixed_new();
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Calculator");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 400);
gtk_container_add(GTK_CONTAINER(window), fixed);
button1 = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button1), "1");
gtk_widget_set_size_request(button1, 45, 35);
gtk_fixed_put(GTK_FIXED(fixed), button1, 5, 200);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("me.test.calculator", 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;
}
NOTE: I ended up using GtxFixed because the size of the window will be fixed as well.

Resources