0

我有个问题。

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

谁能告诉我是什么问题?

我将感激不尽!

而且...对不起英语这么差!

4

3 回答 3

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);
}
于 2020-10-16T16:31:23.447 回答
0

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

于 2013-02-21T13:26:54.647 回答
0

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

简而言之,我创建了一个 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;
}
于 2020-10-17T20:42:08.927 回答