Thread: How can i re-draw or refresh a rendered graphic in GTk+ / Cairo?

  1. #1
    Registered User
    Join Date
    Mar 2017
    Posts
    26

    How can i re-draw or refresh a rendered graphic in GTk+ / Cairo?

    I have been playing around with GTK+ for a few days when i have time spare, and I've learned to draw some simple 2D graphics with Cairo, i can get the graphic to render in a window, but how exactly do i re-draw based on events?
    I've tried a few different things now, including attempting to use the
    Code:
    gtk_widget_queue_draw()
    function, also tried to open a blank window and render the image only when the button is pressed, the program just crashes or does nothing.

    I'm not great at C programming, or programming in general i suppose, but I'm trying to learn as much and as often as possible.

    Here's the code i have so far.

    Code:
    #include <math.h>
    #include <string.h>
    #include <stdio.h>
    #include <cairo.h>
    #include <gtk/gtk.h>
    
    struct m_struct {
        GtkWidget *window, *bx1, *bx2, *d_area, *button;
    };
    
    
    
    static void draw(GtkWidget *widget, cairo_t *cr, gpointer data);
    static void redraw(GtkWidget *widget, cairo_t *cr, gpointer data);
    static void click(struct m_struct *m);
    
    
    static void draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
        cairo_set_source_rgb(cr, 2, 5, 5);
        cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
        cairo_set_font_size(cr, 80.0);
        cairo_set_line_width (cr, 5);
        cairo_move_to(cr, 100, 275);
        cairo_line_to (cr, 100, 50);
        cairo_line_to (cr, 200, 50);
        cairo_line_to (cr, 200, 75);
        cairo_move_to(cr, 100, 275);
        cairo_line_to (cr, 150, 275);
        cairo_move_to(cr, 100, 275);
        cairo_line_to (cr, 50, 275);
        cairo_move_to(cr, 220, 95);
        cairo_arc(cr, 200, 95, 20, 0, 2 * M_PI);
        cairo_move_to(cr, 200, 115);
        cairo_line_to (cr, 200, 175);
        cairo_line_to (cr, 175, 200);
        cairo_move_to(cr, 200, 175);
        cairo_line_to (cr, 225, 200);
        cairo_move_to(cr, 200, 130);
        cairo_line_to (cr, 225, 150);
        cairo_move_to(cr, 200, 130);
        cairo_line_to (cr, 175, 150);
        cairo_stroke (cr);
    
    }
    
    
    static void redraw(GtkWidget *widget, cairo_t *cr, gpointer data) {
        cairo_set_source_rgb(cr, 2, 5, 5);
        cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
        cairo_set_font_size(cr, 80.0);
        cairo_set_line_width (cr, 5);
        cairo_move_to(cr, 100, 275);
        cairo_line_to (cr, 100, 50);
        cairo_line_to (cr, 200, 50);
        cairo_line_to (cr, 200, 75);
        cairo_move_to(cr, 100, 275);
        cairo_line_to (cr, 150, 275);
        cairo_stroke (cr);
    
    }
    
    static void click(struct m_struct *m) {
        g_signal_connect(m->d_area, "draw", G_CALLBACK(redraw), NULL);
    }
    
    int main(int argc, char *argv[]) {
        struct m_struct m;
        gtk_init(&argc, &argv);
    
        m.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    
        m.bx1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, FALSE);
        m.bx2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, FALSE);
    
        m.d_area = gtk_drawing_area_new();
    
        m.button = gtk_button_new_with_label("Button");
        gtk_container_add(GTK_CONTAINER(m.window), m.bx1);
        gtk_box_pack_start(GTK_BOX(m.bx1), m.d_area, TRUE, TRUE, FALSE);
        gtk_box_pack_start(GTK_BOX(m.bx1), m.bx2, FALSE, FALSE, FALSE);
        gtk_box_pack_start(GTK_BOX(m.bx2), m.button, FALSE, FALSE, FALSE);
        g_signal_connect(m.window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(m.button, "clicked", G_CALLBACK(click), &m);
        g_signal_connect(m.d_area, "draw", G_CALLBACK(draw), NULL);
        gtk_window_set_position(GTK_WINDOW(m.window), GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(m.window), 275, 325);
        gtk_window_set_title(GTK_WINDOW(m.window), "DRAW");
        gtk_widget_show_all(m.window);
    
        gtk_main();
    
        return 0;
    }
    As is, the program crashes once the button is pressed, i would like it to re-draw to the window?

    Would very much appreciate some suggestion as to how i should go about this.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    You've simply forgotten GtkWidget *widget for the first parameter of click. And you will need the gtk_widget_queue_draw call after you change the signal handler.

    Also, you're passing your colors to cairo_set_source_rgb incorrectly. They are supposed to be between 0.0 and 1.0. If they are above 1.0 they are "clamped" to 1, so you are setting the color to white.
    Last edited by algorism; 04-11-2017 at 04:12 PM.

  3. #3
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    Now that I think about it, calling g_signal_connect with another handler doesn't "replace" the handler but chains in another handler. You're best to stick with one handler and change a data element to indicate what to do.
    Code:
    // gcc gtk01.c `pkg-config --libs --cflags gtk+-3.0` -o gtk01
    
    #include <gtk/gtk.h>
    #include <math.h>
    
    struct m_struct {
        GtkWidget *window, *bx1, *d_area, *button;
        int draw_num;
    };
    
    static void draw0(GtkWidget *widget, cairo_t *cr, gpointer data) {
        cairo_set_source_rgb(cr, .5, .8, .8);
        cairo_set_line_width (cr, 5);
    
        cairo_move_to(cr, 100, 275);
         cairo_line_to (cr, 100, 50);
         cairo_line_to (cr, 200, 50);
         cairo_line_to (cr, 200, 75);
        cairo_move_to(cr, 100, 275);
         cairo_line_to (cr, 150, 275);
        cairo_move_to(cr, 100, 275);
         cairo_line_to (cr, 50, 275);
        cairo_move_to(cr, 220, 95);
         cairo_arc(cr, 200, 95, 20, 0, 2 * M_PI);
        cairo_move_to(cr, 200, 115);
         cairo_line_to (cr, 200, 175);
         cairo_line_to (cr, 175, 200);
        cairo_move_to(cr, 200, 175);
         cairo_line_to (cr, 225, 200);
        cairo_move_to(cr, 200, 130);
         cairo_line_to (cr, 225, 150);
        cairo_move_to(cr, 200, 130);
         cairo_line_to (cr, 175, 150);
    
        cairo_stroke (cr);
    }
    
    static void draw1(GtkWidget *widget, cairo_t *cr, gpointer data) {
        cairo_set_source_rgb(cr, .5, .8, .8);
        cairo_set_line_width (cr, 5);
    
        cairo_move_to(cr, 100, 275);
         cairo_line_to (cr, 100, 50);
         cairo_line_to (cr, 200, 50);
         cairo_line_to (cr, 200, 75);
        cairo_move_to(cr, 100, 275);
         cairo_line_to (cr, 150, 275);
    
        cairo_stroke (cr);
    }
    
    static void draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
        struct m_struct *m = (struct m_struct *)data;
        switch (m->draw_num) {
        case 0: draw0(widget, cr, data); break;
        case 1: draw1(widget, cr, data); break;
        }
    }
    
    static void click(GtkWidget *widget, gpointer data) {
        struct m_struct *m = (struct m_struct *)data;
        m->draw_num = !m->draw_num;
        gtk_widget_queue_draw(m->d_area);
    }
    
    int main(int argc, char *argv[]) {
        struct m_struct m;
        m.draw_num = 0;
    
        gtk_init(&argc, &argv);
    
        m.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_position(GTK_WINDOW(m.window), GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(m.window), 275, 325);
        gtk_window_set_title(GTK_WINDOW(m.window), "DRAW");
    
        m.bx1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, FALSE); 
        gtk_container_add(GTK_CONTAINER(m.window), m.bx1);
    
        m.d_area = gtk_drawing_area_new();
        gtk_box_pack_start(GTK_BOX(m.bx1), m.d_area, TRUE, TRUE, FALSE);
    
        m.button = gtk_button_new_with_label("Button");
        gtk_box_pack_start(GTK_BOX(m.bx1), m.button, FALSE, FALSE, FALSE);
    
        g_signal_connect(m.window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(m.button, "clicked", G_CALLBACK(click), &m);
        g_signal_connect(m.d_area, "draw", G_CALLBACK(draw), &m);
    
        gtk_widget_show_all(m.window); 
        gtk_main();
     
        return 0;
    }

  4. #4
    Registered User
    Join Date
    Mar 2017
    Posts
    26
    Okay great, thanks a lot!
    Last edited by Strobez; 04-11-2017 at 04:44 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Impossible to draw in an XCB window using Cairo
    By levenstein in forum Linux Programming
    Replies: 5
    Last Post: 07-02-2016, 09:31 AM
  2. NVidia max pre-rendered frames
    By VirtualAce in forum General Discussions
    Replies: 1
    Last Post: 07-18-2010, 08:01 AM
  3. Cairo and GTK, still need a pixmap?
    By TriKri in forum Linux Programming
    Replies: 0
    Last Post: 03-18-2008, 04:18 PM
  4. trying to understand what is being rendered ??
    By caricas in forum Windows Programming
    Replies: 4
    Last Post: 04-20-2007, 02:13 PM
  5. Final Fantasy Movie: Rendered in Real-Time.
    By Cheeze-It in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 08-15-2001, 09:02 PM

Tags for this Thread