Qt 中使用 GDI+ 绘图
背景
GDI+ 是 Windows 提供的图形设备接口 GDI 的后续版本,相比 GDI ,GDI+ 是面向对象的,使用更方便。
在 Qt 中也可以使用 GDI+ 进行绘图。
GDI+ 的使用
使用 GDI+ 进行绘图,需要引入相关的库文件以及头文件,并且进行 GDI+ 环境的初始化操作。
①.相关头文件及 lib 的引入
#include #include #pragma comment(lib, "Gdiplus.lib")using namespace Gdiplus;
②.GDI+ 的启动和关闭
在使用 GDI+ 绘图之前需要调用 GdiplusStartup 加载动态链接库 Gdiplus.dll 以对 GDI+进行初始化;在使用绘图结束后需要调用 GdiplusShutdown 卸载动态链接库以对 GDI+ 进行清除工作。
GdiplusStartupInput StartupInput;GdiplusStartup(&m_gdiplusToken, &StartupInput, NULL);//GDI+初始化//GdiplusShutdown(m_gdiplusToken);//GDI+ 清除
③.使用 RAII 管理 GDI+ 资源
定义一个类 GDIPlusHelper,把GDI+ 的启动和关闭操作分别写入类的构造和析构函数中,用来对 GDI+ 进行初始化和清理工作;然后在需要使用 GDI+ 绘图的 widget 中定义一个 GDIPlusHelper 成员即可。
GDIPlusHelper 类定义如下:
#pragma once#include #include #include #pragma comment(lib, "Gdiplus.lib")using namespace Gdiplus;class GDIPlusHelper : public QObject{ Q_OBJECTpublic: GDIPlusHelper(QObject *parent = nullptr) { GdiplusStartupInput StartupInput; GdiplusStartup(&m_gdiplusToken, &StartupInput, NULL);//GDI+初始化 } ~GDIPlusHelper() { GdiplusShutdown(m_gdiplusToken);//GDI+ 清除 }private: unsigned long m_gdiplusToken;//GDI+句柄};
Qt 中使用 GDI+ 操作
为在 Qt 中使用 gdi+ 进行绘图,需要以下操作:
①.设置 widget 属性
setAttribute(Qt::WA_PaintOnScreen);
②.重载 paintEngine 方法
QPaintEngine* paintEngine() const override { return nullptr; }
③.获取 HDC
HWND hwnd = (HWND)this->winId();//窗口句柄,标识窗口的唯一整数HDC hdc = GetDC(hwnd);//设备环境句柄
Qt 中使用 GDI+ 示例
①..h 文件
#pragma once#include #include "ui_LearnGDI.h"#include "GDIPlusHelper.h"class DemoGDI : public QWidget{ Q_OBJECTpublic: DemoGDI(QWidget *parent = Q_NULLPTR);private: Ui::LearnGDIClass ui;private: GDIPlusHelper gdiHelper;protected: QPaintEngine* paintEngine() const override { return nullptr; } void paintEvent(QPaintEvent *event) override;//重绘事件private: void DrawUser(HDC hdc);//绘图方法 };
②..cpp 文件
#include "LearnGDI.h"DemoGDI::DemoGDI(QWidget *parent) : QWidget(parent){ ui.setupUi(this); setAttribute(Qt::WA_PaintOnScreen);}void DemoGDI::paintEvent(QPaintEvent *event){ HWND hwnd = (HWND)this->winId();//窗口句柄,标识窗口的唯一整数 HDC hdc = GetDC(hwnd);//设备环境句柄 RECT widgetClientRect = { 0 }; GetClientRect(hwnd, &widgetClientRect);//获取窗口客户区坐标 int rectWidth = widgetClientRect.right - widgetClientRect.left;//客户区宽度 int rectHeight = widgetClientRect.bottom - widgetClientRect.top;//客户区高度 HDC memDc = CreateCompatibleDC(hdc);//创建和设备DC兼容的内存DC HGDIOBJ memBmp = CreateCompatibleBitmap(hdc, rectWidth, rectHeight);//创建和设备DC兼容的内存位图 HGDIOBJ oldBmp = SelectObject(memDc, memBmp);//选择了位图才可以进行绘制 PatBlt(memDc, 0, 0, rectWidth, rectHeight, WHITENESS);//更改背景颜色,默认是黑色 DrawUser(memDc);//在内存DC上进行图像绘制 BitBlt(hdc, 0, 0, rectWidth, rectHeight, memDc, 0, 0, SRCCOPY);//内存位图拷贝到设备 SelectObject(memDc, oldBmp);//还原 DeleteObject(memBmp); DeleteDC(memDc); ReleaseDC(hwnd, hdc); }void DemoGDI::DrawUser(HDC hdc){ Graphics graphics(hdc); Pen pen(Color(255, 0, 255, 0),4); graphics.DrawRectangle(&pen, 20, 20, 300, 100); }
运行结果如下:
阅读世界,共赴山海
423全民读书节,邀你共读