I am following the zetecode (http://zetcode.com/gfx/cairo/basicdrawing/) and trying to build my first example of drawing a line after the button is pressed, but it failed and I just couldn't figure out why. I got a segmentation fault
error when click the button.
#include <cairo.h>
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr,0,0,0);
cairo_set_line_width(cr,0.5);
cairo_move_to(cr,400,400);
cairo_line_to(cr,400,200);
cairo_stroke(cr);
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 480);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
darea = gtk_drawing_area_new();
GtkWidget *btn_draw = gtk_button_new_with_label("Draw a line");
GtkWidget *mainwindow = gtk_grid_new();
gtk_grid_set_row_spacing (GTK_GRID (mainwindow), 16);
gtk_grid_set_column_spacing (GTK_GRID (mainwindow), 16);
gtk_grid_set_row_homogeneous(GTK_GRID(mainwindow), TRUE);
gtk_grid_set_column_homogeneous(GTK_GRID(mainwindow), TRUE);
gtk_widget_set_margin_left(mainwindow,20);
gtk_widget_set_margin_right(mainwindow,20);
gtk_widget_set_margin_top(mainwindow,20);
gtk_widget_set_margin_bottom(mainwindow,20);
gtk_grid_attach(GTK_GRID(mainwindow),btn_draw,0,0,1,1);
gtk_grid_attach(GTK_GRID(mainwindow),darea,1,0,5,1);
gtk_container_add(GTK_CONTAINER(window),mainwindow);
g_signal_connect(G_OBJECT(btn_draw),"clicked",G_CALLBACK(on_draw_event),NULL);
gtk_widget_show_all(window);
gtk_main ();
return(0);
}
This is how it looks :
PS:
I followed @jku 's advice and use a gboolean draw_a_line to record the button status, and gtk_widget_queue_draw(widget) for redrawing. The only problem I noticed is that when I click the button, it does not draw immediate, but I have to hide the window or stretch the window for it to show up. I think I need to add some kind of automatic_update() function but I am a newbie to GUI design, so could anybody to me how to make the line show up immediately after I click the button?
#include <cairo.h>
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
GtkWidget *window;
GtkWidget *darea;
gboolean draw_a_line = false;
static gboolean on_draw_event(GtkWidget *widget, GdkEventExpose *event,
gpointer user_data)
{
cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(widget)));
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr,0,0,0);
cairo_set_line_width(cr,0.5);
if (draw_a_line){
cairo_move_to(cr,400,400);
cairo_line_to(cr,400,200);
cairo_stroke(cr);
}
}
static void on_clicked(GtkWidget *widget, gpointer data)
{
draw_a_line = true;
gtk_widget_queue_draw(widget);
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 480);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
darea = gtk_drawing_area_new();
GtkWidget *btn_draw = gtk_button_new_with_label("Draw a line");
GtkWidget *mainwindow = gtk_grid_new();
gtk_grid_set_row_spacing (GTK_GRID (mainwindow), 16);
gtk_grid_set_column_spacing (GTK_GRID (mainwindow), 16);
gtk_grid_set_row_homogeneous(GTK_GRID(mainwindow), TRUE);
gtk_grid_set_column_homogeneous(GTK_GRID(mainwindow), TRUE);
gtk_widget_set_margin_left(mainwindow,20);
gtk_widget_set_margin_right(mainwindow,20);
gtk_widget_set_margin_top(mainwindow,20);
gtk_widget_set_margin_bottom(mainwindow,20);
gtk_grid_attach(GTK_GRID(mainwindow),btn_draw,0,0,1,1);
gtk_grid_attach(GTK_GRID(mainwindow),darea,1,0,5,1);
gtk_container_add(GTK_CONTAINER(window),mainwindow);
g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(btn_draw),"clicked",G_CALLBACK(on_clicked),darea);
gtk_widget_show_all(window);
gtk_main ();
return(0);
}
You have written a draw handler for (presumably) the drawing area but connected it to the clicked signal of the button. These two have completely different function signatures so a segfault is not a surprise.
Don't draw directly on the clicked handler for the button, instead change some application state (like a gboolean should_draw_line
) and use gtk_widget_queue_draw ()
to mark the drawing area as needing a redraw. Then in the draw handler of the drawing area decide what to draw based on application state (like should_draw_line
).
After looking at the example you linked to, it seems to be doing almost exactly what I suggested...