学习Qt使用GDI+绘图笔记

借鉴文章:博主「利白」的原创文章
借鉴文章:博主「litanyuan」的原创文章
链接:GDI+ MSDN文档

1.GDI+介绍:

GDI+ 是 Windows 提供的图形设备接口 GDI 的后续版本,相比 GDI ,GDI+ 是面向对象的,使用更方便。

GDI:微软原生的二维绘图引擎
优点: 微软的全力支持,作为操作系统核心层效率方面不用担心,支持多种开发框架(含语言):WinSDK、MFC、Delphi等。
缺点: 不是面向C++对象组织的,使用起来较为繁琐;不支持反锯齿,不支持复杂的绘图效果(这个相对于GDI+而言)。
GDI+:微软后来推出的二维绘图引擎

优点: 微软的全力支持,支持多种开发框架(含语言):WinSDK、MFC、Delphi等,可以实现复杂的绘图效果,如反锯齿、路径画刷等;面向对象的架构,使用起来比较方便。
缺点: 绘图效率较GDI稍低,绘图交互性不如GDI(缺少GDI的支持位运算的绘图模式),开启反锯齿后效率不如Qt。如果不考虑绘图的效果,使用Win32 GDI函数直接绘图的效率大约是同样的GDI+的10倍以上。

关于绘图引擎的更多介绍请看:博主「利白」的原创文章
https://blog.youkuaiyun.com/libaineu2004/article/details/105475604


2.GDI+的载入与卸载:

使用 GDI+ 进行绘图,需要引入相关的库文件以及头文件,并且进行 GDI+ 环境的初始化操作。

(1)引入相关头文件(.h)及lib

//#include <stdafx.h>	 //这个头文件可以不用加
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "Gdiplus.lib")

(2)GDI+的启动和关闭
在使用 GDI+ 绘图之前需要调用 GdiplusStartup 加载动态链接库 Gdiplus.dll 以对 GDI+进行初始化;在使用绘图结束后需要调用 GdiplusShutdown 卸载动态链接库以对 GDI+ 进行清除工作。

//启动
Gdiplus::GdiplusStartupInput StartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &StartupInput, NULL);//GDI+初始化
//关闭
Gdiplus::GdiplusShutdown(m_gdiplusToken);//GDI+ 清除

(3)使用 RAII 管理 GDI+ 资源
定义一个类 GDIPlusHelper,把GDI+ 的启动和关闭操作分别写入类的构造和析构函数中,用来对 GDI+ 进行初始化和清理工作;然后在需要使用 GDI+ 绘图的 widget 中定义一个 GDIPlusHelper 成员即可。
GDIPlusHelper 类定义如下:

#pragma once
#include <QObject>
#include <windows.h>
#include <gdiplus.h>#pragma comment(lib, "Gdiplus.lib")
using namespace Gdiplus;
class GDIPlusHelper : public QObject
{
  Q_OBJECT
  
​public:
  GDIPlusHelper(QObject *parent = nullptr)
  {
    Gdiplus::GdiplusStartupInput StartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &StartupInput, NULL);//GDI+初始化
  }
  ~GDIPlusHelper()
  {
    Gdiplus::GdiplusShutdown(m_gdiplusToken);//GDI+ 清除
  }
private:
	ULONG_PTRm_gdiplusToken;	//GDI+句柄
  //unsigned long long  m_gdiplusToken;
};

一些注意事项:
1.在使用GDI+中相关函数和结构时,尽量加上Gdiplus命名空间名,以防止与其它模块的代码由于字段的名称同样出现冲突。比方,GDI+库中定义GDI+函数运行结果的每句类型Status,定义例如以下所看到的。假设我们须要推断函数是否正确运行,应该将返回值和Gdiplus::Ok,而不是直接和Ok比较,注意这个加上Gdiplus命名空间名的好习惯。
2.必须在窗体中创建一个此类型的对象或new一个此类型的对象,保证该类的构造函数和析构函数调用,才可使GDI+成功加载。
例如:GDIPlusHelper gidHelper;或者 GIDPlusHelper *gdiHelper = new GDIPlusHelper();
delete gdiHelper;
后续代码中标明!


3.Qt中GDI+的使用

