zoukankan      html  css  js  c++  java
  • GDI 画笔(9)

    使用现有画笔

    Windows 提供三种备用画笔(Stock Pen):BLACK_PEN(黑色画笔)、WHITE_PEN(白色画笔)、NULL_PEN(不绘制任何图形的画笔)。

    调用 GetStockObject 函数可以获取备用画笔的句柄(HPEN),调用 SelectObject 函数可以将指定的画笔选入设备环境,并返回之前选入设备环境的画笔句柄:

    // 定义画笔句柄
    HPEN hPen, hPrevPen;
    
    // 获取备用画笔的句柄
    hPen = GetStockObject(WHITE_PEN);
    
    // 将画笔选入设备环境,函数返回之前选入设备环境的画笔的句柄
    hPrevPen = SelectObject(hdc, hPen);

    GDI 对象使用规则

    • 最终应当删除所有由用户创建的 GDI 对象
    • 当 GDI 对象被选入一个有效的设备环境时,不可删除它
    • 不可删除备用对象(Stock Object)

    创建画笔

    调用 CreatePen 函数可以创建一个画笔,画笔句柄将作为返回值返回:

    HPEN CreatePen(
        int fnPenStyle,    // 画笔样式(决定绘制的是实线、虚线或点线)
        int nWidth,        // 画笔宽度(为 0 时,将设为 1 个像素。虚线或点线只能为 1 个像素,否则将被设为实线)
        COLORREF crColor   // 画笔颜色(COLORREF 值,可以通过 RGB 宏指定)
    );

    调用 CreatePenIndirect 函数可以根据 LOGPEN(逻辑画笔)结构来建立一个画笔,画笔句柄将作为返回值返回:

    LOGPEN 结构:

    typedef struct tagLOGPEN { 
        UINT     lopnStyle; // 画笔样式
        POINT    lopnWidth; // 画笔宽度(Windows 仅使用 x 字段)
        COLORREF lopnColor; // 画笔颜色
    } LOGPEN, *PLOGPEN;

    CreatePenIndirect 函数:

    HPEN CreatePenIndirect(
      CONST LOGPEN *lplgpn   // LOGPEN 结构的地址
    );

    选择画笔

    调用 SelectObject 函数,可以将刚刚创建的画笔选入设备环境,并返回之前选入设备环境的画笔句柄:

    HGDIOBJ SelectObject(
        HDC hdc,          // 设备环境句柄
        HGDIOBJ hgdiobj   // GDI 对象句柄(这里指画笔句柄)
    );

    删除画笔

    调用 DeleteObject 函数,可以将使用完的画笔删除:

    BOOL DeleteObject(
      HGDIOBJ hObject   // GDI 对象句柄(这里指画笔句柄)
    );

    注:不要删除已被选入设备环境的当前画笔

    获取创建的画笔

    调用 GetObject 函数可以从指定画笔句柄中,得到关于此画笔的 LOGPEN 结构的各个字段的值:

    GetObject(hPen, sizeof(LOGPEN), (LPVOID)&logpen);

    调用 GetCurrentObject 函数可以获取当前被选入设备环境的画笔句柄:

    hPen = GetCurentObject(hdc, OBJ_PEN);

    填充空隙

    空隙的颜色由设备环境的背景模式和背景颜色所决定,默认的背景模式是 OPAQUE(不透明),即用背景颜色(默认为白色)填充。

    调用 SetBkColor 函数可以改变 Windows 填充空隙的背景颜色:

    COLORREF SetBkColor(
        HDC hdc,           // 设备环境句柄
        COLORREF crColor   // 背景颜色值(COLORREF)
    );

    调用 GetBkColor 函数可以得到 Windows 填充空隙的背景颜色,函数将它作为返回值返回:

    COLORREF GetBkColor(
        HDC hdc   // 设备环境句柄
    );

    调用 SetBkMode 函数可以设置背景模式,设置成 TRANSPARENT 可以阻止 Windows 填充空隙:

    int SetBkMode(
        HDC hdc,      // 设备环境句柄
        int iBkMode   // 背景模式,可选 QPAQUE(不透明)和 TRANSPARENT(透明)两种模式
    );

    绘图模式

    二元光栅操作(ROP2,raster operation 2):Windows 绘制直线时,将画笔的像素颜色和目标显示表面的像素颜色按位进行布尔运算

    默认情况下,绘图模式是 R2_COPYPEN,像素的简单复制。

    • R2_NOTCOPYPEN 像素复制为画笔颜色的反色
    • R2_BLACK 总是绘制为黑色
    • R2_WHITE 总是绘制为白色
    • R2_NOP 不操作
    • R2_NOT 将目标颜色取反,来获取绘制颜色

    调用 SetROP2 函数可以设置一种新的绘图模式:

    int SetROP2(
        HDC hdc,         // 设备环境句柄
        int fnDrawMode   // 绘图模式(以 R2 为前缀的标志)
    );

    调用 GetROP2 函数可以获取当前的绘图模式,作为返回值返回:

    int GetROP2(
        HDC hdc   // 设备环境句柄
    );


    PENDEMO 示例程序

    #include <windows.h>
    #include <math.h>
    
    #define NUMS 1000
    #define TWOPI 6.283185307179586476925286766559
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    
        HDC hdc;
        PAINTSTRUCT ps;
        static LOGPEN logpen;
        static HPEN hRedPen;
        static HPEN hBluePen;
        static int cxClient, cyClient;
        POINT apt[NUMS];
        int i;
    
        switch (message) {
    
        case WM_CREATE:
            
            logpen.lopnColor = RGB(255, 0, 0);
            logpen.lopnStyle = PS_DASH;
            logpen.lopnWidth.x = 1;
            hRedPen = CreatePenIndirect(&logpen);
    
            logpen.lopnColor = RGB(0, 0, 255);
            logpen.lopnStyle = PS_INSIDEFRAME;
            logpen.lopnWidth.x = 3;
            hBluePen = CreatePenIndirect(&logpen);
    
            return 0;
    
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
    
            return 0;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            SelectObject(hdc, hRedPen);
            MoveToEx(hdc, 0, cyClient / 2, NULL);
            LineTo(hdc, cxClient, cyClient / 2);
    
            SelectObject(hdc, hBluePen);
            for (i = 0; i < NUMS; i++) {
                apt[i].x = i * cxClient / NUMS;
                apt[i].y = (int)(( 1 - sin(TWOPI * i / NUMS)) * cyClient / 2);
            }
    
            SetTextAlign(hdc, TA_TOP | TA_RIGHT);
            TextOut(hdc, cxClient - 12, 12, TEXT("y  =  sin  x"), 12);
            TextOut(hdc, cxClient / 2 - 12, cyClient / 2 + 12, TEXT("( π,  0 )"), 9);
            TextOut(hdc, cxClient - 12, cyClient / 2 + 12, TEXT("( 2 π,  0 )"), 11);
    
            SetTextAlign(hdc, TA_TOP | TA_LEFT);
            TextOut(hdc, 12, cyClient / 2 + 12, TEXT("( 0,  0 )"), 9);
    
            PolyBezier(hdc, apt, NUMS);
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            DeleteObject(hRedPen);
            DeleteObject(hBluePen);
            PostQuitMessage(0);
            return 0;
        }
    
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    
        LPCTSTR lpszClassName = TEXT("PenDemo");
        LPCTSTR lpszWindowName = TEXT("Pen Demo Program");
    
        WNDCLASS wndclass;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hInstance = hInstance;
        wndclass.lpfnWndProc = WindowProc;
        wndclass.lpszClassName = lpszClassName;
        wndclass.lpszMenuName = NULL;
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
    
        if (!RegisterClass(&wndclass)) {
            MessageBox(NULL, TEXT("This program requires Windows NT!"), lpszWindowName, MB_ICONERROR);
            return 0;
        }
    
        HWND hwnd = CreateWindow(
            lpszClassName,
            lpszWindowName,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return msg.wParam;
    }
  • 相关阅读:
    tk资料
    jQuery 1.x和jQuery 2.x的最大区别
    活得更像一个人,我的十六年学习之路——北漂18年(44)
    java中的java.util.Map的实现类
    MVC框架的优缺点
    Web Service有关术语的解释
    Java中的字节输入出流和字符输入输出流
    对称加密算法
    怎么让这4个人在17分钟内要过桥
    mysql 只给更新表的某个字段的授权
  • 原文地址:https://www.cnblogs.com/yenyuloong/p/9122372.html
Copyright © 2011-2022 走看看