使用现有画笔

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

GDI 画笔(9)的更多相关文章

  1. {Reship}{C#}{GDI+}GDI+画笔,线,区域类型

    =================================================================================== This article is ...

  2. GDI编程

    图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...

  3. GDI编程小结

    图形设备接口(GDI)是一个可运行程序,它接受Windows应用程序的画图请求(表现为GDI函数调用),并将它们传给对应的设备驱动程序,完毕特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...

  4. VC++学习之GDI概述

    VC++学习之GDI概述 图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏 ...

  5. MFC绘图相关GDI工具对象和函数介绍

    在利用MFC进行界面编程时,除了需要熟悉各种类型控件的操作外,还会经常遇到图形绘制和显示的问题,比如时频分析界面.图像处理界面等.处理这些软件界面开发问题时,不可避免地需要用到一系列GDI工具对象和相 ...

  6. c# -- 对象销毁和垃圾回收

    有些对象需要显示地销毁代码来释放资源,比如打开的文件资源,锁,操作系统句柄和非托管对象.在.NET中,这就是所谓的对象销毁,它通过IDisposal接口来实现.不再使用的对象所占用的内存管理,必须在某 ...

  7. DWM 窗体玻璃效果实现

    我一直盼望着 Windows 新版本的发布.令人感兴趣的事情莫过于浏览 MSDN® 和 SDK 文档,查找一些可以利用和依赖的最新创新,然后让朋友和同事以及您的老板(如果幸运的话)大开眼界.Windo ...

  8. MFC编程基础

    http://www.cnblogs.com/lzmfywz/archive/2012/03/15/2399403.html 一.MFC类库概述 MFC(Microsoft Foundation cl ...

  9. 【转】DWM 窗体玻璃效果实现

    我一直盼望着 Windows 新版本的发布.令人感兴趣的事情莫过于浏览 MSDN® 和 SDK 文档,查找一些可以利用和依赖的最新创新,然后让朋友和同事以及您的老板(如果幸运的话)大开眼界.Windo ...

随机推荐

  1. AngularJS:日期转换字符

    JS有很多类库提供日期转换函数,AngularJS也不例外.可以通过$filter来完成转换,方法如下: $filter('date')(sourceDate, "yyyy/MM/dd&qu ...

  2. Clojure:日期操作方法

    ;; 日期格式转换 (def df (java.text.SimpleDateFormat. "yyyy-MM-dd hh:mm:ss")) ;; 字符串转换到日期 (defn s ...

  3. java package 命名空间

    原文: http://www.studytonight.com/java/package-in-java.php 创建一个简单的maven 项目的命令是: mvn  archetype:generat ...

  4. Kotlin和Java名称的由来

    Kotlin和Java名称的由来 学习了:http://blog.jobbole.com/111249/ JetBrains由战斗民族开发: Java来源于印尼群岛中的Java岛: Kotlin来源于 ...

  5. jQuery toast message 地址 使用

    jQuery toast message 地址 使用 https://github.com/akquinet/jquery-toastmessage-plugin/wiki

  6. 深入分析JavaWeb Item47 -- Struts2拦截器与文件上传下载

    一.struts2中的拦截器(框架功能核心) 1.过滤器VS拦截器 过滤器VS拦截器功能是一回事. 过滤器是Servlet规范中的技术,能够对请求和响应进行过滤. 拦截器是Struts2框架中的技术. ...

  7. 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法

    垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  8. SQL排他锁的解决方案

    SQL排他锁的解决方案 分类: 事务与锁 数据库管理维护2009-04-28 22:41 680人阅读 评论(0) 收藏 举报 sql数据库database服务器killdisk 问题描述: 我有一个 ...

  9. 95.Extjs 表单中自定义的验证规则 VTypes

    1 Ext.onReady(function(){ Ext.QuickTips.init(); //重写 (自定义)xtype Ext.apply(Ext.form.VTypes,{ repetiti ...

  10. Labeling Balls(拓扑)

    http://poj.org/problem?id=3687 看题意看了半天没看懂怎么回事,看完Discuss彻底凌乱了..后来看了题解才懂,就是逆向建图+拓扑排序,建图时要判重边. #include ...