Qt:玩转QPainter序列一

前言

最近想潜心研究一下QPainter这个类,最好把QPainter所有的函数都敲一遍,特地记录一下。

在说QPainter之前我们需要了解两个非常重要的东西

第一个坐标系

我用两张图来表示

代码实操的结果

更加详细的坐标系内容请看我的另一篇博客

第二个是有关绘图的一些基本概念

QPainter:Qt中的绘图类,用于在各种设备上进行绘图操作。
QPen:用于定义线条的颜色、宽度和样式。
QBrush:用于定义填充区域的颜色、渐变和图案。
QPixmap:用于表示位图图像。
QImage:用于表示图像,支持像素级别的操作。

正文

下面是QPainter的类定义开头一部分,我们逐行开始分析

1. 头文件保护符:

cpp 复制代码
#ifndef QPAINTER_H
#define QPAINTER_H

这段代码用于防止头文件的重复包含。
#ifndef QPAINTER_H 是在检查 QPAINTER_H 是否未定义。

如果未定义,则使用 #define QPAINTER_H 来定义它。

这样当此文件被多次包含时,后续的包含将不会重复定义 QPAINTER_H,从而避免编译错误。

2. 头文件的包含:

cpp 复制代码
#include <QtGui/qtguiglobal.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qrect.h>
#include <QtCore/qpoint.h>
#include <QtCore/qscopedpointer.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qimage.h>
#include <QtGui/qtextoption.h>

这些 #include 指令用于将其他必要的头文件包含到当前文件中。

  • QtGui/qtguiglobal.h 包含与Qt GUI模块相关的全局定义。
  • QtCore/qnamespace.h 包含命名空间相关的定义。
  • qrect.hqpoint.h 是与几何对象相关的头文件,定义了矩形和点的类。
  • qscopedpointer.h 提供了智能指针的功能,用于内存管理。
  • qpixmap.hqimage.h 是处理图像和位图的类的头文件。
  • qtextoption.h 包含与文本显示选项相关的定义。

3. 条件性包含:

cpp 复制代码
#ifndef QT_INCLUDE_COMPAT
#include <QtGui/qpolygon.h>
#include <QtGui/qpen.h>
#include <QtGui/qbrush.h>
#include <QtGui/qmatrix.h>
#include <QtGui/qtransform.h>
#include <QtGui/qfontinfo.h>
#include <QtGui/qfontmetrics.h>
#endif

这部分代码表示,当 QT_INCLUDE_COMPAT 未定义时,才会包含这些头文件。

这些文件中包含了与多边形、画笔、刷子、矩阵变换、字体信息、字体度量等相关的类。

4. 命名空间开始:

cpp 复制代码
QT_BEGIN_NAMESPACE

QT_BEGIN_NAMESPACE 是一个宏,用于标记Qt库的命名空间的开始。

它通常与 QT_END_NAMESPACE 搭配使用,用于确保在不同的编译环境中命名空间的正确使用。

这是下面一部分的定义,继续看

1. 前置声明(Forward Declarations):

cpp 复制代码
class QBrush;
class QFontInfo;
class QFontMetrics;
class QPaintDevice;
class QPainterPath;
class QPainterPrivate;
class QPen;
class QPolygon;
class QTextItem;
class QTextEngine;
class QMatrix;
class QTransform;
class QStaticText;
class QGlyphRun;

class QPainterPrivateDeleter;

这些是类的前置声明。前置声明是告诉编译器这些类的名称和它们是类类型,而不提供它们的完整定义。

这样做的目的是提高编译效率,避免包含不必要的头文件。

在需要使用这些类的指针或引用时,可以仅使用前置声明,而不需要完整的类定义。

2. 类的声明:

cpp 复制代码
class Q_GUI_EXPORT QPainter{}

QPainter 是一个用来执行绘图操作的类。在Qt中,QPainter 类提供了绘制文本、图像、线条和其他图形元素的方法。

  • Q_GUI_EXPORT 是一个宏,用于导出这个类,使其在动态链接库(DLL)中可用。

3. 宏定义:

cpp 复制代码
Q_DECLARE_PRIVATE(QPainter)
Q_GADGET
  • Q_DECLARE_PRIVATE(QPainter) 是一个宏,用于声明一个指向该类的私有数据指针 d_ptr。这是Qt中常用的一个设计模式,用来实现Pimpl(Pointer to Implementation)技术,分离接口和实现,增强封装性。

  • Q_GADGET 是一个用于声明轻量级的Qt对象的宏。虽然它不像 QObject 那样支持信号和槽,但它可以使用元对象系统的其他功能,比如枚举的元信息。

