【问题标题】:Drawing on the GtkDrawingArea with Xlib func使用 Xlib func 在 GtkDrawingArea 上绘图
【发布时间】:2013-02-21 11:20:20
【问题描述】:

我有问题。

我需要使用函数 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。

谁能告诉我有什么问题?

不胜感激!

还有……抱歉英语这么差!

【问题讨论】:

  • 除非你有真正令人信服的理由来使用 xlib,否则不要使用它。改用 cairo,它的更高级别适用于 gtk。你可以在这里找到一个例子:stackoverflow.com/questions/9395111/… 看看第二个代码框架。使用 cairo 可以在 GtkDrawingArea 上使用非常漂亮的图形
  • cairo 将无济于事。因为我使用了一个特殊的库 where 函数。它有以下参数:someFunction (long int, Display *, Window, GC, DRAWPOINT)。所以 cairo 和 gdk 绘图原语将无济于事。因为问题不在这个函数上,而是在错误的组织中使用低级 GtkDrawingArea(通过 Xlib)。

标签: c gtk drawing xlib gdk


【解决方案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);
}

【讨论】:

    【解决方案2】:

    您需要使用这些功能X Window System Interaction,但请注意,但可能存在其他陷阱。我认为您还需要使用 gtk_widget_set_double_buffered 为您的 GtkDrawingArea 禁用双缓冲

    【讨论】:

    • 嗨,伊恩!我阅读了文章“X Window System Interaction”,使用了一些函数。我已经关闭了参数小部件 GtkDrawingArea(在 Glade 中)中的双缓冲。没有任何效果。然后我尝试了函数 gtk_widget_set_double_buffered。它按应有的方式显示! iain,谢谢您的回复和提示!
    【解决方案3】:

    这是我对这个问题的第二个答案...我的第一个答案可能是针对原始问题的,所以我保持不变。虽然,当我第一次发现这个帖子时我正在寻找的更通用的解决方案没有得到解决,但我决定也发布一个更通用的解决方案。

    简而言之,我创建了一个 gtk 图像小部件,它可以独立显示或附加到按钮等其他小部件上。然后我将图像小部件发送到绘图功能。在绘图函数中,所有 xlib 参数都被查询,以便创建一个像素图作为 xlib 可绘制对象,这是所有 xlib 绘图的呈现位置。然后创建 GdkPixbuf,并将 Pixmap 像素复制到 GdkPixbuf,然后将其设置为图像小部件...

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

    需要注意的是,虽然使用 xlib 是可以的; cairo 似乎实现起来不那么繁琐。

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多