Windows GDI 教程(一) 一个简单的绘图程序

13人阅读 评论(0) 收藏 举报

常见的图形编程库,除了 GDI 外还有 GDI+、OpenGL、DirectX等等,GDI 是其中最基础的一个库。所以 GDI 注定了不会有高级应用,有兴趣的就当刷低级怪吧。

在教程的最开始,需要简单的说明一些前置条件。

开发环境与前言

首先是标明开发环境:
操作系统:win7 (xp应该可以,win8未测试)
使用工具:visual studio 2010(或更高)

窗口创建

以前代码的前置问题,首先本教程内的 GDI 画图,在最开始部分主要是在窗口内部绘制(为避免混乱窗口外部,也就是整个桌面的绘制会在很后面的地方讨论)。因此,这里需要对于创建窗口一定的了解。为了让大家可以直接复制完代码就可以在一个文件里面运行,博主准备的代码是手动动态创建窗口的代码,所以这里创建窗口的代码有点长,不过大家不要怕,我们要关注的只是中间的一小部分。这里博主先把代码贴上:

#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

/*
 * 第四步,窗口过程
 */
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        // 窗口绘制消息
        case WM_PAINT:
            /*
             * 我们只需要在这里调用我们的 GDI 绘制函数就可以,其他地方可以先无视
             */
        break;
        // 窗口关闭消息
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        // 窗口销毁消息
        case WM_DESTROY:
            PostQuitMessage(0); // 发送离开消息给系统
        break;
        // 其他消息
        default:
            // pass 给系统,咱不管
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

/*
 * 第一步,注册窗口类
 */
void RegisterMyWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wc;  

    // 1)配置窗口属性
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = MyWindowProc; // 设置第四步的窗口过程回调函数
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    // 2)注册
    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
        exit(0); // 进程退出
    }
}

/*
 * 第二步,创建窗口
 */
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
    HWND hwnd;
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        TEXT("我的窗口名称"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
        exit(0); // 进程退出
    }

    // 显示窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    return hwnd;
}

/*
 * 主函数
 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG Msg;

    // 第一步,注册窗口类
    RegisterMyWindow(hInstance);
    // 第二步:创建窗口
    hwnd =  CreateMyWindow(hInstance, nCmdShow);
    // 第三步:消息循环
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

运行效果图:
创建一个空白窗口

这个创建窗口的代码很长,看起来有点吓人,但是学习 GDI 的过程中,这其中几乎是完全不需要记忆的,只要有一定的了解,然后会 copy 就可以了。当然如果你能懂也是更好,以上代码的出处为 《Windows SDK 教程(三) 一些细节以及动态创建控件》,有兴趣的可以去看看。

那么博主也说过了,最开始的时候,这段长长的代码其实注意一个地方就可以了,就是其中的第四步窗口过程中的一个小 case。

/*
 * 第四步,窗口过程
 */
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        // 窗口绘制消息
        case WM_PAINT:
            /*
             * 只有这一个 case 是我们 GDI 入门中需要注意的
             *
             * 当程序执行到这个地方的时候,意味着系统像我们的程序发送了 WM_PAINT 消息
             * 也就是告诉我们的程序,可以开始绘制窗口的内容了。
             *
             */
        break;
        // 其余略...
    }
    return 0;
}

这样看来,貌似我们要注意的地方确实很小吧。那么我接着往下走。

PS:默认情况下,系统只会向我们的程序发送一次 WM_PAINT 消息。如果想要再来一次,需要使用 SendMessage 函数,来自己向自己手动发送该消息。

坐标系

GDI 的绘图坐标系与普通的数学坐标系不同,原点 (0,0) 位于左上角。如图:
坐标系

设备上下文(DC)

DC (设备上下文, Device Contexts)是 GDI 编程中一个很基础同时也很重要的概念。博主以前看过不少网上的资料以及书上的描述,总感觉他们说的都很奇怪。这里博主为了方便大家理解就说说自己的看法:

大家只要把 DC 当成一个保存图像的内存对象即可。当我们使用 GDI 提供的函数去操作 DC 的时候,也就意味着在使用函数去修改保存在这块内存上的图像。

BeginPaint 与 EndPaint
用于从目标窗口获取可画图的 DC,以及关闭这个 DC。
函数原型

HDC BeginPaint(
  _In_   HWND hwnd,             // 传入想要获取 DC 的窗口句柄
  _Out_  LPPAINTSTRUCT lpPaint  // 保存目标窗口的绘图信息
);

 BOOL EndPaint(
  _In_  HWND hWnd,                  // 目标窗口的句柄
  _In_  const PAINTSTRUCT *lpPaint  // 目标窗口的绘图信息
);

SelectObject
设置目标 DC 选中指定的对象(如画笔、画刷、图片等等)。
函数原型

HGDIOBJ SelectObject(
  _In_  HDC hdc,        // 目标 DC 的句柄
  _In_  HGDIOBJ hgdiobj // 被选中的对象
);

CreatePen
创建一个画笔(pen)对象。
函数原型

