win32 绘图

本文介绍了Win32 API中DrawText函数的使用,包括DT_CALCRECT、DT_CENTER等参数的作用。接着讨论了如何设置颜色、画线、绘制弧线和贝塞尔曲线,提到了Arc、LineDDA、PolyBezier等功能,并阐述了回调函数的概念及其在绘图中的应用。最后,提到了PolyPolyline函数用于绘制复合线条的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DrawText函数

int DrawText(
HDC hDC, // 设备描述表句柄
LPCTSTR lpString, // 将要绘制的字符串
int nCount, // 字符串的长度
LPRECT lpRect, // 指向矩形结构RECT的指针
UINT uFormat // 正文的绘制选项
);

uFormat:
[输入]指定格式化文本的方法。它可以下列值的任意组合,各值描述如下:
DT_CALCRECT:这个参数比较重要,可以使DrawText函数计算出输出文本的尺寸。如果输出文本有多行,DrawText函数使用lpRect定义的矩形的宽度,并扩展矩形的底部以容纳输出文本的最后一行。如果输出文本只有一行,则DrawText函数改变矩形的右边界,以容纳下正文行的最后一个字符。出现上述任何一种情况,DrawText函数将返回格式化文本的高度,而不是绘制文本。
DT_CENTER:指定文本水平居中显示。
DT_VCENTER:指定文本垂直居中显示。该标记只在单行文本输出时有效,所以它必须与DT_SINGLELINE结合使用。
DT_SINGLELINE:单行显示文本,回车和换行符都不断行。

声明一个PAINTSTRUCT结构体的变量,然后传给BeginPaint函数,之后就可以画东西了。

DrawText(ps.hdc, L"希望你失去的是初吻而不是初夜.", -1, &rect, DT_CENTER);

设置颜色

SetTextColor(ps.hdc, RGB(0,150,255));  
case WM_PAINT:
    {
                      BeginPaint(hWnd, &ps);
                      TEXTMETRIC tm;
                      // 取得与文本相关的数据  
                      GetTextMetrics(ps.hdc, &tm);
                      RECT rect;
                      rect.top = 0L;
                      rect.left = ps.rcPaint.left;
                      rect.right = ps.rcPaint.right;
                      rect.bottom = rect.top + tm.tmHeight;
                      // 第一行文本  
                      SetTextColor(ps.hdc, RGB(0, 150, 255));
                      DrawText(ps.hdc, L"希望你失去的是初吻而不是初夜.", -1, &rect, DT_CENTER);
                      // 第二行文本  
                      rect.top += tm.tmHeight;
                      rect.bottom += tm.tmHeight;
                      SetTextColor(ps.hdc, RGB(220, 12, 50));
                      DrawText(ps.hdc, L"回忆是过期的黑白电影", -1, &rect, DT_LEFT);
                      // 第三行文本  
                      rect.top += tm.tmHeight;
                      rect.bottom += tm.tmHeight;
                      SetTextColor(ps.hdc, RGB(30, 255, 7));
                      DrawText(ps.hdc, L"只要我没有麻木只要我身体还有温度我就还是你的退路", -1, &rect, DT_RIGHT);
                      // 第四行文本  
                      rect.top += tm.tmHeight;
                      rect.bottom += tm.tmHeight;
                      SetTextColor(ps.hdc, RGB(0, 40, 210));
                      DrawText(ps.hdc, L"那条旧路依然没有改变", -1, &rect, DT_RIGHT);

                      EndPaint(hWnd, &ps);
                      return 0; 
    }

画线
绘制弧线使用Arc函数,第一个参数是目标HDC,随后的4个参数用于确定弧线所在的位置的矩形,最后4个参数是确定弧线的开始点和结束点的坐标。

BOOL  WINAPI Arc(  
      HDC hdc, //DC的句柄  
      int x1, // 矩形的左坐标  
      int y1, //矩形上坐标  
      int x2,//矩形的右坐标  
      int y2, //矩形的下坐标  
      int x3, //起点x坐标  
      int y3, //起点y坐标  
      int x4, //终点x坐标  
      int y4 //终点y坐标  
);  

逆时针

// 绘制弧线  
HPEN pen = CreatePen(PS_SOLID, 2, RGB(200, 100, 20));//创建笔  
// 将笔选到DC中  
auto oldObj = SelectObject(ps.hdc, pen);  
// 画弧线  
Arc(ps.hdc, 20, 100,  300, 300, 39, 110, 280, 285);  
Arc(ps.hdc, 200, 160, 390, 400, 300,350, 380,165);  
// 画完之后,把原先的笔选回去  
SelectObject(ps.hdc, oldObj);  
// 清理  
DeleteObject(pen);  

默认是逆时针方向,现在我想画顺时针方向的弧线。看下面例子,通过SetArcDirection函数改变弧线的方向。

/* 
AD_COUNTERCLOCKWISE表示逆时针方向 
AD_CLOCKWISE表示顺时针方向 
*/  
SetArcDirection(ps.hdc, AD_CLOCKWISE);  
Arc(ps.hdc, 20,150, 460,450, 90,162, 85,300);  

一条线三种不同颜色的效果
首先要声明回调函数函数,在调用之后定义,就必须先声明,不然编译的时候找不到。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
思路:
[1]定义一个回调函数;
[2]提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
[3]当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData);  

定义

