【Win32绘图编程,GDI绘图对象】绘图基础,位图处理,绘图消息处理,画笔,画刷,文本绘制(上)

简介: 【Win32绘图编程,GDI绘图对象】绘图基础,位图处理,绘图消息处理,画笔,画刷,文本绘制

这一篇文章分享本人学习win32绘图编程,其中包括GDI绘图对象,绘图基础,基本图形的绘制,画笔画刷的使用,文本绘制,以及文本字体的更改。

一.绘图基础

  • 绘图设备DC(Device Context),有时也叫做绘图上下文/绘图描述表/显示设备上下文
  • HDC-DC句柄,表示绘图设备
  • GDI-Windows graphics device interface (win32提供的绘图API)
  • 颜色:
  • RGB函数:
  • 红黄蓝按照一定比例配比,每个点颜色都是3个字节,24位保存,一共有0~2^24-1种
  • 16位操作系统通常使用三个参数来表示颜色,如:5,5,6
  • 32位操作系统通常使用4个参数来表示颜色,如:8,8,8,8.最后一个参数表示透明度
  • 绘图设备句柄:我们使用绘图设备,必须拿到绘图设备句柄

我们来想想这样一个场景:我们需要绘图,但是我们自己不会,我们把绘图设备比喻为一个画家,那么拿到绘图设备句柄的过程就相当于是把这个画家抓过来,抓过来让他完成工作后,还需要把画家放走。

PAINTSTRUCT ps = {0};              //在绘图之前,我们需要定义一个PAINTSTURCT结构体,我们不需要关注结构体内的内容
HDC hdc = BeginPaint(...);         //抓绘图设备句柄
TextOut(hdc,100,100,"Hello",...);  //绘制文本
EndPaint(...);         //释放绘图设备

我们来细讲一下BeginPaint函数和EndPaint函数:

1.BeginPaint函数

BeginPaint 函数准备用于绘制的指定窗口,并使用有关绘图的信息填充 PAINTSTRUCT 结构。

MSDN官方文档解释BeginPaint函数

