Winapi 带Win32双缓冲的Cairo线性渐变

Winapi 带Win32双缓冲的Cairo线性渐变,winapi,gdi,cairo,Winapi,Gdi,Cairo,我试图让Cairo在Win32窗口中工作。这个想法只是为了让它不渲染闪烁 如果直接使用窗口的HDC创建Cairo曲面,则窗口在调整大小时会闪烁。这是正常的,也是意料之中的。通常的解决方案是创建一个兼容的设备上下文并渲染为位图,然后将该位图blit到windowhdc 问题在于,在使用窗口的HDC时使用的相同绘图代码在双缓冲区设备上下文中不起作用。我得到的是一个黑色正方形,而不是一个渐变圆 下面是一个小的功能性示例。如果注释掉#define DOUBLE_BUFFER行,则它将直接将Cairo渲染

我试图让Cairo在Win32窗口中工作。这个想法只是为了让它不渲染闪烁

如果直接使用窗口的HDC创建Cairo曲面,则窗口在调整大小时会闪烁。这是正常的,也是意料之中的。通常的解决方案是创建一个兼容的设备上下文并渲染为位图,然后将该位图blit到windowhdc

问题在于,在使用窗口的HDC时使用的相同绘图代码在双缓冲区设备上下文中不起作用。我得到的是一个黑色正方形,而不是一个渐变圆

下面是一个小的功能性示例。如果注释掉
#define DOUBLE_BUFFER
行,则它将直接将Cairo渲染绘制到窗口的HDC。否则,它将绘制到创建的对象

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <cairo.h>
#include <cairo-win32.h>

// Global variables

// The main window class name.
static TCHAR szWindowClass[] = _T("CairoTestApp");

// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Cairo Test Application");

HINSTANCE hInst;

// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int main(int argc, const char *argv)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL, _T("Call to RegisterClassEx failed!"), szTitle, NULL);

        return 1;
    }

    hInst = hInstance; // Store instance handle in our global variable

    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application does not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        256, 256,
        NULL,
        NULL,
        hInstance,
        NULL
        );

    if (!hWnd)
    {
        MessageBox(NULL, _T("Call to CreateWindow failed!"), szTitle, NULL);

        return 1;
    }

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd, SW_SHOWNORMAL);
    UpdateWindow(hWnd);

    // Main message loop:
    MSG msg;
    while(true)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                break;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }

//  DestroyWindow(hWnd);
    UnregisterClass(szWindowClass, hInstance);

    return 0;
}

void gradientExample( cairo_t* cr ) {
    cairo_pattern_t *pat;

    pat = cairo_pattern_create_linear (0.0, 0.0,  0.0, 256.0);
    cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
    cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
    cairo_rectangle (cr, 0, 0, 256, 256);
    cairo_set_source (cr, pat);
    cairo_fill (cr);
    cairo_pattern_destroy (pat);

    pat = cairo_pattern_create_radial (115.2, 102.4, 25.6,
        102.4,  102.4, 128.0);
    cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
    cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
    cairo_set_source (cr, pat);
    cairo_arc (cr, 128.0, 128.0, 76.8, 0, 2 * 3.14159);
    cairo_fill (cr);
    cairo_pattern_destroy (pat);
}