VOID CALLBACK LineDDAProc(int x, int y, LPARAM lpData)  
{  
    // 从参数中取得HDC  
    HDC hdc = *((HDC*)lpData);  
    // 不同位置的线段设置不同的颜色  
    int type=0;  
    if(x <= 510 || y <= 200)  
    {  
        type = 0;  
    }  
    else if((x > 510 && x <= 700) ||  
        (y > 720 && y <= 360))  
    {  
        type = 1;  
    }  
    else  
    {  
        type = 2;  
    }  

    // 根据不同情况着色  
    switch(type)  
    {  
    case 0:  
        SetPixel(hdc,x,y,RGB(0,255,0));  
        break;  
    case 1:  
        SetPixel(hdc,x,y,RGB(0,0,255));  
        break;  
    case 2:  
        SetPixel(hdc,x,y,RGB(255,0,0));  
        break;  
    default:  
        SetPixel(hdc,x,y,RGB(255,0,0));  
    }  
}  

在相应WM_PAINT消息的时候调用LineDDA函数。

LineDDA(420,130,800,470,LineDDAProc, (LPARAM)&ps.hdc);  

LinaDDa文档介绍

BOOL LineDDA(
int nXStart, // x-coordinate of starting point
int nYStart, // y-coordinate of starting point
int nXEnd, // x-coordinate of ending point
int nYEnd, // y-coordinate of ending point
LINEDDAPROC lpLineFunc, // callback function
LPARAM lpData // application-defined data
);

完整这里写图片描述

CreatePen函数

HPEN  CreatePen(  
      int iStyle, //钢笔的样式,如虚线、实线  
      int cWidth, //线条宽度  
      COLORREF color //线条颜色  
);  

第一个参数指定线条的样式,如

#define PS_SOLID            0  
#define PS_DASH             1       /* -------  */  
#define PS_DOT              2       /* .......  */  
#define PS_DASHDOT          3       /* _._._._  */  
#define PS_DASHDOTDOT       4       /* _.._.._  */  
#define PS_NULL             5  
#define PS_INSIDEFRAME      6  
#define PS_USERSTYLE        7  
#define PS_ALTERNATE        8  

函数成功创建钢笔后就会返回HPEN,H开头的你就要知道它表示句柄。Pen也是系统资源,所以创建笔后系统要为它一个标识。

SelectObject函数

调用SelectObject函数,把刚才创建的钢笔与绘图纸关联,就等于把我们创建的绘图资源放进DC工具箱中,

HGDIOBJ WINAPI SelectObject(  
HDC hdc, //设备描述表的句柄  
HGDIOBJ h //要放到DC中的资源的句柄  
);  

调用成功后,返回原先的资源句柄。

MoveToEx是设置绘制的起点,下次绘图将从这个点开始。它的最后一个参数将被设置为当前点,即Move后的坐标。LineTo从当前坐标开始,到指定坐标之间绘制一条线段。

                    BeginPaint(hWnd, &ps);
                     // 创建钢笔  
                      HPEN pen = CreatePen(PS_DASH, 1, RGB(0, 255, 50));
                      // 把笔选到DC中  
                      SelectObject(ps.hdc, pen);
                      // 设定线段的起点  
                      MoveToEx(ps.hdc, 150, 250, NULL);
                      // 绘制线条  
                      LineTo(ps.hdc, 65, 49);
                      LineTo(ps.hdc, 12, 120);
                      LineTo(ps.hdc, 250, 78);
                      LineTo(ps.hdc, 312, 185);
                      DeleteObject(pen);

                      EndPaint(hWnd, &ps);

用完后调用DeleteObject函数将其销毁。
如图

这里写图片描述

PolyBezier函数和PolyBezierTo函数

两个函数都是用来绘制贝塞尔曲线的,不同的是,PolyBezier函数包含指定的起点和终点,PolyBezierTo是从当前点开始绘制贝塞尔曲线。

● 原型
BOOL PolyBezier(HDC hdc, CONST POINT *lppt, DWORD cPoints);
● 参数
hdc:指定的设备环境句柄。
lppt:POINT结构数组的指针,包括了样条端点和控制点的坐标,其顺序是起点的坐标、起点的控制点的坐标、终点的控制点的坐标和终点的坐标。
cPoints:指明数组中的点的个数。

前者和后者其实很相像,参数都是两个,第一个参数都是POINT结构体的数组指针,第二个参数都是一个指示POINT结构体个数的整数,只不过,前者要求是四或者四的倍数,后者要求是三或者是三的倍数。
都是用来画曲线的。

这里写图片描述

PolyPolyline绘制复合线条
PolyPolyline函数可以绘制多段复合线条。它的声明如下:

BOOL PolyPolyline(  
  HDC hdc,  
  const POINT *lppt,  
  const DWORD *lpdwPolyPoints,  
  DWORD cCount  
); 

lppt参数指向一个POINT的数组,它包含绘制复合线条所需的所有点;lpdwPolyPoints指向一个数组,这个数字数组指明如何分配点数组。

例如,lppt有7个点,我计划,前2个点绘制第一条线,接着3个点绘制第二条线,最后2个点绘制第三条线,这样一来,lpdwPolyPolyPoints得值应为:

{ 2, 3, 2 }

nCount里包含lpdwPolyPolyPoints中的数量,我们上面的例子是3.

由于两点决定一条线段,因此,lpdwPolyPolyPoints里面的值记得要>=2。

PolyBezierTo(ps.hdc, pts2, 3);
                      delete[] pts2;
                      pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80, 20, 160));
                      SelectObject(ps.hdc, pen);
                      POINT plpts[10] =
                      {
                          { 647, 3 }, { 511, 46 }, { 828, 199 }, { 403, 305 }, { 694, 22 },
                          { 902, 377 }, { 521, 45 }, { 437, 7 }, { 500, 398 }, { 775, 25 }
                      };
                      DWORD arr[4] = { 2, 3, 3, 2 };
                      PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);

最后截图
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值