HDC BeginPaint(
  HWND hWnd,
  LPPAINTSTRUCT lpPaintStruct

其中,hWnd参数指定了要重新绘制的窗口句柄,lpPaintStruct指向我们定义的PAINTSTRUCT结构,这个函数会填上该结构中所需要的信息。

  • 返回值:如果创建成功,返回值是指定窗口的显示设备上下文的句柄,如果失败,返回NULL,指示没有显示设备上下文可用。

2.EndPaint函数

MSDN官方文档解释EndPaint函数

EndPaint函数标记指定窗口中绘制的结尾,每次调用BeginPaint函数时都需要此函数,但仅在绘制完成后才需要此函数。

语法:

BOOL EndPaint(
  HWND hWnd,          //已经重新绘制的窗口的句柄
  const PAINTSTRUCT* lpPaint    //指向包含BeginPaint检索的绘画信息的PAINTSTRUCT结构的指针
  );

返回值:返回值始终为非零值。

EndPaint函数释放BeginPaint函数检索道德显示设备上下文

3.颜色的使用

colorref–实际DWORD–using long

例如:

COLORREF nColor = 0;

赋值RGB宏:

例:

`nColor =RGB(0,0,255);

获取RGB的值:

GetRValue/GetGValue/GetBValue函数

例:

BYTE nRed = GetRValue(nColor);

二.基本图形绘制

1.点的绘制

SetPixel函数

MSDN官方文档解释SetPixel函数

SetPixel函数将指定坐标处的像素设置为指定颜色

函数原型:

COLORREF SetPixel(
  HDC hdc,      //设备上下文句柄
  int x,        //要设置的x坐标
  int y,        //要设置的y坐标
  COLORREF color        //用于绘制点的颜色
  );
  • 返回值:如果函数成功,则返回值为函数将像素设置为的RGB值。此值可能与crColor指定的颜色不同,当找不到指定颜色的完全匹配项时发生。如果函数失败,返回值为-1.

回调函数中处理绘图消息

这里给出的是所有的回调函数内容,大家可以翻到最后直接看绘制窗口消息处理过程。

LRESULT CALLBACK WindowProc(
  IN  HWND hwnd,
  IN  UINT uMsg,
  IN  WPARAM wParam,
  IN  LPARAM lParam
)
{
  char output[256] = { 0 };
  switch (uMsg)
  {
  //常见消息
  case WM_DESTROY: {
    PostQuitMessage(0);
    break;
    }
  case WM_SYSCOMMAND: {
    sprintf(output, TEXT("检测到WM_COMMAND消息\n"));
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_CREATE: {
    sprintf(output, "检测到WM_CREATE消息,将创建窗口。\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_SIZE: {
    sprintf(output, "lParam:窗口宽变化为:%d,窗口高变化为:%d \n", HIWORD(lParam), LOWORD(lParam));
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  //菜单命令消息
  case WM_COMMAND: {
    switch(LOWORD(wParam)) {
      case MY_OPEN: {
        sprintf(output, "打开按钮被点击,请到回调函数中做具体处理。\n");
        WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
        break;
      }
      case MY_QUIT: {
        sprintf(output, "退出按钮被点击,请到回调函数中做具体处理。\n");
        WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
        break;
      }
      case IDM_ABOUT: {
        sprintf(output, "帮助按钮被点击,请到回调函数中做具体处理。\n");
        WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
      }
      case MY_NEWFILE: {
        sprintf(output, "打开新文件按钮被点击,请到回调函数中做具体处理。\n");
        WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
        break;
      }
      case MY_LASTTIMEFILE: {
        sprintf(output, "上次打开文件按钮被点击,请到回调函数中做具体处理。\n");
        WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
        break;
      }
    }
    break;
  }
  //键盘消息
  case WM_KEYDOWN: {
    sprintf(output, "检测到WM_KEYDOWN消息,键码值:%d.\n", wParam);
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_KEYUP: {
    sprintf(output, "检测到WM_KEYUP消息,键码值:%d.该按键被放开\n", wParam);
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  //鼠标消息
  case WM_LBUTTONDOWN: {
    sprintf(output, "检测到WM_LBUTTONDOWN消息,鼠标左键被按下。\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_LBUTTONUP: {
    sprintf(output, "检测到WM_LBUTTONUP消息,鼠标左键被放开。\n");
    WriteConsole(g_hOUTPUT, output, strlen(output),0,0);
    break;
  }
  case WM_RBUTTONDOWN: {
    sprintf(output, "检测到WM_RBUTTON消息,鼠标右键被按下。\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_RBUTTONUP: {
    sprintf(output, "检测到WM_RBUTTON消息,鼠标右键被放开。\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
  }
  case WM_MOUSEMOVE: {
    sprintf(output, "检测到WM_MOUSEMOVE消息,鼠标移动中,鼠标位置(%d,%d).\n", LOWORD(lParam), HIWORD(lParam));
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_MOUSEWHEEL: {
    sprintf(output, "鼠标滚轮滚动中,偏移量:%d,鼠标当前位置(%d,%d)\n",HIWORD(wParam), LOWORD(lParam), HIWORD(lParam));
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    break;
  }
  case WM_CONTEXTMENU: {
    TrackPopupMenu(
    CreatePopupMenu(),
    TPM_LEFTALIGN,
    0, 0, 0, hwnd, 0);
    break;
  }
  //绘制窗口消息
  case WM_PAINT: {
    sprintf(output, "检测到WM_PAINT消息");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    PAINTSTRUCT ps = { 0 };
    HDC hdc = BeginPaint(hwnd, &ps);
    SetPixel(hdc, 100, 100, RGB(6, 8, 9));
    EndPaint(hwnd, &ps);
    break;
  }
  }
  return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

处理效果:

大家可以看到程序中出现的点。由于是一个像素,可能看的不是很清楚。

2.线的绘制

像绘制点一样,我们也需要抓到设备上下文的句柄,画线,释放设备上下文。

在绘制线条的时候,我们需要几个函数,我们先来学习一下这几个函数:

MoveToEx函数

MSDN官方文档解释MoveToEx函数

MoveToEx函数将当前位置更新为指定点,并选择性地返回上一个位置。

语法:

BOOL MoveToEx(
  HDC hdc,        //设备上下文句柄
  int x,
  int y,          //指定当前点
  LPPOINT lppt    //指向接收当前位置的POINT指针,如果此参数为NULL指针,则不返回上一个位置
  )
  • 返回值:
  • 如果函数成功,则返回值为非零值
  • 如果函数失败,则返回值为0
  • 注释:MoveToEx函数将影响所有的绘图函数

LineTo函数

LineTo函数从当前位置绘制一行,但不包括指定点。

MSDN官方文档解释LineTo函数

BOOL LineTo(
  HDC hdc,          //设备上下文句柄
  int x,
  int y             //指定线条终点坐标
  );
  • 返回值:
  • 如果函数成功,返回值为非零值
  • 如果函数失败,返回值为零
  • 回调函数处理:
case WM_PAINT: {
    sprintf(output, "检测到WM_PAINT消息\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    PAINTSTRUCT ps = { 0 };
    HDC hdc = BeginPaint(hwnd, &ps);
    MoveToEx(hdc, 0, 0, NULL);
    LineTo(hdc, 500, 500);
    EndPaint(hwnd, &ps);
    break;
  }

处理效果:

3.封闭图形绘制

封闭图形:能够用画刷填充的图形

这里给出绘制矩形和绘制圆形的函数,其他函数有很多,大家可以自行学习

BOOL Rectangle(
  HDC hdc,            //设备上下文句柄
  int left,
  int top,
  int right,
  int botton
);

回调函数处理:

case WM_PAINT: {
    sprintf(output, "检测到WM_PAINT消息\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    PAINTSTRUCT ps = { 0 };
    HDC hdc = BeginPaint(hwnd, &ps);
  /*  MoveToEx(hdc, 0, 0, NULL);
    LineTo(hdc, 500, 500);*/
    Rectangle(hdc,100,100,200,200);
    EndPaint(hwnd, &ps);
    break;
  }

处理效果:

  • 绘制圆形:Ellipse函数
  • 椭圆函数绘制椭圆。 椭圆的中心是指定边界矩形的中心。

MSDN官方文档解释Ellipse函数

BOOL Ellipse(
  HDC hdc,                  //设备上下文句柄
  int left,
  int top,
  int right,
  int bottom
  );

回调函数处理:

case WM_PAINT: {
    sprintf(output, "检测到WM_PAINT消息\n");
    WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
    PAINTSTRUCT ps = { 0 };
    HDC hdc = BeginPaint(hwnd, &ps);
  /*  MoveToEx(hdc, 0, 0, NULL);
    LineTo(hdc, 500, 500);*/         //绘制直线
  //  Rectangle(hdc, 100, 100, 200, 200);    //绘制矩形
    Ellipse(hdc, 100, 100, 50, 50);        //绘制圆形
    EndPaint(hwnd, &ps);
    break;
  }

处理效果:


相关文章
|
11月前
|
算法 数据可视化 Windows
【Win32绘图编程,GDI绘图对象】绘图基础,位图处理,绘图消息处理,画笔,画刷,文本绘制(下)
【Win32绘图编程,GDI绘图对象】绘图基础,位图处理,绘图消息处理,画笔,画刷,文本绘制
|
前端开发
Delphi绘图功能[2] —— 窗体的绘图属性、圆弧类图形、获取Canvas对象(ClientRect解析)
Delphi绘图功能[2] —— 窗体的绘图属性、圆弧类图形、获取Canvas对象(ClientRect解析)
325 0
Delphi绘图功能[2] —— 窗体的绘图属性、圆弧类图形、获取Canvas对象(ClientRect解析)
|
前端开发
Delphi绘图功能[1] —— 入门(绘制直线和矩形)
Delphi绘图功能[1] —— 入门(绘制直线和矩形)
366 0
Delphi绘图功能[1] —— 入门(绘制直线和矩形)
|
存储 Python
海龟编程 python绘图工具turtle库的用法 turtle库使用方法大全,画笔设置 画布设置 绘图设置,画笔粗细,画笔颜色, 画笔速度。
海龟编程 Python绘图工具trutle库的使用方法 trutle库命令大全,总结了常用命令,学会这些命令,玩转turtle库
OpenGL几种简单图形的绘制
圆、五角星、正弦函数图形的绘制
305 0
|
Web App开发 C# Windows
Qt之图形(绘制漂亮的圆弧)
简述 综合前面对二维绘图的介绍,想必我们对一些基本绘图有了深入的了解,下面我们来实现一些漂亮的图形绘制。 简述 圆形 效果 源码 弧形 效果 源码 文本 效果 源码 旋转 效果 源码 圆形 经常地,我们会在网上看到一些列的抽奖活动,里面就有圆盘抽奖,是不是有点手痒了O(∩_∩)O~ 效果 源码 void M
2653 0