Gtk, How to scroll at bottom of viewport list? - gtk

I have created one list with GtkVBox and GtkViewPort.
and i am doing the scroll by two up/down GtkButtons.
GtkAdjustment* adjustment;
adjustment = gtk_viewport_get_vadjustment(GTK_VIEWPORT(viewport_ptr));
gtk_adjustment_set_value(adjustment, gtk_adjustment_get_value(adjustment)+(gdouble)SCROLL_SIZE);
gtk_widget_show_all(viewport_ptr);
But when I add the widget to VBox it gets added at the end of the VBox as I am using gtk_box_pack_start. So i want to scroll viewport up to this newly added last widget which is at bottom of the list.

Did you try just setting the adjustment to the maximum value:
gtk_adjustment_set_value(adjustment, gtk_adjustment_get_upper(adjustment));
Note that you might need to delay this, or trigger it from a suitable event, since the upper bound will change as the scrolled vbox grows.
My suggestion would be to hook it into the size-allocate signal of the GtkVBox.

Here's an example that shows what #unwind means when he suggests hooking the adjustment into the size-allocate signal.
/***
This basic example program shows how to (automatically) move the
scrollbar of a GTK+ text view to the very bottom after text has been added.
Public domain code by N.L.M. de Jonge.
gcc `pkg-config gtk+-3.0 --cflags` -O2 -std=c99 -g -pedantic -Wall \
-Wextra -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes \
-Wmissing-prototypes -D_REENTRANT example.c -o example `pkg-config \
gtk+-3.0 --libs`
***/
#include <gtk/gtk.h>
#include <stdlib.h>
GtkAdjustment *adj;
GtkWidget *scroll;
GtkTextBuffer *buffer;
GtkTextIter iter;
int iCounter;
void ScrollToEnd (GtkWidget *widget, GdkRectangle *allocation);
void Add (GtkButton *button);
/*****************************************************************************/
void ScrollToEnd (GtkWidget *widget, GdkRectangle *allocation)
/*****************************************************************************/
{
if (widget != NULL) { }
if (allocation != NULL) { }
adj = gtk_scrolled_window_get_vadjustment
(GTK_SCROLLED_WINDOW (scroll));
gtk_adjustment_set_value (adj, gtk_adjustment_get_upper (adj));
}
/*****************************************************************************/
void Add (GtkButton *button)
/*****************************************************************************/
{
char sText[10];
if (button != NULL) { }
iCounter++;
snprintf (sText, 10, "\n%i", iCounter);
gtk_text_buffer_get_end_iter (buffer, &iter);
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
g_locale_to_utf8 (sText, -1, NULL, NULL, NULL), -1, "red_fg", NULL);
/*** We just added text, but we do NOT call ScrollToEnd() here. ***/
}
/*****************************************************************************/
int main (int argc, char *argv[])
/*****************************************************************************/
{
GtkWidget *window, *box, *grid, *text, *button;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete_event",
G_CALLBACK (exit), NULL);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_widget_realize (window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show (box);
grid = gtk_grid_new();
gtk_widget_show (grid);
gtk_box_pack_start (GTK_BOX (box), grid, TRUE, TRUE, 0);
scroll = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_size_request (scroll, 200, 200);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
/***/
/*** We call ScrollToEnd() if scroll receives the size-allocate signal. ***/
/***/
g_signal_connect (scroll, "size-allocate", G_CALLBACK (ScrollToEnd), NULL);
gtk_grid_attach (GTK_GRID (grid), scroll, 0, 0, 1, 1);
g_object_set (scroll, "vexpand", TRUE, NULL);
g_object_set (scroll, "margin", 10, NULL);
gtk_widget_show (scroll);
text = gtk_text_view_new();
gtk_container_add (GTK_CONTAINER (scroll), text);
gtk_widget_show (text);
buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (buffer, "red_fg", "foreground", "red", NULL);
gtk_text_view_set_buffer (GTK_TEXT_VIEW (text), buffer);
button = gtk_button_new_with_label ("Add");
g_signal_connect (button, "clicked", G_CALLBACK (Add), NULL);
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1);
g_object_set (button, "hexpand", TRUE, NULL);
gtk_widget_show (button);
gtk_widget_show (window);
iCounter = 0;
gtk_text_buffer_get_end_iter (buffer, &iter);
gtk_text_buffer_insert (buffer, &iter, g_locale_to_utf8
("Click \"Add\" to add numbers.", -1, NULL, NULL, NULL), -1);
gtk_main();
return 0;
}
/*****************************************************************************/
As a bonus it shows how to add colored text.

Related

How do I unfocus all other widgets in GTK when I click on a widget?

