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来加载

相关推荐
jianglq12 分钟前
C++20 新特征:Ranges库初探
开发语言·c++20·c++20新特征
wxy202431517 分钟前
基础数据类型的输入(5)再说一声“Hello World!“
开发语言·c++
kalrry22 分钟前
Qt连接mysql数据库---kalrry
数据库·qt·mysql
1900_41 分钟前
【Qt】按钮样式--按钮内部布局(调整按钮文本和图标放置在任意位置)
java·数据库·qt
大刀爱敲代码1 小时前
java实习生第一次被分配需求——完成需求的大概流程
java·开发语言
余生逆风飞翔1 小时前
前端代码上传文件
开发语言·前端·javascript
Feng_Sean1 小时前
01_Python基本语法
开发语言·网络·python
zyh200504301 小时前
c++list模拟实现
开发语言·c++
Crossoads1 小时前
【数据结构】带你初步了解排序算法
c语言·开发语言·数据结构·算法·排序算法
快乐小土豆~~1 小时前
pdfmake生成pdf的使用
开发语言·javascript·pdf