HPEN CreatePen(
  _In_  int fnPenStyle,     // 样式
  _In_  int nWidth,         // 宽度
  _In_  COLORREF crColor    // 颜色
);

MoveToEx
移动绘制的初始位置。未移动则默认是 (0,0)。(C语言基础好的可以联想 fseek 函数)
函数原型

BOOL MoveToEx(
  _In_   HDC hdc,           // 操作目标DC的句柄
  _In_   int X,             // x 坐标
  _In_   int Y,             // y 坐标
  _Out_  LPPOINT lpPoint    // 保存移动后的当前坐标
);

LineTo
使用当前选中的对象(selected object、通常是画笔)从当前位置绘制一条直线到目标位置。
函数原型

BOOL LineTo(
  _In_  HDC hdc,    // 目标DC句柄
  _In_  int nXEnd,  // 目标位置 x 坐标
  _In_  int nYEnd   // 目标位置 y 坐标
);

绘制直线实例

#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint(HWND hwnd) 
{
    // paint struct 绘图结构体,存储目标窗口可以绘图的客户端区域(client area)
    PAINTSTRUCT ps;
    HDC hdc;   // DC(可画图的内存对象) 的句柄
    HPEN hpen; // 画笔

    // 通过窗口句柄获取该窗口的 DC
    hdc = BeginPaint(hwnd, &ps);
    // 创建画笔
    hpen = CreatePen(PS_SOLID, 1, RGB(255,0,0));
    // DC 选择画笔
    SelectObject(hdc,hpen);
    // (画笔)从初始点移动到 50,50
    MoveToEx(hdc, 50, 50, NULL);
    // (画笔)从初始点画线到 100,100
    LineTo(hdc, 150, 100);

    EndPaint(hwnd, &ps);
}

/*
 * 第四步,窗口过程
 */
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        // 窗口绘制消息
        case WM_PAINT:
            Paint(hwnd); // 调用我们的 GDI 绘制函数
        break;
        // 其余略...
    }
    return 0;
}

// 其余略

运行效果图:
这里写图片描述

查看评论

组合查询

用PB进行数据库应用系统开发时,我们经常要对大量的数据进行筛选、查询,得到符合要求的记录,这就需要用到组合条件查询功能。我在作应用系统开发时,就自己编写了一个简单而又实用的组合条件查询模板窗口,只要用...
  • xingjiaren
  • xingjiaren
  • 2001-04-10 14:22:00
  • 728

Windows GDI绘图-入门篇

Windows则提供了一抽象的接口,称之为图形设备接口(GDI)。 Windows己经提供了各种显示卡及打印机的驱动程序, 这样我们的程序就可以不必关心与系统相连的显示卡及打印机的类型。 我们的程序可...
  • xdrt81y
  • xdrt81y
  • 2014-02-20 11:44:57
  • 11019

Windows GDI绘图-实践篇一

一、基础   GDI的绘图函数基本上都是有状态的,所有的函数都要求一个HDC类型的句柄。这个HDC的获得有几个途径BeginPaint,GetWindowDC, GetDC.他们的参数都只需要一个H...
  • xdrt81y
  • xdrt81y
  • 2014-02-20 12:00:19
  • 3322

使用GDI在windows中绘图(一)——windows GDI原理

在windows下绘图可以借助一些图形库用DrawLine和DrawCirccle这样的程序来画些tuxin
  • KujoJyotaro
  • KujoJyotaro
  • 2014-07-08 23:52:54
  • 2939

C语言Windows程序设计 -> 第九天 -> GDI绘图基础

转载自:http://www.cnblogs.com/mr-wid/archive/2012/11/07/2758726.html GDI介绍     GDI(Graphics Devic...
  • u012377333
  • u012377333
  • 2016-09-01 14:06:50
  • 1717

Windows GDI绘图基础与轻量进阶

GDI 是 Graphics Device Interface 的缩写,称为图形设备接口,主要用来绘图,由动态链接库 GDI32.DLL 提供支持。 GDI 就是一个函数库,提供了很多绘图函数(...
  • softn
  • softn
  • 2016-06-20 06:36:23
  • 1348

gd i绘图教程 C#

  • 2011年05月03日 15:38
  • 417KB
  • 下载

使用Windows API进行GDI窗口绘图

1.概述 在Windows上绘图方式,跟美术大师绘图差不多。美术绘画,首先要具备以下工具:画板,画布,画笔,画刷。同样,Windows上也有相关的概念。绘图设备DeviceContext(DC),位图...
  • celte
  • celte
  • 2013-08-23 23:55:20
  • 5084

windows程序设计绘图模式及映射模式

在windows程序设计中,GDI是很重要的一部分,gdi
  • anzijian1993
  • anzijian1993
  • 2014-08-04 21:13:15
  • 557

windows基础编程----第四篇(调用GDI绘制出相关图形)

这一篇我们来画图吧~相信大家对图像的绘制也是会感兴趣点。
  • qq_30501909
  • qq_30501909
  • 2016-03-06 20:53:13
  • 1777
    个人资料
    等级:
    访问量: 440
    积分: 20
    排名: 211万+
    文章分类
    文章存档