The answers from andlabs are fine. Here is in addition a short (although not entirely elegant) example. It will "kind of remember" the last NUM
lines - creation/resize/activation/deactivation of the window will trigger a "draw" of the content. A Next button click will add a new line to the output. Check also the command-line output for an update of
the array values that are drawn.
#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <cairo.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#define NUM 3
typedef struct {
GtkApplication *app;
GtkWidget *window;
GtkWidget *button;
GtkWidget *da;
cairo_t* cr;
gboolean redraw;
gint xsize;
gint ysize;
} appWidgets;
gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data);
void nextCallback (GtkWidget *widget, gpointer data);
void nextCallback (GtkWidget *widget, gpointer data)
{
appWidgets *w = (appWidgets*) data;
static gint cnt = 0;
static gdouble x[NUM], y[NUM], u[NUM], v[NUM];
// determine the next coordinates for a line
if (w->redraw == FALSE) {
x[cnt] = g_random_double();
y[cnt] = g_random_double();
u[cnt] = g_random_double();
v[cnt] = g_random_double();
}
w->cr = gdk_cairo_create (gtk_widget_get_window (w->da));
// map (0,0)...(xsize,ysize) to (0,0)...(1,1)
cairo_translate (w->cr, 0, 0);
cairo_scale (w->cr, w->xsize, w->ysize);
// set linewidth
cairo_set_line_width (w->cr, 0.005);
// draw the lines
for (int k = 0; k < NUM; k++) {
cairo_move_to (w->cr, x[k], y[k]);
cairo_line_to (w->cr, u[k], v[k]);
cairo_stroke (w->cr);
g_print("k=%d:(%1.2lf,%1.2lf).(%1.2lf,%1.2lf) ",
k, x[k], y[k], u[k], v[k]);
}
g_print("\n");
cairo_destroy (w->cr);
if (w->redraw == FALSE) {
cnt++;
if (cnt == NUM)
cnt = 0;
}
}
gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data)
{
appWidgets *w = (appWidgets*) data;
w->xsize = gtk_widget_get_allocated_width (w->da);
w->ysize = gtk_widget_get_allocated_height (w->da);
w->redraw = TRUE;
nextCallback (NULL, w);
w->redraw = FALSE;
return TRUE;
}
void activate (GtkApplication *app, gpointer data)
{
GtkWidget *box;
appWidgets *w = (appWidgets*) data;
w->window = gtk_application_window_new (w->app);
gtk_window_set_application (GTK_WINDOW (w->window), GTK_APPLICATION (w->app));
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (w->window), box);
w->da = gtk_drawing_area_new();
gtk_widget_set_size_request (w->da, 400, 400);
gtk_box_pack_start (GTK_BOX (box), w->da, TRUE, TRUE, 0);
g_signal_connect (w->da, "draw", G_CALLBACK (drawEvent), (gpointer) w);
w->button = gtk_button_new_with_label ("Next");
g_signal_connect (G_OBJECT (w->button), "clicked", G_CALLBACK (nextCallback),
(gpointer) w);
gtk_box_pack_start (GTK_BOX (box), w->button, FALSE, TRUE, 0);
gtk_widget_show_all (GTK_WIDGET (w->window));
w->redraw = FALSE;
}
int main (int argc, char *argv[])
{
gint status;
appWidgets *w = g_malloc (sizeof (appWidgets));
w->app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (w->app, "activate", G_CALLBACK (activate), (gpointer) w);
status = g_application_run (G_APPLICATION (w->app), argc, argv);
g_object_unref (w->app);
g_free (w);
w = NULL;
return status;
}
Build the program as usual:
gcc example.c -o example `pkg-config --cflags --libs gtk+-3.0`
draw
signal; before this signal is issued, it will clear the widget to give you a blank slate to draw on". If you want to preserve the contents of the drawing area, you will need to do that yourself somehow (perhaps by saving the drawing parameters; in your case a list of lines). You cannot force a redraw immediately, but you can tell GTK+ that you want to redraw by using thegtk_widget_queue_draw()
method and its variants; GTK+ will then give you thedraw
signal when it next can. – andlabs