In my GTK program I have a TextEntry widget and a TreeView widget. When I click on the TextEntry widget and select some text, then click on the TreeView widget, it doesn't deselect the text in the TextEntry widget. How do I get it to deselect the text in the TextEntry widget when I click on the TreeView widget?
You can bind gtk_editable_select_region to the entry's "focus-out-event" signal, see the sample below:
#include <gtk/gtk.h>
gboolean unselect_on_focus_lost (GtkWidget *widget)
{
gtk_editable_select_region (GTK_EDITABLE (widget), 0, 0);
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window, *box, *entry, *button;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 130);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
gtk_container_add (GTK_CONTAINER (window), box);
entry = gtk_entry_new ();
gtk_entry_set_placeholder_text (GTK_ENTRY (entry), "I will lose my selection when you click the button below");
g_signal_connect (G_OBJECT (entry), "focus-out-event", G_CALLBACK (unselect_on_focus_lost), NULL);
gtk_container_add (GTK_CONTAINER (box), entry);
entry = gtk_entry_new ();
gtk_entry_set_placeholder_text (GTK_ENTRY (entry), "I will NOT lose my selection when you click the button below");
gtk_container_add (GTK_CONTAINER (box), entry);
/* I used a button instead of a treeview to keep the code short */
button = gtk_button_new_with_label("Click me");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_grab_focus (button);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

Displaying toggle button

i am new to gtk and i dont know how to display a toggle button in gtk.
there are no examples of the same for gtk+3.
here is what i did
GtkToolItem *tog;
tog = gtk_toggle_tool_button_new();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tog), FALSE);
i tried to add toggle button to grid, container. i also tried using gtk_widget_show and pass tog but of no use.
can any one show me the an example code or how to solve this.
PS: not a C++ programmer.
You need to show all your toplevel's widgets:
// cc `pkg-config --cflags --libs gtk+-3.0` main.c
#include <gtk/gtk.h>
int main (int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *grid;
GtkToolItem *tool;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
grid = gtk_grid_new ();
tool = gtk_toggle_tool_button_new ();
gtk_tool_button_set_label (GTK_TOOL_BUTTON (tool), "Hi there");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (tool), 0, 0, 1, 1);
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

How to make a GTK3+ window with a background image