#define DOUBLE_BUFFER

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        {
            HDC newDC = CreateCompatibleDC(hdc);
            RECT theRect;
            GetClientRect(hWnd, &theRect);
            int width, height;
            width = theRect.right - theRect.left;
            height = theRect.bottom - theRect.top;
            HBITMAP theBmp = CreateCompatibleBitmap(newDC, width, height);
            HGDIOBJ oldBmp = SelectObject(newDC, theBmp);

            //Test some text.
#ifdef DOUBLE_BUFFER
            TextOut(newDC, 5, 5, greeting, _tcslen(greeting));
#else
            TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
#endif

            {
#ifdef DOUBLE_BUFFER
                cairo_surface_t *surface = cairo_win32_surface_create(newDC);
#else
                cairo_surface_t *surface = cairo_win32_surface_create(hdc);
#endif
                cairo_t *cr = cairo_create(surface);

                // Draw on the cairo context.
                cairo_set_source_rgb(cr, 1, 1, 1);
                cairo_paint(cr);

                gradientExample( cr );
                cairo_surface_finish(surface);

                // Cleanup.
                cairo_destroy(cr);
                cairo_surface_destroy(surface);
            }

#ifdef DOUBLE_BUFFER
            BitBlt(hdc, 0, 0, width, height, newDC, theRect.left, theRect.top, SRCCOPY);
#endif

            SelectObject(newDC, oldBmp);
            DeleteDC(newDC);
        }

        EndPaint(hWnd, &ps);
        break;
    case WM_ERASEBKGND:
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:                                // Is A Key Being Held Down?
        {
            if(wParam == VK_ESCAPE)
            {
                PostMessage(hWnd, WM_CLOSE, 0, 0);
            }
        }
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
//全局变量
//主窗口类名称。
静态TCHAR szWindowClass[]=“CairoTestApp”);
//显示在应用程序标题栏中的字符串。
静态TCHAR szTitle[]=“开罗测试应用程序”);
HINSTANCE hInst;
//转发此代码模块中包含的函数声明:
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM);
int main(int argc,const char*argv)
{
HINSTANCE HINSTANCE=GetModuleHandle(NULL);
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_应用程序));
wcex.hCursor=LoadCursor(空,IDC_箭头);
wcex.hbrBackground=(HBRUSH)(彩色窗口+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=szWindowClass;
wcex.hIconSm=LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_应用程序));
如果(!RegisterClassEx(&wcex))
{
MessageBox(NULL,_T(“调用RegisterClassEx失败!”),szTitle,NULL);
返回1;
}
hInst=hInstance;//将实例句柄存储在全局变量中
//CreateWindow的参数解释如下:
//szWindowClass:应用程序的名称
//szTitle:出现在标题栏中的文本
//WS_OVERLAPPEDWINDOW:要创建的窗口类型
//CW_使用默认值,CW_使用默认值:初始位置(x,y)
//500、100:初始尺寸(宽度、长度)
//NULL:此窗口的父级
//NULL:此应用程序没有菜单栏
//hInstance:WinMain的第一个参数
//NULL:此应用程序中未使用
HWND HWND=CreateWindow(
szWindowClass,
szTitle,
WS_重叠窗口,
CW_USEDEFAULT,CW_USEDEFAULT,
256, 256,
无效的
无效的
hInstance,
无效的
);
如果(!hWnd)
{
MessageBox(NULL,_T(“调用CreateWindow失败!”),szTitle,NULL);
返回1;
}
//ShowWindow的参数解释如下:
//hWnd:从CreateWindow返回的值
//nCmdShow:WinMain的第四个参数
显示窗口(hWnd、SW_显示正常);
更新窗口(hWnd);
//主消息循环:
味精;
while(true)
{
if(peek消息(&msg,NULL,0,0,PM_-REMOVE))
{
如果(msg.message==WM\u退出)
{
打破
}
其他的
{
翻译信息(&msg);
发送消息(&msg);
}
}
}
//窗口(hWnd);
未注册类(szWindowClass、hInstance);
返回0;
}
void gradiente示例(cairo_t*cr){
开罗模式;
pat=开罗模式创建线性(0.0,0.0,0.0,256.0);
开罗(cairo)(pat,1,0,0,1);;
开罗(cairo)(pat,0,1,1,1,1)(pat,0,1,1);;
cairo_矩形(cr,0,0,256,256);
cairo_集_源(cr、pat);
开罗填料(cr);
开罗模式破坏(pat);
pat=开罗模式创建径向(115.2102.4,25.6,
102.4,  102.4, 128.0);
开罗(cairo)(pat,0,1,1,1,1)(pat,0,1,1);;
开罗(cairo)(pat,1,0,0,1);;
cairo_集_源(cr、pat);
开罗弧(cr,128.0,128.0,76.8,0,2*3.14159);
开罗填料(cr);
开罗模式破坏(pat);
}
#定义双缓冲区
LRESULT回调WndProc(HWND HWND,UINT消息,WPARAM WPARAM,LPARAM LPARAM)
{
PAINTSTRUCT-ps;
HDC-HDC;
TCHAR问候语[]=“你好,世界!”;
开关(信息)
{
案例WM_油漆:
hdc=开始喷漆(hWnd和ps);
{
HDC newDC=CreateCompatibleDC(HDC);
直截了当;
GetClientRect(hWnd和theRect);
int宽度、高度;
宽度=右侧-左侧;
高度=垂直底部-垂直顶部;
HBITMAP theBmp=CreateCompatibleBitmap(新建DC、宽度、高度);
hgdobj oldBmp=选择对象(newDC,theBmp);
//测试一些文本。
#ifdef双_缓冲区
文本输出(newDC,5,5,问候语,_tcslen(问候语));
#否则
文本输出(hdc,5,5,问候语,_-tcslen(问候语));
#恩迪夫
{
#ifdef双_缓冲区
cairo\u surface\u t*surface=cairo\u win32\u surface\u create(newDC);
#否则
cairo\u surface\u t*surface=cairo\u win32\u surface\u create(hdc);
#恩迪夫
cairo_t*cr=cairo_创建(曲面);
//利用开罗的环境。
cairo_set_source_rgb(cr,1,1,1);
开罗漆(cr);
梯度样品(cr);
开罗表面光洁度(表面);
//清理。
开罗大学(cr);
开罗·表面·破坏(表面);
}
#ifdef双_缓冲区
BitBlt(hdc、0、0、宽度、高度、新建DC、theRect.left、theRect.top、SRCCOPY);
#恩迪夫
选择对象(新建DC、旧BMP);
DeleteDC(newD