【问题标题】:GtkDrawingArea - how to make it drawable?GtkDrawingArea - 如何使其可绘制?
【发布时间】:2012-02-22 12:51:49
【问题描述】:

我在这里有点发疯了。

我正在尝试使用 cairo 在我的 GTK 表单上绘制一些简单的图形。

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

GtkWidget* window;
GtkWidget* darea; 


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), 390, 240);

    darea = gtk_drawing_area_new();
    gtk_container_add(GTK_CONTAINER(window), darea); 

    cairo_t *cr; 
    cr = gdk_cairo_create(darea->window);
    cairo_rectangle(cr, 0, 0, 100, 100); 
    cairo_fill(cr);


    gtk_widget_show_all(window);

    gtk_main(); 

    return 0;
}

这编译,但给了我

Gdk-CRITICAL **: IA__gdk_cairo_create: 断言`GDK_IS_DRAWABLE (drawable)'失败

后跟一个段错误。

我一直在看tutorial here

所以我改变了我的代码如下,使开罗调用发生在暴露事件中。

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

    GtkWidget* window;
    GtkWidget* darea; 

    static gboolean
    on_expose_event(GtkWidget *widget,
        GdkEventExpose *event,
        gpointer data)
    {
        cairo_t *cr; 
        cr = gdk_cairo_create(darea->window);
        cairo_rectangle(cr, 0, 0, 100, 100); 
        cairo_fill(cr);

    }    

    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), 390, 240);

        darea = gtk_drawing_area_new();
        gtk_container_add(GTK_CONTAINER(window), darea); 

        g_signal_connect(darea, "expose-event",
          G_CALLBACK(on_expose_event), NULL);


        gtk_widget_show_all(window);

        gtk_main(); 

        return 0;
    }

为什么这会解决它? 我的理解是:暴露是:

g_signal_connect(darea, "expose-event", G_GCALLBACK(on_expose_event), NULL); 

告诉程序,'当一个暴露事件发生在darea时,然后调用on_expose_event'。 null 是您可以将指针传递给函数以供使用的附加信息结构的位置。

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

意味着 on_expose_event 被传递一个指向事件发生的小部件的指针,在这种情况下,因为它是一个暴露事件,一个指向包含有关暴露事件信息的结构的指针,以及一个指向任何其他信息的结构的指针您可能想添加。

【问题讨论】:

    标签: gtk cairo


    【解决方案1】:

    在具有 Cairo 的小部件上绘图在暴露事件中起作用。这是因为 Cairo 不像一个矢量绘图程序,其中的线条和形状是可以记住并可以操作的对象; Cairo 只是将形状绘制到绘图区域并忘记它们。

    因此,当您最小化并恢复您的窗口,或将另一个窗口移到它上面时,这些形状就会消失。将生成一个expose 事件,让您知道形状已经消失并且需要重新绘制小部件。所以你在暴露事件处理程序中使用 Cairo 进行重绘。

    【讨论】:

    • 好的,假设我们的表单上有两个按钮,一个在绘图区域绘制一个红色圆圈,另一个在绘图区域绘制一个蓝色方块。这样做的方法是-每个按钮单击事件都会更改一个“模式”变量,并调用gtk_widget_queue_draw(),然后expose_events根据模式决定绘制什么?示例代码:pastebin.com/7ZvwcCXb
    • 在过去,您可以将某些内容设置为双缓冲或使用保存条件,我认为这在 GTK 中是可能的。您还可以将窗口复制到像素图,然后根据需要复制回来。但在 XLib 和 Motif 中,如果我画了一些东西,然后盖上又揭开,没有什么能让我的画恢复原状。
    【解决方案2】:

    第一个代码中的警告和随之而来的崩溃是因为 darea-&gt;windowNULLGdkWindow (darea-&gt;window) 在您调用 @ 时尚未在程序中创建987654327@。一旦绘图区域小部件实现,绘图区域的GdkWindow 就会创建。尝试在调用 gdk_cairo_create 之前添加 gtk_widget_realize(darea); 。另外,我建议不要直接访问window,而是建议使用访问器函数gtk_widget_get_window
    当您在expose-event 回调中添加相同的代码时,它没有断言和崩溃的原因是因为与绘图区域相关联的GdkWindow 在程序执行时已经创建。

    编辑:
    上面提供的原因解释了为什么代码在expose-event 回调中没有崩溃以及为什么在程序运行时调用gdk_cairo_create 没有断言。将上述响应只是视为与崩溃相关的解释。绘制机制详情请参考ptomato's response

    希望这会有所帮助!

    【讨论】:

    • 你答案的第一部分是正确的:当小部件没有实现时,darea-&gt;windowNULL。其余的都是错误的:绘图 only 在暴露事件中起作用。
    • @ptomato:你说得对。我想我搞砸了回复中的措辞。我试图解释为什么在处理程序中添加代码时没有发生崩溃以及在实现小部件时调用时间处理程序创建的可绘制对象GdkWindow。我将相应地更新响应。谢谢
    • 也感谢您的更新!我已经把我的 -1 变成了 +1。
    • @ptomato:你真好!再次感谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多