The Pixbuf method doesn't work anymore for GTK3+ because obsoleted/removed. I want to put a background image in the back of a GtkFixed, on the gdk part of the GtkWindow or a GtkBox. I believe I need Cairo graphics library to do this.
Can a pleasant soul guide me in the right direction?
I have hacked an example together. It fills the background of the toplevel application window with an image.
As background image i choosed a little star (1). To compile the example invoke gcc like
gcc `pkg-config --libs --cflags glib-2.0 gtk+-3.0` <source> -o <executable>
On my machine the result looks like
1 : http://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Featured_Star_green.svg/32px-Featured_Star_green.svg.png
#include <gtk/gtk.h>
#include <glib-2.0/glib.h>
typedef struct Texture_
{
gint root_width, root_height;
cairo_surface_t *bg_image;
} Texture;
typedef struct Ui_
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
Texture *texture;
gulong window_draw_cb_handler_id;
} Ui;
gboolean window_draw_cb (GtkWidget *, cairo_t *, Ui *);
void
button_clicked_cb (GtkWidget * widget, Ui * ui)
{
gboolean ret;
ret =
g_signal_handler_is_connected (ui->window,
ui->window_draw_cb_handler_id);
if (ret) {
g_signal_handler_disconnect (ui->window, ui->window_draw_cb_handler_id);
}
else {
ui->window_draw_cb_handler_id =
g_signal_connect (ui->window, "draw", G_CALLBACK (window_draw_cb),
ui);
}
gtk_widget_queue_draw (ui->window);
}
void
destroy_cb (GtkWidget * widget, gpointer data)
{
gtk_main_quit ();
}
gboolean
window_draw_cb (GtkWidget * widget, cairo_t * cr, Ui * ui)
{
cairo_set_source_surface (cr, ui->texture->bg_image, 0, 0);
cairo_rectangle (cr, 0, 0,
ui->texture->root_width, ui->texture->root_height);
cairo_fill (cr);
/* draw all widgets attached to `grid` to the
* cairo context of the mainwindow */
gtk_widget_draw (ui->grid, cr);
cairo_fill (cr);
return TRUE;
}
void
ui_texture_init (Ui * ui)
{
gint root_width, root_height, width, height;
guint n_x, n_y, i, k;
cairo_format_t format;
cairo_surface_t *bg_image, *target;
cairo_status_t ret;
GdkWindow *root;
cairo_t *cr;
ui->texture = g_new (Texture, 1);
bg_image =
cairo_image_surface_create_from_png ("./Featured_Star_green.svg.png");
ret = cairo_surface_status (bg_image);
g_assert (ret == 0);
format = cairo_image_surface_get_format (bg_image);
width = cairo_image_surface_get_width (bg_image);
height = cairo_image_surface_get_height (bg_image);
root = gdk_get_default_root_window ();
gdk_window_get_geometry (root, NULL, NULL, &root_width, &root_height);
target = cairo_image_surface_create (format, root_width, root_height);
cr = cairo_create (target);
n_x = root_width / width;
n_y = root_height / height;
for (i = 0; i <= n_x; i++) {
for (k = 0; k <= n_y; k++) {
cairo_set_source_surface (cr, bg_image, i * width, k * height);
cairo_rectangle (cr, i * width, k * height, width, height);
cairo_fill (cr);
}
}
ui->texture->root_width = root_width;
ui->texture->root_height = root_height;
ui->texture->bg_image = target;
}
void
forall_container (GtkWidget * widget, gpointer data)
{
gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_margin_top (widget, 10);
gtk_widget_set_margin_bottom (widget, 10);
gtk_widget_set_margin_left (widget, 10);
gtk_widget_set_margin_right (widget, 10);
}
Ui *
ui_init ()
{
Ui *ui;
GtkWidget *label, *entry;
PangoAttrList *attributes;
ui = g_new (Ui, 1);
ui_texture_init (ui);
ui->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
ui->grid = gtk_grid_new ();
gtk_grid_set_column_homogeneous (GTK_GRID (ui->grid), TRUE);
gtk_grid_set_row_homogeneous (GTK_GRID (ui->grid), TRUE);
gtk_grid_set_row_spacing (GTK_GRID (ui->grid), 10);
label = gtk_label_new ("Label:");
attributes = pango_attr_list_new ();
pango_attr_list_insert (attributes, pango_attr_size_new_absolute (30000));
gtk_label_set_attributes (GTK_LABEL (label), attributes);
entry = gtk_entry_new ();
ui->button = gtk_button_new_with_label ("Toggle background image");
gtk_grid_attach (GTK_GRID (ui->grid), label, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (ui->grid), entry, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (ui->grid), ui->button, 0, 1, 2, 1);
gtk_container_foreach (GTK_CONTAINER (ui->grid), &forall_container, NULL);
gtk_container_add (GTK_CONTAINER (ui->window), ui->grid);
return ui;
}
int
main (int argc, char *argv[])
{
Ui *ui;
gtk_init (&argc, &argv);
ui = ui_init ();
g_signal_connect (ui->window, "destroy", G_CALLBACK (destroy_cb), ui);
ui->window_draw_cb_handler_id =
g_signal_connect (ui->window, "draw", G_CALLBACK (window_draw_cb), ui);
g_signal_connect (ui->button, "clicked", G_CALLBACK (button_clicked_cb),
ui);
gtk_widget_show_all (ui->window);
gtk_main ();
}

gtk callback multiple arguments

