GDI+学习笔记

  • 1.GDI+介绍:
  • 2.GDI+的载入与卸载:
  • 3.Qt中GDI+的使用
    • (1).pro文件设置
    • (2)widget属性设置
    • (3)重载painEngine()方法
    • (4)获取HDC
  • 4.静态函数FromFile、FromHBitmap和FromStream的使用
  • 5.在 Qt 中使用 GDI+ 的实例
    • 6.遇到的一些问题:关于Bitmap的复制拷贝,以及多图交互的问题。

借鉴文章:博主「利白」的原创文章
借鉴文章:博主「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.csdn.net/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的使用

关于这三个静态函数的使用:
CSDN博主「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的相互转换问题。
待续。。。

学习Qt使用GDI+绘图笔记相关推荐

  1. Qt使用GDI绘图(仅Windows平台)

    绘图引擎 Windows环境下二维绘图引擎有多种选择:GDI.GDI+.DirectDraw.Qt/QPainter.Agg.Cairo.skia.Direct2D.Direct3D.OpenGL等. ...

  2. Windows高级工程师:GDI+绘图;基础入门大全

    Windows GDI绘图基础知识 一.Windows可以画直线.椭圆线(椭圆圆周上的曲线)和贝塞尔曲线. 7 个画线函式是: (1)画直线 LineTo    BOOL LineTo(HDC hdc ...

  3. GDI+绘图轻松入门[5]-绘图坐标的理解和应用

    我们都知道,有大约五种方式可以获得一个坐标位置,他们分别是new point.PointToClient.PointToScreen,Location及控件鼠标事件传递的坐标.为了了解绘图坐标,我们事 ...

  4. Qt 开发使用VSCode 笔记2

    在之前有写过使用VSCode开发QT的笔记 Qt 开发使用VSCode 在以前的基础上继续学习记录写下<Qt 开发使用VSCode 笔记2> 该笔记相比之前的Qt 开发使用VSCode新加 ...

  5. OriginPro 科研绘图笔记 一

    OriginPro 科研绘图笔记 一 一.前言 二.软件准备 三.数据准备工具 四.快捷绘图 五.函数绘图 六.与其他编程语言接口 一.前言 OriginPro是由OriginLab公司开发的专业版科 ...

  6. windows编程之GDI绘图 -- 实验3-1

    windows编程之GDI绘图 – 实验3-1 文章目录 windows编程之GDI绘图 -- 实验3-1 @[toc] 1.实验名称 2.实验目的 3.实验的步骤和方法 4.代码实现 5.思考题 6 ...

  7. Qt:QChart绘图介绍(主要包含类:QChart,QTableWidget,QGridLayout)

    Qt:QChart绘图介绍(主要包含类:QChart,QTableWidget,QGridLayout) 首先点击[打开]摁键,从excel中读入相关数据 之后点击[计算]摁键,将数据进行处理,并将部 ...

  8. 使用bitblt提高GDI+绘图的效率(转)

    最近在做使用GDI+绘制K线界面发现传统的GDI+绘制方式效率比较低,根本无法满足K线界面及时刷新的速度要求. 所以做了个GDI+绘制图形界面的试验,改试验主要在一个600×600的区域内每隔10MS ...

  9. cimage和gdi绘图效率比较_GDI+和GDI绘图性能对比实验

    龙源期刊网 http://www.qikan.com.cn GDI+ 和 GDI 绘图性能对比实验 作者:王克茹 来源:<科技创新与应用> 2013 年第 25 期 摘 要:本文通过完全相 ...

最新文章

  1. UML 数据建模EA的基本使用——《用例图的使用》
  2. java如何做全局缓存_传智播客JNI第七讲 – JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式...
  3. 【WebRTC---进阶篇】(一)服务器基础编程
  4. 使用python实现对于chineseocr的API调用
  5. 黑马博客——详细步骤(一)路由跳转和抽取公共部分代码
  6. 555定时器的应用——单稳态触发器
  7. 科大讯飞 离线语音识别python_使用python语言调用科大讯飞离线语音合成
  8. WebService
  9. office 2010 Word,Excel的功能区突然消失了
  10. 宏基因组公众号4年精华文章目录,收藏贴(2021.1更新)
  11. JS网页特效实例:让网页前进和后退
  12. 【服务器数据恢复】某银行服务器磁盘阵列多块硬盘掉线的数据恢复案例
  13. 前端笔记(03)——一文看懂flex布局
  14. 图形学笔记(十八)光场、颜色和感知—— 光场相机(全光函数、光线和光场的定义)、可见光谱、谱功率密度、颜色的生物学基础、Tristimulus Theory、同色异谱、加色与减色系统、颜色空间SPD
  15. 鲤鱼精的Python学习笔记(一)
  16. Day69(贪心算法)
  17. JasperReports配置中文字体
  18. 超级兔子魔法设置正式版
  19. 湖南“聚才兴湘”2014年春季特大型综合人才招聘会4月12日举行
  20. Android 点击View实现前后翻转动画

热门文章

  1. LVS(DR)+Keepalive高可用+Zabbix监控脑裂
  2. JSF seam 中使用UEditor
  3. 【转载】《天下粮仓》
  4. CATTI 三级笔译考试准备
  5. 小米科技-运维工程师-面试经验
  6. 2020年高考理综试题解析:聚焦关键能力,凸显价值引领
  7. 好嗨游戏 || 20款全世界最佳移动RPG角色扮演游戏(下)
  8. Android 10适配要点,作用域存储
  9. 用AntlR4实现简单的汇编编译器
  10. 高红冰:淘宝村促进乡村振兴