QPainter在高频绘画的使用CPU占用较高,我们可以使用GDI+绘图。由于GDI+是使用GPU绘图,会减少CPU占用,绘图效率非常不错。

因为Qt是通过repaint和update事件触发paintEvent绘图,其他绘图会被覆盖,所以需要以下方法实现GDI+绘图:

(1).pro文件设置

pro或pri文件中增加: LIBS += -lgdi32 -luser32

(2)widget属性设置

在需要绘图的Widget构造函数写

setAttribute(Qt::WA_PaintOnScreen);
(3)重载painEngine()方法

重写该Widget的QPaintEngine * paintEngine()函数返回nullptr;

一些注意事项:
在绘图函数用GDI+绘图,不要在paintEvent实现,因为刷新会慢,在自己主动调用的函数里写

(4)获取HDC

Qt使用GDI绘图关键在于获取HDC,对于Qt5来说,有3种方法:

1、使用gui-private
pro或pri文件中增加: QT += gui-private

#include <qpa/qplatformnativeinterface.h>
 
QPlatformNativeInterface *fooPlatformNativeInterface=  QGuiApplication::platformNativeInterface();
QBackingStore *fooBackingStore = this->topLevelWidget()->backingStore();
HDC fooNRFWGetDC = static_cast<HDC>(fooPlatformNativeInterface->nativeResourceForBackingStore(QByteArrayLiteral("getDC"), fooBackingStore));

这个方法不需要releaseDC。此方法使用了Qt官方不推荐使用的 gui-private,并且在整个窗口绘图,没有限制。

2、强行使用GetDC
pro或pri文件中增加: LIBS += -lgdi32 -luser32

#include <windows.h>
HWND hwnd = (HWND)this->window()->winId();
HDC hdc = GetDC(hwnd);
ReleaseDC(hwnd, dhc);

方法2只适用于顶层窗体。此方法在整个窗口绘图,没有限制。

3、使用QtWin
pro或pri文件中增加 QT += winextras

#include <QtWin>
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbm = CreateCompatibleBitmap(hdcScreen, rectForMap.width(), rectForMap.height());
SelectObject(hdc, hbm);
QImage img = QtWin::imageFromHBITMAP(hdc, hbm, rectForMap.width(), rectForMap.height());
//释放GDI资源
DeleteObject(hbm);
DeleteDC(hdc);
ReleaseDC(nullptr, hdcScreen);

该方法是Qt5.2后的一种新的使用GDI绘图的方法,在Qt5.2中,新增了命名空间QtWin,推荐使用!


4.静态函数FromFile、FromHBitmap和FromStream的使用

关于这三个静态函数的使用:
优快云博主「yaowang107」的原创文章


5.在 Qt 中使用 GDI+ 的实例

当做完以上的准备工作之后,就可以开始使用gdi+ 绘图了,在这里使用了第二种GetDC()方式获取HDC(强制获取)。
使用双缓存模式绘图,m_DBuffer 为 Graphics* 类型,作用是将需要的图片现在缓存中绘制。

void QFrameForm::paintEvent(QPaintEvent *event)
{
	/*
	** 双缓冲绘制模式:先在Bitmap(缓存)上绘制需要绘制的图画,
	** 然后将绘制好的Bitmap图像绘制到屏幕上
	*/
	Bitmap bmp(m_nWidth,m_nHeight);		//创建画布(位图)
	m_DBuffer = Graphics::FromImage(&bmp);	//为m_DBuffer指定画布,m_DBuffer为Graphics* 类型
	
	//绘制图像
	DrawBmp();
	
	/*
	** 在实际dc设备上绘制,两种方式:
	*/
	//第一种:直接绘制到屏幕上,绘制速度较慢
	//Graphics graphics(m_hdc);	//指定绘图设备为当前屏幕
	//graphics.DrawImage(&map,m_nWidth,m_nHeight);	//将绘制好的bitmap图像画到屏幕上
	
	//第二种:使用CachedBitmap类,更加快速的绘制
	Graphics graphics(m_hdc);
	CachedBitmap ccbp(&bmp,&graphics);	//绑定位图和绘图设备
	//graphics.Clear(Color::Black);   //刷新背景用(colorse色),防止出现重影
	graphics.DrawCachedBitmap(&ccbp,0,0);
}