#include <gtk/gtk.h>
#include <stdio.h>
typedef struct {
const gchar *host;
} example;
void b_clicked (GtkButton *c_button, example *test){
g_print("Hostname: %s\n", test->host);
}
int main (int argc, char *argv[]){
GtkWidget *window;
GtkWidget *grid;
GtkWidget *c_button;
GtkWidget *q_button;
GtkWidget *label_host;
GtkWidget *h_name;
gtk_init (&argc, &argv);
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), 10);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
label_host = gtk_label_new("Hostname");
example test;
h_name = gtk_entry_new();
test.host = gtk_entry_get_text(GTK_ENTRY (h_name));
gtk_entry_set_placeholder_text (GTK_ENTRY (h_name), "Hostname");
c_button = gtk_button_new_with_label ("Connect");
g_signal_connect (c_button, "clicked", G_CALLBACK (b_clicked), (gpointer*)&test);
q_button = gtk_button_new_with_label ("Quit");
g_signal_connect (q_button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
gtk_grid_attach (GTK_GRID (grid), label_host, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), h_name, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), c_button, 0, 3, 2, 1);
gtk_grid_attach (GTK_GRID (grid), q_button, 0, 4, 2, 1);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
What is wrong whit this??
i have no errors and no warnings but on the terminal this program doesn't write anything :(
if i write:
test.host="trying something"
it works but with gtk_entry_get_text it doesn't show nothing :(
i don't understand...why it doesn't work with gtk_entry_get_text?
You need to understand that GTK is an event-driven toolkit (like many other). You need interact with events. But it won't check for events until you've run gtk_main. So your problem is that you're reading the hostname using test.host = gtk_entry_get_text(GTK_ENTRY (h_name)), but at that time, the widget hasn't been displayed, and you didn't even typed anything in it! So you're basically just getting a null string from this, and that is what you display when you click on the "connect" button.
One way to do it is to have your pointer to widgets in the struct. That way, you call gtk_entry_get_text from inside the b_clicked callback. That way, the value you get is the one that is inside the text entry widget at that time.
#include <gtk/gtk.h>
#include <stdio.h>
typedef struct {
GtkWidget *host;
} example;
void b_clicked (GtkButton *c_button, example *test){
g_print("Hostname: %s\n", gtk_entry_get_text (GTK_ENTRY(test->host)));
}
int main (int argc, char *argv[]){
GtkWidget *window;
GtkWidget *grid;
GtkWidget *c_button;
GtkWidget *q_button;
GtkWidget *label_host;
GtkWidget *h_name;
gtk_init (&argc, &argv);
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), 10);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
label_host = gtk_label_new("Hostname");
example test;
h_name = gtk_entry_new();
test.host = h_name;
gtk_entry_set_placeholder_text (GTK_ENTRY (h_name), "Hostname");
c_button = gtk_button_new_with_label ("Connect");
g_signal_connect (c_button, "clicked", G_CALLBACK (b_clicked), &test);
q_button = gtk_button_new_with_label ("Quit");
g_signal_connect (q_button, "clicked", G_CALLBACK (gtk_main_quit), NULL);
gtk_grid_attach (GTK_GRID (grid), label_host, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), h_name, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), c_button, 0, 3, 2, 1);
gtk_grid_attach (GTK_GRID (grid), q_button, 0, 4, 2, 1);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
Another nicer way to do it is, without modifying your struct, is to ask to be notified when the text has changed. For that, use the "changed" signal, as GtkEntry implements the GtkEditable interface. See "GtkEntry text change signal".
Please also note that (gpointer*)&test is wrong. test is a struct, &test is the adress of a struct. gpointer is a void *, ie. already a pointer, so gpointer * is a pointer to a pointer, which is not what &test is. So just write &test.

opencv image update in gtk for video streaming linux with C programming

I am using opencv 1.0.0 and gtk2.0. I want to grab images continuously from a video stream. So far I have successfully been able to grab still image. This is non standard IP camera not VGA/USB /V4L one so need to know explicit method to refresh or update images continuously for video streaming!
GtkWidget *image;
...
...
IplImage* bayerImage = NULL;
IplImage* rgbImage = NULL;
...
...
...
cvCvtColor( bayerImage, rgbImage, CV_BayerBG2RGB );
// Usually opencv image is BGR, so we need to change it to RGB
pix = gdk_pixbuf_new_from_data ((guchar*)rgbImage->imageData,
GDK_COLORSPACE_RGB,
FALSE,
rgbImage->depth,
rgbImage->width,
rgbImage->height,
(rgbImage->widthStep),
NULL,
NULL);
image = gtk_image_new_from_pixbuf (pix);
/* (c) 2010 Virgoptrex. Feel Free to use. Leave credits intact */
#include gtk/gtk.h
gint t=0;
gboolean
expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
//g_object_ref_sink (widget->window);
// gdk_drawable_ref (widget->window);
gdk_draw_arc (widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
TRUE,
0, 0, widget->allocation.width, widget->allocation.height,
0, 64 * 18*t);
//gdk_drawable_unref (widget->window);
return TRUE;
}
static gboolean
time_handler(GtkWidget *widget)
{
gtk_widget_queue_draw(GTK_WIDGET(widget));
if (t<20)
{ t++; }
else if (t >=20)
{ t=0; }
printf("hello %d\n",t);
return TRUE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *aspect_frame;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create an aspect_frame and add it to our toplevel window */
aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
0.5, /* center x */
0.5, /* center y */
2, /* xsize/ysize = 2 */
FALSE /* ignore child's aspect */);
gtk_container_add (GTK_CONTAINER (window), aspect_frame);
gtk_widget_show (aspect_frame);
/* Now add a child widget to the aspect frame */
drawing_area = gtk_drawing_area_new ();
/* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
* window since we are forcing a 2x1 aspect ratio */
gtk_widget_set_size_request (drawing_area, 200, 200);
gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
gtk_widget_show (drawing_area);
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
g_timeout_add(100, (GSourceFunc) time_handler, (gpointer)drawing_area);
gtk_widget_show (window);
gtk_main ();
return 0;
}