【问题标题】:How to create a cairo object within a gtk window in GTK+3如何在 GTK+3 的 gtk 窗口中创建 cairo 对象
【发布时间】:2019-08-28 19:38:23
【问题描述】:

我正在尝试使用 cairo 绘制一些弧线,但 gcc 警告我 gdk_cairo_create() is deprecated. Use gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context() instead

为了解决这个问题,我做了一些研究,发现对于 gdk_window_begin_draw_frame() 我需要“GdkWindow”。我一直在为我的窗口使用 GtkWidget,所以我需要将“GtkWidget”转换为“GdkWindow”,但是 gtk_widget_get_window () 返回 NULL 并导致段错误。

#include <gtk/gtk.h>
#include <cairo.h>
void main(int argc , char **argv){
    gtk_init(&argc , &argv);
    GtkWidget *win;
    GdkWindow *gdkwin;
    GdkDrawingContext *dc;

    cairo_region_t *region;

    cairo_t *cr;


    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    region = cairo_region_create();

    gdkwin = gtk_widget_get_window(GTK_WIDGET(win));

    //Here gdkwin should contain a GdkWindow but it's NULL.

    gc = gdk_window_begin_draw_frame(gdkwin , (const cairo_region_t*)&region);
    ...
    ...

这是运行时错误:

(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_window_begin_draw_frame: assertion 'GDK_IS_WINDOW (window)' failed

(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_drawing_context_get_cairo_context: assertion 'GDK_IS_DRAWING_CONTEXT (context)' failed
Segmentation fault

我想获取一个 cairo 对象并将其用于 cairo_arc()。

谢谢。最好的问候。

【问题讨论】:

  • 为什么要绘制到main() 中的窗口?此时,您的窗口很可能还不可见,并且任何绘图(在 X11 上完成)都将丢失。我猜你得到的NULL 是因为你的GtkWindow 还没有GdkWindow。请看developer.gnome.org/gtk3/stable/ch01s05.html
  • 另外,根据developer.gnome.org/gtk3/stable/…gtk_widget_get_window 返回NULL 的唯一方法是小部件尚未实现。另见developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-showdeveloper.gnome.org/gtk3/stable/…
  • 我只需要一种方法来创建一个用于绘图的 cairo 对象,并且在 gnome 网站的那个示例中似乎“cairo_create()”可以完成工作。另外我需要改变我的编码风格所以从来没有把所有这些东西放在主程序中。提前感谢@Uli Schlachter
  • 直接使用 cairo 也是一种更好的做法,因为无需担心 gdk 和那些繁琐的警告 (gdk_cairo_create)。

标签: c gtk cairo


【解决方案1】:

下面是让 Cairo 在 GTK 3 下工作的完整源代码。它应该可以按原样编译。

正如其他人已经指出的那样,您必须使用绘图信号才能使事情正常进行。

    #include <gtk/gtk.h>
    #include <cairo.h>

    // ------------------------------------------------------------

    gboolean on_draw (GtkWidget *widget,
                    GdkEventExpose *event,
                    gpointer data) 
    {

        // "convert" the G*t*kWidget to G*d*kWindow (no, it's not a GtkWindow!)
        GdkWindow* window = gtk_widget_get_window(widget);  

        cairo_region_t * cairoRegion = cairo_region_create();

        GdkDrawingContext * drawingContext;
        drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);

        { 
            // say: "I want to start drawing"
            cairo_t * cr = gdk_drawing_context_get_cairo_context (drawingContext);

            { // do your drawing
                cairo_move_to(cr, 30, 30);
                cairo_set_font_size(cr,15);
                cairo_show_text(cr, "hello world");
            }

            // say: "I'm finished drawing
            gdk_window_end_draw_frame(window,drawingContext);
        }

        // cleanup
        cairo_region_destroy(cairoRegion);

        return FALSE;
    }

    // ------------------------------------------------------------

    int main (int argc, char * argv[]) {
        gtk_init(&argc, &argv);

        GtkWindow * window; 
        { // window setup
            window = (GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
            gtk_window_set_default_size (window, 200, 200);
            gtk_window_set_position     (window, GTK_WIN_POS_CENTER);
            gtk_window_set_title        (window, "Drawing");

            g_signal_connect(window, "destroy", gtk_main_quit, NULL);
        }  

        // create the are we can draw in
        GtkDrawingArea* drawingArea;
        {
            drawingArea = (GtkDrawingArea*) gtk_drawing_area_new();
            gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)drawingArea);

            g_signal_connect((GtkWidget*)drawingArea, "draw", G_CALLBACK(on_draw), NULL);    
        }  


        gtk_widget_show_all ((GtkWidget*)window);
        gtk_main();

        return 0;
    }



    // ------------------------------------------------------------

【讨论】:

    【解决方案2】:

    在 GTK+ 3 中,您应该根据draw 信号进行绘图。在 main 中执行此操作没有任何意义(小部件刚刚创建,但在运行 main 事件循环时会进一步初始化它们)。

    请阅读:https://developer.gnome.org/gtk3/stable/chap-drawing-model.html

    【讨论】:

      【解决方案3】:

      Dark Trick 的程序已经完成。 他使用的函数如下,

      GdkWindow* window = gtk_widget_get_window (widget);
      cairo_region_t *cairoRegion = cairo_region_create();
      GdkDrawingContext *drawingContext;
      drawingContext = gdk_window_begin_draw_frame (window, cairoRegion);
      cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);
      

      但我使用的功能如下,

      GdkWindow *window = gtk_widget_get_window(widget);
      cairo_rectangle_int_t cairoRectangle = {0, 0, 200, 200};
      cairo_region_t *cairoRegion = cairo_region_create_rectangle (&cairoRectangle);
      GdkDrawingContext *drawingContext;
      drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);
      cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);
      

      这行得通,但我无法理解其中的区别,因为我是一名老年泌尿科医生。

      【讨论】:

      • 我遇到了同样的问题。我认为 cairo_region_create 默认返回一个宽度为 0、高度为 0 的矩形区域。这是我可以解释为什么需要传入自定义宽度和高度的唯一方法。
      【解决方案4】:

      我不肯定,但我认为您正试图在 GdkWindow 准备好之前获取它。我认为您需要连接到窗口的“实现”信号,并且只有在发出该信号时,您才应该尝试访问底层 GdkWindow。

      #include <gtk/gtk.h>
      #include <cairo.h>
      
      
      void OnWindowRealize(GtkWidget *pWidget, gpointer data)
      {
          GdkWindow *pUnderlyingWindow = gtk_widget_get_window(pWidget);
      
          cairo_region_t *region = cairo_region_create();
      
          GdkDrawingContext *gc = gdk_window_begin_draw_frame(pUnderlyingWindow, (const cairo_region_t*)&region);
      
          //etc...
      }
      
      
      void main(int argc , char **argv)
      {
          gtk_init(&argc , &argv);
      
          GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      
          g_signal_connect(G_OBJECT(win), "realize", OnWindowRealize, NULL);
      
          //etc...
      }
      
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-11
        相关资源
        最近更新 更多