绘图引擎
Windows环境下二维绘图引擎有多种选择:GDI、GDI+、DirectDraw、Qt/QPainter、Agg、Cairo、skia、Direct2D、Direct3D、OpenGL等。
GDI:微软原生的二维绘图引擎。
优点:微软的全力支持,作为操作系统核心层效率方面不用担心,支持多种开发框架(含语言):WinSDK、MFC、Delphi等。
缺点:不是面向C++对象组织的,使用起来较为繁琐;不支持反锯齿,不支持复杂的绘图效果(这个相对于GDI+而言)。
GDI+:微软后来推出的二维绘图引擎。
优点:微软的全力支持,支持多种开发框架(含语言):WinSDK、MFC、Delphi等,可以实现复杂的绘图效果,如反锯齿、路径画刷等;面向对象的架构,使用起来比较方便。
缺点:绘图效率较GDI稍低,绘图交互性不如GDI(缺少GDI的支持位运算的绘图模式),开启反锯齿后效率不如Qt。
Qt:Qt的二维图形引擎是基于QPainter类的,绘图的效果取决于QPainter的设置。面向对象的方式组织,使用起来较为方便。
Agg:C++编写的开源绘图引擎(基于GPL协议)
Cairo:C编写的开源绘图引擎(基于LGPL协议),大名鼎鼎的FireFox就是用这个绘图引擎的。
Skia:Google的Android的绘图引擎。
Direct2D:微软在WindowsVista及之后的Windows版本推出的意在取代GDI、GDI+的二维绘图引擎,支持硬件加速。Direct 2D是微软在后XP时代开发的开发二维绘图引擎。微软出于兼容性的考虑还会继续对GDI、GDI+进行支持,但毫无疑问微软的策略是要Direct 2D取代GDI和GDI+的,因此在WindowsVista及其之后的Windows上进行二维绘图开发,建议是直接使用Direct2D。Direct 2D支持硬件加速,在绘图效率应有一定程度的提升。
Direct3D:微软开发的3D绘图引擎。
OpenGL:SGI开发的3D绘图引擎。OpenGL的优势是三维绘图,不建议用来二维绘图,因为OpenGL在二维一些操作并不合适,如二维中的点、线捕捉、自定义图例的添加、打印的支持等等。
使用GDI取代QPainter
QPainter在高频绘画的使用CPU占用较高,我们可以使用GDI绘图。由于没有复杂的抗锯齿处理,GDI绘图效率非常不错。GDI因为是使用GPU绘图,会减少CPU占用。
因为Qt是通过repaint和update事件触发paintEvent绘图,其他绘图会被覆盖,所以需要以下方法实现GDI绘图:
在需要绘图的Widget构造函数写setAttribute(Qt::WA_PaintOnScreen, true);
重写该Widget的QPaintEngine * paintEngine()函数返回nullptr;
在绘图函数用GDI绘图,不要在paintEvent实现,因为刷新会慢,在自己主动调用的函数里写:
HWND hwnd;
hwnd = (HWND)this->winId();
HDC labelDC = GetDC(hwnd);//取得窗体句柄
QImage image(imageRaw.get(), m_w, m_h, QImage::Format_Grayscale8);//imageRaw是std::shared_ptr<unsigned char>类型,m_w和m_h是图像宽高
QPixmap pixmap = QPixmap::fromImage(image);
HBITMAP bitMap = toHBITMAP(pixmap);//通过一系列转换得到HBITMAP位图
HDC hdcsource1 = CreateCompatibleDC(labelDC);//创建后备显示缓冲
SelectObject(hdcsource1, bitMap);
BitBlt(labelDC, 0, 0, m_w, m_h, hdcsource1, 0, 0, SRCCOPY);//将后备缓冲显示到屏幕
ReleaseDC(hwnd, labelDC);
DeleteObject(hdcsource1);
DeleteObject(bitMap);
Qt绘图获取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,推荐使用!
参考文献
https://blog.csdn.net/wwwwxhh/article/details/79461668
https://blog.csdn.net/ssitu/article/details/54615746
来源:oschina
链接:https://my.oschina.net/u/4394395/blog/3232736