【问题标题】:How to avoid cairo drawing xlib surface from flickering?如何避免cairo绘制xlib表面闪烁?
【发布时间】:2015-12-20 15:51:21
【问题描述】:

我正在用 C++ 中的 cairoxlib 进行一些编程,我的代码如下所示。

我遇到了一些闪烁的问题,但是通过修改我的代码,现在总体上看起来效果很好。
但是,当窗口调整为 小尺寸(我的笔记本电脑上约为 600x450)时,它仍然闪烁
我该如何解决?

#include <cairo.h>
#include <cairo-xlib.h>
#include <string>
#include <cstdio>

using namespace std;

int main (int argc, char *argv[])
{
    cairo_surface_t *surface;
    cairo_t *cr;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600);
    cr = cairo_create (surface);
    /* Examples are in 1.0 x
     * 1.0 coordinate space */
    cairo_scale (cr, 800, 600);

    cairo_set_source_rgb (cr, 1.0, 0, 0);
    cairo_rectangle (cr, 0, 0, 1.0, 1.0);
    cairo_fill(cr);
    cairo_destroy(cr);

    Display *display = XOpenDisplay(NULL);
    int default_scr = DefaultScreen(display);
    Visual *visual = DefaultVisual(display, default_scr);
    Window root_win = RootWindow(display, default_scr);
    Drawable drawable = XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));
    cairo_surface_t *x11_sf = cairo_xlib_surface_create(display, drawable, visual, 800, 600);

    XSelectInput(display, drawable, ExposureMask | StructureNotifyMask);
    XMapWindow(display, drawable);
    XFlush(display);
    XSync(display, default_scr);
    Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(display, drawable, &wmDeleteMessage, 1);

    int height;
    int width;
    XEvent event;
    bool running = true;
    while (running)
    {
        XNextEvent(display, &event);
        switch (event.type)
        {
        case Expose:
            {
                cairo_t *x11_cr = cairo_create(x11_sf);
                cairo_scale(x11_cr, double(width) / 800, double(height) / 600);
                cairo_set_source_surface(x11_cr, surface, 0, 0);
                cairo_paint(x11_cr);
                cairo_destroy (x11_cr);
            }
            break;
        case ClientMessage:
            if (event.xclient.data.l[0] == wmDeleteMessage)
            {
                running = false;
            }
            break;
        case ConfigureNotify:
            width = event.xconfigure.width;
            height = event.xconfigure.height;
            cairo_xlib_surface_set_size(x11_sf, width, height);
            break;
        }
    }

    cairo_surface_destroy (surface);

    return 0;
}

我使用cairo_xlib_surface 来绘制一个窗口,它具有整个红色背景色。我试图捕捉XExpose 事件并重绘它。但有时重绘结果会很奇怪。

#include <cairo.h>
#include <cairo-xlib.h>
#include <string>
#include <cstdio>

using namespace std;

int main (int argc, char *argv[])
{
    cairo_surface_t *surface;
    cairo_t *cr;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600);
    cr = cairo_create (surface);
    /* Examples are in 1.0 x 1.0 coordinate space */
    cairo_scale (cr, 800, 600);

    /* Drawing code goes here */
    cairo_set_source_rgb (cr, 1.0, 0, 0);
    cairo_rectangle (cr, 0, 0, 1.0, 1.0);
    cairo_fill(cr);

    Display *display = XOpenDisplay(NULL);
    int default_scr = DefaultScreen(display);
    Visual *visual = DefaultVisual(display, default_scr);
    Window root_win = RootWindow(display, default_scr);
    Drawable drawable = XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));

    XSelectInput(display, drawable, ExposureMask);
    XMapWindow(display, drawable);
    XFlush(display);
    XSync(display, default_scr);


    int height;
    int width;
    XEvent event;
    while (1)
    {
        XNextEvent(display, &event);
        switch (event.type)
        {
        case Expose:
            {
                width = event.xexpose.width;
                height = event.xexpose.height;
                cairo_surface_t *x11_sf = cairo_xlib_surface_create(display, drawable, visual, width, height);
                cairo_t *x11_cr = cairo_create(x11_sf);
                cairo_scale(x11_cr, double(width) / 800, double(height) / 600);
                cairo_set_source_surface(x11_cr, surface, 0, 0);
                cairo_paint(x11_cr);
                cairo_destroy (x11_cr);
                cairo_surface_destroy (x11_sf);
            }
            break;
        }
    }


    /* Write output and clean up */
    cairo_destroy (cr);
    cairo_surface_destroy (surface);

    return 0;
}

当我调整窗口大小时,有时会得到如下结果:

红色背景好像还没画完。

有人能告诉我为什么会发生这种情况以及如何避免吗?

如果有人想在Linux下编译,可以使用:g++ \pkg-config --cflags --libs x11 cairo\src.cpp

谢谢!

【问题讨论】:

  • 是否故意将暴露的宽度和高度作为窗口大小提供给 cairo_xlib_surface_create()?你为什么不使用窗口的实际大小呢?在您的情况下,最初是 800x600 并且当您的窗口调整大小时,您必须捕获告诉您它的 ConfigureNotify 并使用 cairo_xlib_surface_set_size()。这个信息真的是你想要的吗?如果不是,我不明白你的问题。
  • 感谢您的回复。你的建议确实有效。但是当窗口尺寸较小(低于 600x450)时,重绘过程仍然会出现问题。我修改了我的代码。我错过了其他一点吗? THX
  • 我测试了一些案例,发现当我创建的'surface'为100x100时,闪烁消失了。但是,那么表面是 1x1,结果 x11 窗口有一个奇怪的背景。
  • 使用 XCreateWindow 代替 XCreateSimpleWindow。我猜你的问题是你通过这个机制为你的窗口使用了白色的背景颜色。 XCreateWindow(display, root_win, 0, 0, 800, 600, 0, 0, CopyFromParent, CopyFromParent, 0, NULL);应该工作。
  • XCreateWindow 有效。谢谢!

标签: c++ cairo xlib


【解决方案1】:

问题是由于您在白色背景上填充红色区域以制作红色背景,这不是最有效的方法。

您应该创建一个将背景颜色定义为红色而不是白色的窗口!

所以,要做到这一点,在 XCreateSimpleWindow()background 参数(最后一个)中,您应该输入 0xFF0000,它是 24 位色彩空间中红色的十六进制值, 但如果您使用不同的颜色空间,您可能需要更改它。该行将如下所示:

XCreateSimpleWindow(display, root_win, 0, 0, 800, 600, 0,
            BlackPixel(display, default_scr), WhitePixel(display, default_scr));

【讨论】:

    猜你喜欢
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2023-03-22
    • 2013-11-16
    相关资源
    最近更新 更多