void QFrameForm::DrawBmp()
{
	/* 绘制最好在函数中实现
	*/
	Pen pen(m_color,1.0);	
	m_DBuffer->DrawLine(&pen,10,10,50,50);	//画线
	m_DBuffer->DrawEllipse(&pen,csPoint.X,csPoint.Y,100,100);	//画椭圆 csPoint为获取到的鼠标当前位置
}

6.遇到的一些问题:关于Bitmap的复制拷贝,以及多图交互的问题。

在项目中遇到了一个多图交互的问题,

当存在多图交互时,可能会涉及到Bitmap数据的拷贝与保存Bitmap的拷贝与保存使用到了LockBits() 函数和 UnLockBits() 函数有以及BitmapData类,
我在项目中还遇到了Bitmap与QPixmap的相互转换问题。
待续。。。

<think>好的,用户问的是Qt使用的界面是GDI+还是DirectX。首先,我需要回忆一下Qt的图形架构。Qt是一个跨平台的框架,所以它在不同操作系统上使用的底层技术可能不同。比如在Windows上,Qt可能会使用GDI或DirectX,而在其他系统上可能用OpenGL或者Vulkan。 接下来,我得确认具体版本是否有变化。比如旧版的Qt可能默认用GDI,而新版本可能转向DirectX或者其他的加速技术。Qt 5引入了场景图(Scene Graph)和不同的渲染后端,比如OpenGL、DirectX 12、Vulkan等。而Qt 6可能进一步优化了这些后端,甚至默认使用更现代的API。 另外,用户提到的GDI+是微软的2D图形API,而DirectX是更底层的3D加速框架。Qt为了跨平台,可能不会直接依赖GDI+,而是通过抽象层来选择不同的后端。例如,在Windows上,Qt可能会根据可用的硬件和驱动选择Direct3D或OpenGL,而如果这些不可用,可能回退到软件渲染,比如使用GDI。 还需要考虑用户可能的实际需求。用户可能是在开发跨平台应用,需要了解性能优化或者图形兼容性。比如,如果需要硬件加速,可能需要配置Qt使用DirectX或OpenGL后端。或者在嵌入式中,可能使用EGLFS等不同的后端。 最后,应该整理这些信息,分点说明不同平台和版本的情况,并推荐查阅Qt文档或检查运行环境来确认具体使用的渲染器。确保回答准确且对用户有帮助,避免误解。</think>Qt框架的图形渲染机制在不同平台和版本中存在差异,其设计目标是实现跨平台兼容性。以下是技术层面的分步说明: 1. **架构抽象层分析** - Qt使用QPA(Qt Platform Abstraction)作为平台抽象层 - 底层渲染器通过插件系统动态加载 - 具体实现取决于: * 操作系统版本 * 图形硬件支持 * Qt编译配置选项 2. **Windows平台实现细节** - **传统实现(5.x之前):** $$ \text{默认使用GDI软件渲染} $$ $$ \text{可选ANGLE层实现Direct3D转换} $$ - **现代实现(5.x+):** $$ \text{支持D3D11/D3D12硬件加速} $$ $$ \text{通过`-platform windows:dxgi`参数启用} $$ - **特殊场景:** * 软件回退模式使用GDI+ * OpenGL ES通过ANGLE转换为D3D 3. **多平台支持矩阵** | 平台 | 默认渲染器 | 可选方案 | |------------|-----------------|-----------------------| | Windows | Direct3D 11 | OpenGL/Software(GDI+) | | macOS | Metal | OpenGL | | Linux/X11 | OpenGL | Vulkan | | Wayland | EGL/Vulkan | OpenGL ES | 4. **运行时验证方法** ```bash # 设置环境变量查看渲染信息 export QT_LOGGING_RULES=qt.qpa.*=true ./your_qt_app | grep "Rendering backend" ``` 5. **性能优化建议** - 对于DirectX加速需求: $$ \text{编译时配置} \quad -opengl dynamic $$ - 强制指定渲染器: ```bash ./app -platform windows:dxgi # 启用DXGI交换链 ./app -platform windows:ang
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值