1、

什么是Direct2D

一言以蔽之,就是Windows 7平台上的一个2D图形API,可以提供高性能,高质量的2D渲染。比直接使用WINDOWSAPI会先进和轻松一些。

D2D的架构

Direct2D是基于Direct3D 10.1 API构建的,这意味着Direct2D可以使用硬件加速,下图是Direct2D与Direct3D的一个关系图

由上图可以看出,Direct2D还自带了一个软件实现(Software rasterizer),这是因为如果显卡不支持硬件加速,那么Direct2D可以使用软件方式渲染,即使这样,效果还是要优于GDI的

测试代码:


/*
配置:C++附加包含目录D:\Windows Kits\10\Include\10.0.17763.0\um(D2d1.h
附加库目录D:\Windows Kits\10\Lib\10.0.17134.0\um\x86 (D2d1.lib
附加依赖项:D2d1.lib
子系统:窗口(/ SUBSYSTEM:WINDOWS)
*/#include <windows.h>
#include <D2D1.h>
#include <dwrite.h>//dwrite,DirectWrite实际上已经是一个独立的DirectX组件了 需要连接器输入lib
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}ID2D1Factory*           g_pD2DFactory = NULL;  // Direct2D factory
ID2D1HwndRenderTarget*  g_pRenderTarget = NULL;    // Render target
ID2D1SolidColorBrush*   g_pBlackBrush = NULL;  // A black brush, reflect the line color
IDWriteFactory* g_pDWriteFactory = NULL;VOID CreateD2DResource(HWND hWnd)
{if (!g_pRenderTarget){HRESULT hr;//创建工厂 凭空创造  不需要对象 直接产生一个工厂hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory);if (FAILED(hr)){MessageBox(hWnd, "Create D2D factory failed!", "Error", 0);return;}// Obtain the size of the drawing areaRECT rc;GetClientRect(hWnd, &rc);// Create a Direct2D render target//通过工厂创建RenderTarget渲染对象hr = g_pD2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),D2D1::HwndRenderTargetProperties(hWnd,D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),&g_pRenderTarget);if (FAILED(hr)){MessageBox(hWnd, "Create render target failed!", "Error", 0);return;}// Create a brush//通过渲染对象发 创建一个固定颜色的画刷hr = g_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::RoyalBlue),&g_pBlackBrush);if (FAILED(hr)){MessageBox(hWnd, "Create brush failed!", "Error", 0);return;}}
}
/*D2D1_COLOR_F使用sRGB编码,红色,绿色,蓝色以及Alpha(透明值)。范围是0.0-1.0。数值越大表示颜色越深,
0.0表示无此颜色,1.0表示满色。对于Alpha(透明值),0.0表示完全透明,1.0表示完全不透明*/VOID DrawRectangle(HWND hwnd)
{CreateD2DResource(hwnd);//绘制的代码要放在BeginDraw和EndDraw函数之间g_pRenderTarget->BeginDraw();//调用Clear函数可以将Render target清除为指定的背景色// Clear background color to Whiteg_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));//在Direct2D中绘制文本实际上是通过DirectWrite来实现的,一切和文本相关的接口也都是由这个接口来创建的//所以接下来要创建一个IDWriteFactory接口对象HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,__uuidof(IDWriteFactory),reinterpret_cast<IUnknown**>(&g_pDWriteFactory));//用IDWriteTextFormat来描述文本的这些属性,所以,下一步需要创建IDWriteTextFormat对象了。//需要注意的是文本的颜色并不是由该接口来控制的,而是由画刷来控制IDWriteTextFormat* g_pTextFormat = NULL;hr = g_pDWriteFactory->CreateTextFormat(L"Helvetica",                   // Font family name微软雅黑 Arial Garamond Helvetica等任意字体名NULL,                          // Font collection(NULL sets it to the system font collection)DWRITE_FONT_WEIGHT_REGULAR,    // WeightDWRITE_FONT_STYLE_NORMAL,      // StyleDWRITE_FONT_STRETCH_NORMAL,    // Stretch50.0f,                         // Size    L"en-us",                      // Local  英国-美国 zh-CN 华 -中国&g_pTextFormat                 // Pointer to recieve the created object);//需要确定文本的绘制区域,这个区域通常是一个矩形结构。所以,只需简单定义一个rect即可RECT rc;GetClientRect(hwnd, &rc);D2D1_RECT_F textLayoutRect = D2D1::RectF(static_cast<FLOAT>(rc.left+100),static_cast<FLOAT>(rc.top),static_cast<FLOAT>(rc.right - rc.left),static_cast<FLOAT>(rc.bottom - rc.top));//渲染文本,这里使用接口ID2D1HwndRenderTarget中的函数DrawText来完成具体的绘制工作/*参数说明:string,                               待绘制的文本,unicode编码。stringLength,                     文本长度。textFormat,                       文本的格式化信息(属性),上面提到过。layoutRect,                        绘制区域对应的矩形。defaultForegroundBrush,    绘制文本所用的画刷*/g_pRenderTarget->DrawText(L"hello,下单一笔50手",           // Text to render18,       // Text lengthg_pTextFormat,     // Text formattextLayoutRect,    // The region of the window where the text will be renderedg_pBlackBrush      // The brush used to draw the text);//使用画刷来 DrawRectangle函数用来绘制矩形g_pRenderTarget->DrawRectangle(D2D1::RectF(10.f, 100.f, 500.f, 500.f),g_pBlackBrush);g_pRenderTarget->DrawLine(D2D1::Point2F(100.f, 100.f),D2D1::Point2F(500.f, 500.f),g_pBlackBrush);D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect(D2D1::RectF(100.f, 100.f, 500.f, 500.f),30.0f,50.0f);g_pRenderTarget->DrawRoundedRectangle(roundedRect, g_pBlackBrush, 1.0f);D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(100.0f, 100.0f), 100.0f, 50.0f);g_pRenderTarget->DrawEllipse(ellipse, g_pBlackBrush);ellipse = D2D1::Ellipse(D2D1::Point2F(50.0f, 50.0f), 50.0f, 50.0f);g_pRenderTarget->DrawEllipse(ellipse, g_pBlackBrush);ID2D1PathGeometry* g_pLeftMountainGeometry = NULL;//创建Path geometry路径图形HRESULT hr2 = g_pD2DFactory->CreatePathGeometry(&g_pLeftMountainGeometry);if (SUCCEEDED(hr2)){//ID2D1GeometrySink用来绘画ID2D1GeometrySink *pSink = NULL;HRESULT hr3 = g_pLeftMountainGeometry->Open(&pSink); // 获取Sink对象if (SUCCEEDED(hr3)){pSink->BeginFigure(D2D1::Point2F(346,255), D2D1_FIGURE_BEGIN_FILLED);// 添加图形 D2D1_POINT_2F points[5] = {D2D1::Point2F(267, 177),D2D1::Point2F(236, 192),D2D1::Point2F(212, 160),D2D1::Point2F(156, 255),D2D1::Point2F(346, 255),};pSink->AddLines(points, ARRAYSIZE(points));pSink->EndFigure(D2D1_FIGURE_END_CLOSED);}pSink->Close(); // 关闭Sink对象}//轮廓g_pRenderTarget->DrawGeometry(g_pLeftMountainGeometry, g_pBlackBrush, 1.f);//填充//g_pBlackBrush->SetColor(D2D1::ColorF(D2D1::ColorF::OliveDrab, 1.f));g_pRenderTarget->FillGeometry(g_pLeftMountainGeometry, g_pBlackBrush);//enddraw返回是否画成功了hr = g_pRenderTarget->EndDraw();if (FAILED(hr)){MessageBox(NULL, "Draw failed!", "Error", 0);return;}}
//每个COM对象都有一个Release方法,用来释放自己,这里我们定义一个宏来释放COM对象。
VOID Cleanup()
{SAFE_RELEASE(g_pRenderTarget);SAFE_RELEASE(g_pBlackBrush);SAFE_RELEASE(g_pD2DFactory);SAFE_RELEASE(g_pDWriteFactory);}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){//D2D响应WM_PAINT消息进行渲染case   WM_PAINT:DrawRectangle(hwnd);return 0;case WM_KEYDOWN:{switch (wParam){case VK_ESCAPE:SendMessage(hwnd, WM_CLOSE, 0, 0);break;default:break;}}break;case WM_DESTROY:Cleanup();PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{WNDCLASSEX winClass;winClass.lpszClassName = "Direct2D";winClass.cbSize = sizeof(WNDCLASSEX);winClass.style = CS_HREDRAW | CS_VREDRAW;winClass.lpfnWndProc = WndProc;//函数调用 lpfn (long point function)消息处理winClass.hInstance = hInstance;winClass.hIcon = NULL;winClass.hIconSm = NULL;winClass.hCursor = LoadCursor(NULL, IDC_ARROW);winClass.hbrBackground = NULL;winClass.lpszMenuName = NULL;winClass.cbClsExtra = 0;winClass.cbWndExtra = 0;if (!RegisterClassEx(&winClass)){MessageBox(NULL, TEXT("This program requires Windows NT!"), "error", MB_ICONERROR);return 0;}HWND hwnd = CreateWindowEx(NULL,//这个是扩展风格"Direct2D",                 // window class name"Draw Rectangle",         // window captionWS_POPUP | WS_VISIBLE,             // window style最重要的是这个风格 WS_POPUP | WS_VISIBLE没有边框和标题栏创建一个弹出式窗口100,             // initial x position  CW_USEDEFAULT100,                // initial y position1200,                      // initial x size500,                       // initial y sizeNULL,                      // parent window handleNULL,                        // window menu handlehInstance,                 // program instance handleNULL);                        // creation parametersShowWindow(hwnd, iCmdShow);UpdateWindow(hwnd);MSG    msg;ZeroMemory(&msg, sizeof(msg));while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;
}

2、CreateWindow 与 CreateWindowEx

相同点: 创建一个具有扩展风格的层叠式窗口、弹出式窗口或子窗口。

不同点: CreateWindowEx 比 CreateWindow 多一个参数,可以指定窗口扩展样式。比如: 带边框。

用途上: CreateWindowEx 创建标准窗口,CreateWindow 创建子窗口,或控件。

函数原型

HWND CreateWindow (LPCTSTR lpClassName, //窗口类的名称LPCTSTR lpWindowName, //窗口标题DWORD dwStyle, //窗口风格int x, //窗口的水平位置int y, //窗口的垂直位置int nWidth, //窗口的宽度int nHeight, //窗口的高度HWND hWndParent, //父窗口的句柄HMENU hMenu, //菜单句柄或是子窗口标识符HANDLE hlnstance, //应用程序实例句柄LPVOID lpParam //创建参数);HWND CreateWindowEx (DWORD DdwExStyle, //窗口扩展风格...同上);

dwExStyle: 指定窗口的扩展风格。该参数可以是下列值:

WS_EX_NODRAG: 防止窗口被移动。

WS_EX_ACCEPTFILES: 指定以该风格创建的窗口接受一个拖拽文件。

WS_EX_APPWINDOW: 当窗口可见时,将一个顶层窗口放置到任务条上。

WS_EX_CLIENTEDGE: 指定窗口有一个带阴影的边框。

WS_EX_CONTEXTHELP: 在窗口的标题条包含一个问号标志。

当用户点击了问号时,鼠标光标变为一个问号的指针。

如果点击了一个子窗口,则子窗口接收到WM_HELP消息。

子窗口应该将这个消息传递给父窗口过程,

父窗口再通过HELP_WM_HELP命令调用WinHelp函数。

这个Help应用程序显示一个包含子窗口帮助信息的弹出式窗口。

注:WS_EX_CONTEXTHELP不能与WS_MAXIMIZEBOX和WS_MINIMIZEBOX同时使用。

WS_EX_CONTROLPARENT: 允许用户使用Tab键在窗口的子窗口间搜索。

WS_EX_DLGMODALFRAME: 创建一个带双边的窗口;该窗口可以在dwStyle中指定WS_CAPTION风格来创建一个标题栏。

WS_EX_LAYERED: 创建一个分层窗口

WS_EX_LEFT: 窗口具有左对齐属性,这是缺省设置的。

WS_EX_LEFTSCROLLBAR: 如果外壳语言是如Hebrew,Arabic,或其他支持reading order alignment的语言,

则标题条(如果存在)则在客户区的左部分。

若是其他语言,在该风格被忽略并且不作为错误处理。

WS_EX_LTRREADING: 窗口文本以LEFT到RIGHT(自左向右)属性的顺序显示。这是缺省设置的。

WS_EX_MDICHILD: 创建一个MDI子窗口。

WS_EX_NOPATARENTNOTIFY: 指明以这个风格创建的窗口在被创建和销毁时不向父窗口发送WM_PARENTNOTFY消息。

WS_EX_OVERLAPPEDWINDOW: WS_EX_CLIENTEDGE和WS_EX_WINDOWEDGE的组合。

WS_EX_PALETTEWINDOW: WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW和WS_WX_TOPMOST风格的组合

WS_EX_RIGHT: 窗口具有普通的右对齐属性,这依赖于窗口类。

只有在外壳语言是如Hebrew,Arabic或其他支持读顺序对齐(reading order alignment)

的语言时该风格才有效,否则,忽略该标志并且不作为错误处理。

WS_EX_RIGHTSCROLLBAR: 垂直滚动条在窗口的右边界。这是缺省设置的。

WS_EX_RTLREADING: 如果外壳语言是如Hebrew,Arabic,或其他支持读顺序对齐(reading order alignment)的语言,

则窗口文本是一自左向右RIGHT到LEFT顺序的读出顺序。

若是其他语言,在该风格被忽略并且不作为错误处理。

WS_EX_STATICEDGE: 为不接受用户输入的项创建一个3一维边界风格

WS_EX_TOOLWINDOW: 创建工具窗口,即窗口是一个游动的工具条。

工具窗口的标题条比一般窗口的标题条短,并且窗口标题以小字体显示。

工具窗口不在任务栏里显示,当用户按下alt+Tab键时工具窗口不在对话框里显示。

如果工具窗口有一个系统菜单,它的图标也不会显示在标题栏里,

但是,可以通过点击鼠标右键或Alt+Space来显示菜单。

WS_EX_TOPMOST: 指明以该风格创建的窗口应放置在所有非最高层窗口的上面

并且停留在其L,即使窗口未被激活。

使用函数SetWindowPos来设置和移去这个风格。

WS_EX_TRANSPARENT: 指定以这个风格创建的窗口在窗口下的同属窗口已重画时,该窗口才可以重画。

由于其下的同属窗口已被重画,该窗口是透明的。

dwStyle: 指定创建窗口的风格。该参数可以是下列窗口风格的组合再加上说明部分的控制风格。

WS_BORDER: 创建一个带边框的窗口。

WS_CAPTION: 创建一个有标题框的窗口(包括WS_BODER风格)。

WS_CHILD: 创建一个子窗口。这个风格不能与WS_POPUP风格合用。

WS_CHILDWINDOW: 与WS_CHILD相同。

WS_CLIPCHILDREN: 当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。

WS_CLIPSIBLINGS: 排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,

WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。

如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,

则在重绘子窗口的客户区时,就会重绘邻近的子窗口。

WS_DISABLED: 创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。

WS_DLGFRAME: 创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。

WS_GROUP: 指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,

自第二个控制开始每个控制,具有WS_GROUP风格,

每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。

用户随后可以使用光标在组内的控制间改变键盘焦点。

WS_HSCROLL: 创建一个有水平滚动条的窗口。

WS_ICONIC: 创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。

WS_MAXIMIZE: 创建一个初始状态为最大化状态的窗口。

WS_MAXIMIZEBOX: 创建一个具有最大化按钮的窗口。

该风格不能与WS_EX_CONTEXTHELP风格同时出现,

同时必须指定WS_SYSMENU风格。

WS_OVERLAPPED: 产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。

WS_OVERLAPPEDWINDOW: 创建一个具有 WS_OVERLAPPED,

WS_CAPTION,

WS_SYSMENU,

WS_THICKFRAME,

WS_MINIMIZEBOX,

WS_MAXIMIZEBOX风格的层叠窗口,

与WS_TILEDWINDOW风格相同。

WS_POPUP: 创建一个弹出式窗口。该风格不能与WS_CHILD风格同时使用。

WS_POPUPWINDOW: 创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,

WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。

WS_SIZEBOX: 创建一个可调边框的窗口,与WS_THICKFRAME风格相同。

WS_SYSMENU: 创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。

WS_TABSTOP: 创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。

按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。

WS_THICKFRAME: 创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。

WS_TILED: 产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。

WS_TILEDWINDOW: 创建一个具有 WS_OVERLAPPED,

WS_CAPTION,

WS_SYSMENU,

WS_THICKFRAME,

WS_MINIMIZEBOX,

WS_MAXIMIZEBOX风格的层叠窗口。

与WS_OVERLAPPEDWINDOW风格相同。

WS_VISIBLE: 创建一个初始状态为可见的窗口。

WS_VSCROLL: 创建一个有垂直滚动条的窗口。

C++ Direct2D绘图、winapi创建窗口初探相关推荐

  1. Rust使用winapi创建窗口

    Rust使用winapi创建窗口:https://paper.knowlesea.top/post/45

  2. 【OpenGL】七、桌面窗口搭建 ( 导入头文件 | 桌面程序入口函数 | 注册窗口 | 创建窗口 | 显示窗口 )

    文章目录 一.导入头文件 二.桌面程序入口函数 三.注册窗口 四.创建窗口 五.显示窗口 六.完整代码示例 七.相关资源 基于 [OpenGL]一.Visual Studio 2019 创建 Wind ...

  3. Windows程序设计之创建窗口示例

    Windows程序设计书本上的创建窗口示例,手敲代码,拿出了show,记录一下而已~~~ 一.代码如下: #include <tchar.h> #include <windows.h ...

  4. 在非主线程中创建窗口

    很多朋友都会有过这样的经历,为什么在主线程中创建窗口且窗口工作很正常,但一移到非主线程(有的朋友喜欢叫它为工作线程),却无法正常工作.本文就这个问题和各位探讨,可能无法做到尽善尽美,但能抛砖引玉也算是 ...

  5. vs2022创建窗口应用程序

    打开vs2022,创建新项目,找到桌面向导,如图 创建一个新工程,选择控制台应用程序,选择空项目,创建即可完成. 控制台窗口实例 #include<Windows.h> int WINAP ...

  6. 【Python_PyQtGraph 学习笔记(五)】基于PyQtGraph和GraphicsLayoutWidget动态绘图并实现窗口模式,且保留全部绘图信息

    基于PyQtGraph和GraphicsLayoutWidget动态绘图并实现窗口模式,且保留全部绘图信息 前言 基于PySide2.PyQtGraph和GraphicsLayoutWidget动态绘 ...

  7. Windows编程-创建窗口

    窗口创建的基本步骤是: 设计窗口类 注册窗口类 创建窗口 显示更新窗口 消息循环 编写回调函数 ----------帅气的分割线---------– 下面我们一步一步进行讲解: 1.设计窗口类WNDC ...

  8. 【免杀前置课——Windows编程】五、窗口控件——什么是控件、Windolws 窗口两大类、Windows标准控件/通用控件、控件响应的接收、创建窗口制作不同控件

    窗口控件 WINDOW控件 什么是控件? 控件是常见的窗口上的交互元素.例如:一个按钮,一个复选框,一个列表框等.当控件的特定功能被触发后,会主动发送消息通知父窗口,父窗口可以通过发送消息给控件控制控 ...

  9. MFC学习笔记--MFC创建窗口

    MFC创建窗口 基本说明 过程 消息映射机制 应用例子 利用模版创建窗口 文化建设 基本说明 mfc:微软基础类库(microsoft foundation classes)微软公司提供的类库,以 * ...

最新文章

  1. RxJava 内置多种用于调度的线程类型
  2. Mac没有winnt格式_8款优秀软件,让你使用mac更舒适
  3. 安装mysql Install/Remove of the Service Denied!错误的解决办法
  4. Linux -su、sudo、限制root远程登录
  5. import java.awt.event.;是什么意思,。import java.awt.*;import java.awt.event.*;import...
  6. JPA用TABLE生成主键
  7. RHCE033内容摘要
  8. 图神经网络-图与图学习笔记-中
  9. 【python爬虫】http.cookiejar库之CookieJar,模拟登录与访问
  10. ubuntu14.04 clementine音乐播放器无法播放ape格式解决方法
  11. React中实现防抖功能的两种方式
  12. 92 - 青蛙跳台阶
  13. Android Studio如何用无线(WiFi)连接手机进行调试
  14. 使用pip/pip3安装第三方模块,出现Cannot unpack file xxx的问题的解决以及pip安装速度慢或出现readtime out问题的解决。
  15. dz论坛附件在服务器中的位置,discuz x3 如何将头像和帖内等附件分离到远程服务器?...
  16. 06-jQuery的文档操作***
  17. hdf5格式的matlab读写操作
  18. Orchard学习 01、orchard日志
  19. 计算机设备维修更换记录,单位电脑设备维护(维修)
  20. 美国打车应用Lyft公布IPO招股书 预计3月底挂牌交易

热门文章

  1. 哲理故事三百篇(1-50)5
  2. JAVA红石_[我的世界]Java版入门红石教程ep1.½---红石的兴趣与概念
  3. 稳定同位素标记谱图可作为另一维数据
  4. 用txt文本显示图片
  5. 不能让假期变得更长,但整个十月都能让支付宝里的黄金变更大!
  6. 灵魂拷问!GPT-4来了!人类自媒体博主存在的意义是什么?
  7. spark之OOM常见问题梳理(一)
  8. C语言输入字符和字符串
  9. You辉编程_MongoDB基础
  10. 30 个与程序猿有关的成语