【问题标题】:How to draw a line in a GtkDrawingArea using Cairo with Gtk3如何使用 Cairo 和 Gtk3 在 GtkDrawingArea 中绘制一条线
【发布时间】:2012-01-19 19:55:58
【问题描述】:

有人可以向我展示一个使用 C 语言在 Cairo 和 Gtk3 中绘制 GtkDrawingArea 中的一条线的最小工作示例。我试图在 Gtk3 测试文件夹中修改testcairo.c,但我无法让它工作。请不要在开罗网站上推荐教程; Zetcode.com 或 gnome.org,它们要么不适用于 Gtk3,要么不是最小的工作示例。

【问题讨论】:

    标签: c gtk gtk3 cairo


    【解决方案1】:

    我明白了。关键区别在于,对于 gtk+3,您必须从“绘制”信号处理程序中进行绘制。使用 gtk+2 它来自“expose-event”信号处理程序。这是minimal working example

    【讨论】:

    • 这很有帮助。我想提一下,如果您使用的是“draw”信号,ZetCode.com 上的教程现在已经是最新的了。
    • 这个链接现在每次点击它都会导致一个随机的广告客户,就好像这个域已经丢失了一样。我搜索了标题,但没有找到任何东西。答案的核心信息有效,但演示丢失。
    • @cardiffspaceman 我从网络档案中找到了它,这是少数几个可能比Stack Overflow 更长寿的网站之一。不过,您必须向下滚动两页才能找到任何代码。
    【解决方案2】:

    这是一个完整的工作示例:

    • 确保已安装 gtk3-devel(在 Fedora #dnf install gtk3-devel 中)

    • 在 Ubuntu 中:sudo apt install libgtk-3-dev

    编译:gcc draw.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0` -o draw

    #include <gtk/gtk.h>
    gboolean draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
    {
        guint width, height;
        GdkRGBA color;
        GtkStyleContext *context;
        
        context = gtk_widget_get_style_context (widget);
        width = gtk_widget_get_allocated_width (widget);
        height = gtk_widget_get_allocated_height (widget);
        gtk_render_background(context, cr, 0, 0, width, height);
        cairo_arc (cr, width/2.0, height/2.0, MIN (width, height) / 2.0, 0, 2 * G_PI);
        gtk_style_context_get_color (context, gtk_style_context_get_state (context), &color);
        gdk_cairo_set_source_rgba (cr, &color);
        gdk_cairo_set_source_rgba (cr, &color);
        cairo_fill (cr);
        return FALSE;
    }
    
    gint main(int argc,char *argv[])
    {
        GtkWidget *window, *drawing_area;
        
        gtk_init (&argc, &argv);
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
        
        drawing_area = gtk_drawing_area_new();
        gtk_container_add (GTK_CONTAINER (window), drawing_area);
        gtk_widget_set_size_request (drawing_area, 200, 100);
        g_signal_connect (G_OBJECT (drawing_area), "draw", G_CALLBACK (draw_callback), NULL);
        gtk_widget_show_all (window);
        gtk_main ();
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      任何人都在 2020 年这样做。这是重构为使用 GTK3 的 Zetcode 示例,它绘制了您想要的内容,因此线条不会奇怪地连接。我添加了 cmets 来解释发生了什么。

      /* To compile: gcc linetest.c -o linetest `pkg-config --cflags --libs gtk+-3.0`
      * C program for basic drawing with GTK+ and cairo.
      * Working 2020 example if this got you stuck, http://zetcode.com/gfx/cairo/basicdrawing/
      * Note: the above command line uses backticks (`), it's right before 1 on your keyboard.
      */
      #include <cairo.h>
      #include <gtk/gtk.h>
      
      //function prototypes
      static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
      static void do_drawing(cairo_t *cr);
      static gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
      //end of function prototypes
      
      /* Global variables for storing mouse coordinates,
      * count is index of arrays, coordx and coordy are x and y coordinates of the mouse
      */
      struct {
        int count;
        double coordx[100];
        double coordy[100];
      } glob;
      
      /* Function: on_draw_event
      *Parameters: GtkWidget, cairo_t, gpointer
      *Use: This is the function we attach to the main method when we want to draw. It calls the do_drawing method.
      *Example: g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
      */
      static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data)
      {
        do_drawing(cr);
        return FALSE;
      }
      
      
      /* Function: do_drawing
      *Parameters: cairo_t
      *Use: It sets cairo canvas settings, and draws shapes with a for loop
      *Settings: are commented
      *Note: printf is used during debugging to find mouse click coordinates :)
      */
      static void do_drawing(cairo_t *cr)
      {
        cairo_set_source_rgb(cr, 0, 0, 0);//Line colour
        cairo_set_line_width(cr, 0.5);//Line width
      
        if (glob.count > 1) {
          cairo_move_to(cr, glob.coordx[0], glob.coordy[0]);
          //printf("from: x:%f, y:%f\n",glob.coordx[0],glob.coordy[0]);
        }
      
        //Connect lines.
        for (int i = 1; i < glob.count; ++i) {
          cairo_line_to(cr, glob.coordx[i], glob.coordy[i]);
          //printf("to: x:%f, y:%f\n",glob.coordx[i],glob.coordy[i]);
        }
      
        // Draw the above.
        cairo_stroke(cr);
        //resets array so shape can be drawn again.
        glob.count = 0;
      }
      
      
      /* Function: clicked
      *Parameters: GtkWidget, GdkEventButton, gpointer
      *Use: Registers mouse clicks, 1 is right, 3 is left on laptop. Clicks may be 1, 2 or 3 on a desktop
      *Note: printf is used during debugging to find mouse click coordinates :)
      */
      static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
        gpointer user_data)
      {
        if (event->button == 1) {
             // printf("Right Click");
          glob.coordx[glob.count] = event->x;
          glob.coordy[glob.count++] = event->y;
      
              // int i;
              // for (i =0; i <= glob.count-1; i++) {
              //   printf("%f\n", glob.coordx[i]);
              // }
        }
      
        if (event->button == 3) {
              //printf("left Click");
          gtk_widget_queue_draw(widget);
        }
      
        return TRUE;
      }
      
      //Main method.
      int main(int argc, char *argv[])
      {
        //widget variables, window and drawing area.
        GtkWidget *window;
        GtkWidget *darea;
      
        //Set global count 0, so array is at beginning whenver program starts.
        glob.count = 0;
      
        //Always have this to start GTK.
        gtk_init(&argc, &argv);
      
        //Set new window, set new drawing area.
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        darea = gtk_drawing_area_new();
      
        //Add the drawing area to the window.
        gtk_container_add(GTK_CONTAINER(window), darea);
      
        //You need this to register mouse clicks.
        gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
      
        //Attaching draw function to the main method.
        g_signal_connect(G_OBJECT(darea), "draw",
          G_CALLBACK(on_draw_event), NULL);
      
        //You can close window when you exit button.
        g_signal_connect(window, "destroy",
          G_CALLBACK(gtk_main_quit), NULL);
      
        //Register if left or right mouse click.
        g_signal_connect(window, "button-press-event",
          G_CALLBACK(clicked), NULL);
      
        //Set window position, default size, and title.
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
        gtk_window_set_title(GTK_WINDOW(window), "Lines");
      
        //Show all widgets.
        gtk_widget_show_all(window);
      
        //start window
        gtk_main();
      
        return 0;
      }
      

      【讨论】:

      • 您现在可以将它移植到 GTK4 ;) 这将很快发布。
      • .. GTK4 也会有 GTKSnapshot,并且不再使用 Cairo。
      【解决方案4】:
      // compila con valac --pkg gtk+-3.0 nombre_archivo.gs
      uses 
          Gtk
          Cairo
      
      init
          Gtk.init (ref args)
          var TestCairo = new Ventana ()
          TestCairo.show_all ()
          Gtk.main ()
      
      class Ventana : Window
      
          area: Gtk.DrawingArea   
      
          init        
              title = "Test Genie + GTK + Cairo"
              set_default_size (400, 400)     
              window_position = WindowPosition.CENTER
              destroy.connect(Gtk.main_quit)
      
              // área de dibujo
              area: Gtk.DrawingArea = new Gtk.DrawingArea ()
              // conecta el área de dibujo al método dibujar
              area.draw.connect (dibujar) 
              // añade el área de dibujo a la ventana
              add (area)
      
          def dibujar (context : Context) : bool      
      
              context.set_source_rgba (1, 0, 0, 1)        
              context.set_line_width (2)
      
              context.move_to (200, 100)
              context.line_to (200, 300)
      
              context.move_to (100, 200)
              context.line_to (300, 200)      
      
              context.stroke ()
      
              return true
      

      更多 Genie + Gtk + Cairo 的例子在http://genie.webierta.skn1.com

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-12
        • 1970-01-01
        相关资源
        最近更新 更多