4. 公共部分 (public):

cpp 复制代码
public:
    enum RenderHint {
        Antialiasing = 0x01,
        TextAntialiasing = 0x02,
        SmoothPixmapTransform = 0x04,
#if QT_DEPRECATED_SINCE(5, 14)
        HighQualityAntialiasing Q_DECL_ENUMERATOR_DEPRECATED_X("Use Antialiasing instead") = 0x08,
        NonCosmeticDefaultPen Q_DECL_ENUMERATOR_DEPRECATED_X("Default pen is non-cosmetic now") = 0x10,
#endif
        Qt4CompatiblePainting = 0x20,
        LosslessImageRendering = 0x40,
    };

public 表示这一部分的成员可以被类的外部访问。

  • RenderHintQPainter 类中的一个枚举类型,用于指定绘图时的渲染提示。渲染提示是一些位掩码值,用于控制绘图的质量和性能。

    • Antialiasing = 0x01:启用抗锯齿,以获得平滑的图形边缘。
    • TextAntialiasing = 0x02:启用文本的抗锯齿处理。
    • SmoothPixmapTransform = 0x04:启用平滑的位图变换。

    枚举中还包括一些已弃用的选项,用 QT_DEPRECATED_SINCE(5, 14) 来标记。

    • HighQualityAntialiasing:高质量抗锯齿处理,但已弃用,建议使用 Antialiasing 代替。
    • NonCosmeticDefaultPen:默认笔非装饰性,但已弃用。

    其他选项:

    • Qt4CompatiblePainting = 0x20:启用与Qt 4兼容的绘图模式。
    • LosslessImageRendering = 0x40:启用无损图像渲染,确保图像质量。

OK现在我们写一个小例子来测试这些渲染

cpp 复制代码
void PlayQPainter::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    // 设置当前的渲染提示
    //painter.setRenderHint(QPainter::Antialiasing,true);

    // 绘制不同的图形以展示渲染效果
    painter.drawEllipse(50, 50, 200, 200);  // 画圆
    painter.drawText(100, 300, "没有开始渲染时的效果!");  // 画文本
    // 绘制图像(假设有一个图像)
    painter.drawPixmap(50, 350, QPixmap("D:/all_the_code/qt_code/ts/playQPainter/lyf.jpg"));

    // 测试其他几何图形
    painter.drawRect(300, 50, 200, 200);  // 画矩形
    painter.drawLine(550, 50, 580, 580);  // 画线条
}

没有开启渲染时可以看到线条有许多锯齿状

cpp 复制代码
void PlayQPainter::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    // 设置当前的渲染提示
    painter.setRenderHint(QPainter::Antialiasing,true);

    // 绘制不同的图形以展示渲染效果
    painter.drawEllipse(50, 50, 200, 200);  // 画圆
    painter.drawText(100, 300, "开启平滑抗锯齿时的效果!");  // 画文本
    // 绘制图像(假设有一个图像)
    painter.drawPixmap(50, 350, QPixmap("D:/all_the_code/qt_code/ts/playQPainter/lyf.jpg"));

    // 测试其他几何图形
    painter.drawRect(300, 50, 200, 200);  // 画矩形
    painter.drawLine(550, 50, 580, 580);  // 画线条
}

可以看到线条平滑了许多

cpp 复制代码
void PlayQPainter::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QFont font;
    font.setPointSize(20);
    painter.setFont(font);
    // 设置当前的渲染提示
    painter.setRenderHint(QPainter::TextAntialiasing,true);

    // 绘制不同的图形以展示渲染效果
    painter.drawEllipse(50, 50, 200, 200);  // 画圆
    painter.drawText(100, 300, "开启文本抗锯齿时的效果!");  // 画文本
    // 绘制图像(假设有一个图像)
    painter.drawPixmap(50, 350, QPixmap("D:/all_the_code/qt_code/ts/playQPainter/lyf.jpg"));

    // 测试其他几何图形
    painter.drawRect(300, 50, 200, 200);  // 画矩形
    painter.drawLine(550, 50, 580, 580);  // 画线条
}

使用文本抗锯齿对文本影响很小,至少在我这边运行时是这样。

平滑位图变换我就不测试了,它是要用QImage来加载图片,而不是用QPainter来加载

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript