使用Xlib func在GtkDrawingArea上绘图

时间:2013-02-21 11:20:21

标签: c gtk drawing xlib gdk

我有一个问题。

我需要使用函数Xlib(XDrawLine等)在小部件类型GtkDrawingArea上绘制。

为什么?

我使用的是用Xlib绘制的库。我需要在渲染函数drawSome(...)中传递任何参数(Display,Window,GC)。一切都很好。我获取这些参数(通过gdk_x11 _...(),GdkDrawable,GdkGC)并使用获得的参数调用drawSome(...)。

但是有问题 - 绘画并不总是这样。最大化窗口,拖动,调整DrawingArea等大小时,不会显示图像。图像仅在顶部窗口的异常操作下显示。

然后我测试了XDrawPoint / Line / Rectangle函数 - 同样的问题。如果我们使用gdk_draw_rectangle(...) - 一切正常。

以下是以下代码:

...
GtkDrawingArea* area;
...
int main (int argc, char *argv[])
{
   ...
   area=GTK_DRAWING_AREA(gtk_builder_get_object(builder,"area"));
   gtk_widget_realize (GTK_WIDGET(area));
   ...
   g_signal_connect (G_OBJECT(area), "expose_event", G_CALLBACK(expose_event_callback), NULL);
   ...
}
...
gboolean expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
   Display *dpy = gdk_x11_drawable_get_xdisplay(widget->window);
   Window win =gdk_x11_drawable_get_xid(widget->window);
   GC gc = DefaultGC(dpy, DefaultScreen(dpy));

   //draw image on (0,0) in widget DrawingArea and a small black rectangle over image
   drawSome(dpy, win, gc, ...);
   XFillRectangle(dpy, win, gc, 0, 0, 10, 10);

   return FALSE;
}
...

图像和仅在一种情况下显示的小黑色矩形:如果窗口移出桌面并返回桌面,则会显示图像。在其他情况下,它不会显示。 印象是另一个功能会删除DrawingArea。

谁能告诉我这是什么问题?

我将不胜感激!

而且......抱歉这么糟糕的英语!

3 个答案:

答案 0 :(得分:1)

我想您需要做的就是添加XFlush(dpy);在XFillRectangle命令之后。我写了一个简短的例程,它似乎起作用。

#include <X11/Xlib.h> //-lX11
#include <gtk/gtk.h> //$$(pkg-config --cflags --libs gtk+-3.0) 
#include <gdk/gdkx.h>
void DrawOnWidget(GtkWidget *widget)
{
    GdkDisplay *gdk_dis = gdk_display_get_default();
    Display *dis = gdk_x11_display_get_xdisplay (gdk_dis);    
    GC gc = DefaultGC(dis, DefaultScreen(dis));
    GdkWindow *gdk_window = gtk_widget_get_window(widget);
    Window win = gdk_x11_window_get_xid(gdk_window);
    unsigned long valuemask = GCForeground;
    XGCValues vColor;
    vColor.foreground = 0x000000FF;
    XChangeGC(dis, gc, valuemask, &vColor);
    XFillRectangle(dis, win, gc, 0, 0, 100, 100);
    XFlush(dis);
}

答案 1 :(得分:0)

您需要使用这些函数X Window System Interaction但要注意,但可能还有其他陷阱。我想你还需要使用gtk_widget_set_double_buffered

为你的GtkDrawingArea禁用双缓冲

答案 2 :(得分:0)

这是我对该问题的第二个答案...我的第一个答案可能是针对原始问题的,因此我将其保留不变。虽然,当我第一次发现此线程时没有找到更通用的解决方案,因此,我还是决定发布一个更通用的解决方案。

简而言之,我创建了一个gtk图像小部件,该小部件可以独立显示或附加到其他小部件(如按钮)。然后,我将图像小部件发送到了绘图功能。在绘图功能中,查询所有xlib参数,以创建一个Pixmap作为xlib可绘制对象,在该位置绘制所有xlib绘图。然后创建GdkPixbuf,并将Pixmap像素复制到GdkPixbuf,然后将其设置为图像小部件...

有一些注释行可用于更改行为,解释将留给读者确定。

应该注意的是,使用xlib是可能的;开罗实施起来似乎不太麻烦。

#include <gtk/gtk.h> //$$(pkg-config --cflags --libs gtk+-3.0)
#include <gdk/gdkx.h>
#include <X11/Xlib.h> //-lX11

void DrawOnWidget(GtkWidget *widget, int width, int height)
{    
    GdkDisplay *gdk_dis = gdk_display_get_default();
    Display *dis = gdk_x11_display_get_xdisplay (gdk_dis);    
    GC gc = DefaultGC(dis, DefaultScreen(dis));

    GdkWindow *gdk_window = gtk_widget_get_window(widget);
    Window win = gdk_x11_window_get_xid(gdk_window);
    
    GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height);
    //GdkPixbuf *pb = gtk_image_get_pixbuf((GtkImage *) widget);
    char *data = (char *) gdk_pixbuf_read_pixels((const GdkPixbuf *) pb); //RGB(A)
    //int width = gdk_pixbuf_get_width(pb);
    //int height = gdk_pixbuf_get_height(pb);
    int pb_depth = gdk_pixbuf_get_n_channels(pb);

    int depth  = DefaultDepth(dis, DefaultScreen(dis)) / 8;
    Pixmap pm = XCreatePixmap(dis, win, width, height, depth * 8);          

    unsigned long valuemask = GCForeground;
    XGCValues vColor;
    vColor.foreground = 0x00FF0000;
    XChangeGC(dis, gc, valuemask, &vColor);
    XFillRectangle(dis, pm, gc, 0, 0, width, height);
    XFlush(dis);
    
    XImage *ximage = XGetImage(dis, pm, 0, 0, width, height, AllPlanes, ZPixmap); //BGRX
    for(int i=0, j=0; i<width*height*pb_depth; i+=pb_depth, j+=4)
    {
        data[i+0] = ximage->data[j+2];
        data[i+1] = ximage->data[j+1];
        data[i+2] = ximage->data[j+0];
        if(pb_depth == 4) data[i+3] = 255;
    }
    
    gtk_image_set_from_pixbuf((GtkImage *) widget, pb);
    XFreePixmap(dis, pm);
    g_object_unref(pb);
    return;
}
static void destroy( GtkWidget *widget, gpointer data )
{
    gtk_main_quit();
}
static void test( GtkWidget *widget, gpointer data )
{
    DrawOnWidget((GtkWidget *) data, 200, 200);
}
void GTK_Win()
{
    GtkWidget *window, *grid;
    GtkWidget *button_Exit, *button_Test;    
    
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
    
    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);
       
    button_Exit = gtk_button_new_with_label ("x");
    g_signal_connect (button_Exit, "clicked", G_CALLBACK (destroy), NULL);
    
    //GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 200, 200);
    //GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);  
    
    GtkWidget *image = gtk_image_new();
            
    button_Test = gtk_button_new_with_label ("Test");
    g_signal_connect (button_Test, "clicked", G_CALLBACK (test), image);
    //gtk_button_set_image((GtkButton *) button_Test, image);
           
    gtk_grid_attach (GTK_GRID (grid), button_Exit, 0, 0, 1, 1);
    gtk_grid_attach (GTK_GRID (grid), button_Test, 0, 1, 1, 1);
    gtk_grid_attach (GTK_GRID (grid), image, 0, 2, 1, 1);

    gtk_widget_show_all (window);
    gtk_main();   
}
int main(int argc, char** argv)
{
    gtk_init (&argc, &argv);  
    GTK_Win();
    return 0;
}