QT OpenGL (1)2D Painting Example

news2024/11/16 6:41:22

2D Painting Example

为方便查阅,此文是原网站文档翻译与整理,如有侵权,请与本人联系。
官网


目录

  • 2D Painting Example
  • 概述
  • Helper类定义
  • Helper类实现
  • Widget类定义
  • Widget类实现
  • GLWidget类定义
  • GLWidget类实现
  • Window 类定义
  • Window 类实现
  • 运行示例


2D Painting示例展示了QPainter和QOpenGLWidget如何一起使用,以在支持的硬件上显示加速的2D图形。

在这里插入图片描述

QPainter类用于在QPaintDevice子类(如QWidget和QImage)提供的绘制设备上绘制2D图形基元。
由于QOpenGLWidget是QWidget的子类,因此可以重新实现其paintEvent()并使用QPainter在设备上绘制,就像使用QWidget一样。唯一的区别是,如果系统的OpenGL驱动程序支持,绘制操作将在硬件中加速。
在本例中,我们对QWidget和QOpenGLWidget执行相同的绘制操作。QWidget显示为启用了抗锯齿,如果系统的OpenGL驱动程序支持所需的扩展,QOpenGLWidget也将使用抗锯齿。

概述

为了能够将在QOpenGLWidget子类上绘制的结果与在QWidget子类中的本地绘制进行比较,我们希望并排显示这两种小部件。为此,我们派生了QWidget和QOpenGLWidget的子类,使用一个单独的Helper类为每个子类执行相同的绘制操作,并将它们放在一个顶级小部件中,该小部件本身提供了一个Window类。

Helper类定义

在本例中,绘制操作由辅助类执行。我们这样做是因为我们希望对QWidget子类和QOpenGLWidget子类执行相同的绘制操作。
Helper类是最小的:

class Helper
{
public:
    Helper();

public:
    void paint(QPainter *painter, QPaintEvent *event, int elapsed);

private:
    QBrush background;
    QBrush circleBrush;
    QFont textFont;
    QPen circlePen;
    QPen textPen;
};

除了构造函数之外,它只提供了一个paint()函数来使用我们的一个小部件子类提供的painter进行绘制。

Helper类实现

类的构造函数设置将内容绘制到小部件上所需的资源:

Helper::Helper()
{
    QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
    gradient.setColorAt(0.0, Qt::white);
    gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));

    background = QBrush(QColor(64, 32, 64));
    circleBrush = QBrush(gradient);
    circlePen = QPen(Qt::black);
    circlePen.setWidth(1);
    textPen = QPen(Qt::white);
    textFont.setPixelSize(50);
}

实际绘制是在paint()函数中执行的。这需要一个已经设置为在绘制设备(QWidget或QOpenGLWidget)上绘制的QPainter,一个提供要绘制区域信息的QPaintEvent,以及自上次更新绘制设备以来经过的时间(以毫秒为单位)

void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
    painter->fillRect(event->rect(), background);
    painter->translate(100, 100);
/*
*在平移坐标系的原点之前,我们通过填充绘制事件中包含的区域来开始绘制,以便将其余的绘制操作移向绘制设备的中心。
*我们绘制了一个圆形的螺旋图案,使用指定的运行时间为它们设置动画,使它们看起来向外移动并围绕坐标系的原点移动:
*/
	painter->save();
    painter->setBrush(circleBrush);
    painter->setPen(circlePen);
    painter->rotate(elapsed * 0.030);

    qreal r = elapsed / 1000.0;
    int n = 30;
    for (int i = 0; i < n; ++i) {
        painter->rotate(30);
        qreal factor = (i + r) / n;
        qreal radius = 0 + 120.0 * factor;
        qreal circleRadius = 1 + factor * 20;
        painter->drawEllipse(QRectF(radius, -circleRadius,circleRadius * 2, circleRadius * 2));
    }
    painter->restore();
/*
*由于坐标系在这个过程中旋转了很多次,我们事先save() QPainter的状态,然后restore()。
*/
	painter->setPen(textPen);
    painter->setFont(textFont);
    painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter, QStringLiteral("Qt"));
/*
*我们在原点绘制一些文本来完成效果。
*/

Widget类定义

Widget类提供了一个基本的自定义小部件,用于显示Helper类绘制的简单动画

class Helper;

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(Helper *helper, QWidget *parent);

public slots:
    void animate();

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    Helper *helper;
    int elapsed;
};

除了构造函数之外,它只包含一个paintEvent()函数,该函数允许我们绘制自定义内容,以及一个用于为其内容设置动画的槽。一个成员变量跟踪小部件用来绘制其内容的Helper,另一个记录自上次更新以来所用的时间。

Widget类实现

构造函数只初始化成员变量,存储提供的Helper对象并调用基类的构造函数,并强制小部件的固定大小:

Widget::Widget(Helper *helper, QWidget *parent)
    : QWidget(parent), helper(helper)
{
    elapsed = 0;
    setFixedSize(200, 200);
}

每当我们稍后定义的计时器超时时,就会调用animate()槽:

void Widget::animate()
{
    elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
    update();
}

在这里,我们确定自计时器上次超时以来所经过的时间间隔,并在重新绘制小部件之前将其添加到任何现有值中。由于Helper类中使用的动画每秒循环一次,因此我们可以使用模运算符来确保经过的变量始终小于1000。
由于Helper类完成了所有实际绘制,我们只需要实现一个绘制事件,该事件为小部件设置一个QPainter并调用Helper的paint()函数:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    helper->paint(&painter, event, elapsed);
    painter.end();
}

GLWidget类定义

GLWidget类的定义与Widget类基本相同,只是它是从QOpenGLWidget派生的。

class Helper;

class GLWidget : public QOpenGLWidget
{
    Q_OBJECT

public:
    GLWidget(Helper *helper, QWidget *parent);

public slots:
    void animate();

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    Helper *helper;
    int elapsed;
};

同样,成员变量记录用于绘制小部件的Helper以及自上次更新以来经过的时间。

GLWidget类实现

构造函数与Widget类的构造函数略有不同:

GLWidget::GLWidget(Helper *helper, QWidget *parent)
    : QOpenGLWidget(parent), helper(helper)
{
    elapsed = 0;
    setFixedSize(200, 200);
    setAutoFillBackground(false);// 多了这个设置
}

除了初始化逝去的成员变量和存储用于绘制widget的Helper对象外,还使用指定QGL::SampleBuffers标志的格式调用基类的构造函数。如果系统的OpenGL驱动程序支持,则可以启用抗锯齿功能。
animate()插槽与Widget类提供的插槽完全相同:

void GLWidget::animate()
{
    elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
    update();
}

paintEvent()与Widget类中的几乎相同:

void GLWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    helper->paint(&painter, event, elapsed);
    painter.end();
}

由于如果可用,将启用抗锯齿,我们只需要在小部件上设置一个QPainter,并调用助手的paint()函数来显示小部件的内容。

Window 类定义

Window类有一个基本的、最小的定义:

class Window : public QWidget
{
    Q_OBJECT

public:
    Window();

private:
    Helper helper;
};

它包含一个将在所有widgets之间共享的Helper对象。

Window 类实现

构造函数完成所有的工作,创建每种类型的widget ,并将它们与标签一起插入到布局中:

Window::Window()
{
    setWindowTitle(tr("2D Painting on Native and OpenGL Widgets"));

    Widget *native = new Widget(&helper, this);
    GLWidget *openGL = new GLWidget(&helper, this);
    QLabel *nativeLabel = new QLabel(tr("Native"));
    nativeLabel->setAlignment(Qt::AlignHCenter);
    QLabel *openGLLabel = new QLabel(tr("OpenGL"));
    openGLLabel->setAlignment(Qt::AlignHCenter);

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(native, 0, 0);
    layout->addWidget(openGL, 0, 1);
    layout->addWidget(nativeLabel, 1, 0);
    layout->addWidget(openGLLabel, 1, 1);
    setLayout(layout);

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, native, &Widget::animate);
    connect(timer, &QTimer::timeout, openGL, &GLWidget::animate);
    timer->start(50);
}

一个超时50毫秒的计时器是为动画目的而构建的,并连接到Widget和GLWidget对象的animate()插槽。一旦启动,小部件应该以每秒20帧左右的速度更新。

运行示例

该示例显示了在Widget和GLWidget中同时执行的相同绘制操作。GLWidget中渲染的质量和速度取决于系统的OpenGL驱动程序对多采样和硬件加速的支持程度。如果缺乏对其中任何一个的支持,驱动程序可能会依赖于软件渲染器,该软件渲染器可能会以质量换取速度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《利息理论》指导 TCP 拥塞控制

欧文费雪《利息原理》第 10 章&#xff0c;第 11 章对利息的几何说明是普适的&#xff0c;任何一个负反馈系统都能引申出新结论。给出原书图示&#xff0c;本文依据于此&#xff0c;详情参考原书&#xff1a; 将 burst 看作借贷是合理的&#xff0c;它包含成本(报文)&#xf…

代码随想录算法训练营第三十五天丨 贪心算法part06

738.单调递增的数字 思路 暴力解法 题意很简单&#xff0c;那么首先想的就是暴力解法了【超时】。 贪心算法 题目要求小于等于N的最大单调递增的整数&#xff0c;那么拿一个两位的数字来举例。 例如&#xff1a;98&#xff0c;一旦出现strNum[i - 1] > strNum[i]的情况…

通过Vue自带服务器实现Ajax请求跨域(vue-cli)

通过Vue自带服务器实现Ajax请求跨域&#xff08;vue-cli&#xff09; 跨域 原理&#xff1a;从A页面访问到B页面&#xff0c;并且要获取到B页面上的数据&#xff0c;而两个页面所在的端口、协议和域名中哪怕有一个不对等&#xff0c;那么这种行为就叫跨域。注意&#xff1a;类…

大厂面试题-Java并发编程基础篇(二)

目录 一、wait和notify这个为什么要在synchronized代码块中&#xff1f; 二、ThreadLocal是什么&#xff1f;它的实现原理呢&#xff1f; 三、基于数组的阻塞队列ArrayBlockingQueue原理 四、怎么理解线程安全&#xff1f; 五、请简述一下伪共享的概念以及如何避免 六、什…

【Qt之控件QKeySequenceEdit】分析及使用

描述 QKeySequenceEdit小部件允许输入一个QKeySequence。 该小部件允许用户选择一个QKeySequence&#xff0c;通常用作快捷键。当小部件获取焦点时&#xff0c;录制将开始&#xff0c;并在用户释放最后一个键后的一秒钟结束。 用户可以使用输入键盘来输入键序列。通过调用get…

迁移学习 - 微调

什么是与训练和微调&#xff1f; 你需要搭建一个网络模型来完成一个特定的图像分类的任务。首先&#xff0c;你需要随机初始化参数&#xff0c;然后开始训练网络&#xff0c;不断调整参数&#xff0c;直到网络的损失越来越小。在训练的过程中&#xff0c;一开始初始化的参数会…

matlab创建矩阵、理解三维矩阵

1.创建矩阵 全0矩阵&#xff1a;a zeros(2,3,4) 全1矩阵&#xff1a;a ones(2,3,4) &#xff01;和python不一样的地方&#xff01;此处相当于创建了4页2行3列的矩阵&#xff0c;而在python里是2页3行4列。 对第1页的第2行第3列元素进行修改&#xff1a;

【中国知名企业高管团队】系列49:VIVO

今天为您介绍蓝绿两厂的蓝厂——VIVO。这两家公司同源于步步高&#xff0c;两家公司除了名字都是四个字以外&#xff0c;其他方面也实在是太像了&#xff0c;就连核心价值观的前两个词都一样&#xff1a;本分、用户导向。 一、VIVO公司简介 和OPPO一样&#xff0c;VIVO也来源…

[微信小程序踩坑]微信小程序editor富文本组件渲染字符串时,内部图片超出大小导致无法正常渲染或回显(数据传输长度为 3458 KB,存在有性能问题!)

坑一&#xff1a;回显问题 富文本组件&#xff1a; <editor id"editor" name"{{name}}" style"font-size: 28rpx;color: #C9CDD4" read-only"{{true}}" placeholder"{{placeholder}}" bind:input"onChange11"…

Java实现大学兼职教师管理系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管理3.3 课程管理模块3.4 授课管理模块3.5 课程考勤模块3.6 课程评价模块3.7 课程成绩模块3.8 可视化图表 四、免责说明 一、摘要 1.1 项目介绍 大学兼职教师管理系统&#xff0c;旨…

汇编运算符和表达式

运算符&#xff1a; 汇编语言由表达式和运算符组成&#xff0c;运算符分为数值运算符和属性运算符。属性运算符面向变量或标号。 数值运算符&#xff1a; 算术运算符&#xff1a; 运算符类型 ✓ ( 正号 ) 、 -( 负号 ) ✓ ( 加 ) 、 -( 减 ) 、 *( 乘 ) 、 /( 除 ) 、 MO…

Linux常用命令——chpasswd命令

在线Linux命令查询工具 chpasswd 批量更新用户口令的工具 补充说明 chpasswd命令是批量更新用户口令的工具&#xff0c;是把一个文件内容重新定向添加到/etc/shadow中。 语法 chpasswd(选项)选项 -e&#xff1a;输入的密码是加密后的密文&#xff1b; -h&#xff1a;显示…

CS224W1.2——图机器学习应用

文章目录 1. 任务分类2. 节点层级任务3. 边层级任务4. 子图层级任务5. 图层级任务 这节我们讲讨论图机器学习的应用。 1. 任务分类 在图机器学习中&#xff0c;我们有不同的任务&#xff1a; 节点层级的任务边层级的任务子图层级任务整张图层级任务&#xff08;图预测&#xf…

应用在温度测量仪领域中的数字温度传感芯片

用于测量温度的仪器。测量仪是测温仪器类型的其中之一。根据所用测温物质的不同和测温范围的不同&#xff0c;有煤油温度计、酒精温度计、水银温度计、气体温度计、电阻温度计、温差电偶温度计、辐射温度计和光测温度计、双金属温度计等。 温度测量仪表按测温方式可分为接触式…

网络协议--TCP连接的建立与终止

18.1 引言 TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前&#xff0c;都必须先在双方之间建立一条连接。本章将详细讨论一个TCP连接是如何建立的以及通信结束后是如何终止的。 这种两端间连接的建立与无连接协议如UDP不同。我们在第11章看到一端使用UDP向另一端发…

selenium (自动化概念 测试环境配置)

什么是自动化测试 自动化测试介绍 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统. 预设条件包括正常和异常&#xff0c;最后评估运行结果。   自动化测试&#xff0c;就是将人为驱动的测试行为转化为机器执行的过程。 【机器 代替 人工】 自动化…

1-径向基(RBF)神经网络PID控制器仿真

1、内容简介 略 1-可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 4、参考论文 略

毅速丨哪些金属材料在3D打印中应用最多

金属3D打印作为一种新兴的制造技术已经在很多领域得到广泛应用&#xff0c;目前金属3D打印应用较多的材料有不锈钢、钛合金、铝合金、钴铬合金、镍基合金、模具钢等&#xff0c;其中不锈钢材料的应用最为常见。 这些金属3D打印材料各有其特点和适用场景&#xff0c;可以根据具体…

nodejs+vue宁夏旅游景点客流量数据分析

然后通过引入混沌算法构建了旅游景点客流量预测的学习样本,最后引入数据挖掘技术对旅游景点客流量预测进行建模, 与粒子群算法优化BP神经网络的,支持向量机的旅游景点客流量预测模型的 目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1…

RTE(Runtime Environment)

RTE&#xff08;Runtime Environment&#xff09;是一个运行时环境&#xff0c;在这个环境里&#xff0c;你可以实现的功能是&#xff1a; 作为一个缓冲buffer给应用层和BSW层的接口&#xff08;例如COM&#xff09;用来存储数据&#xff0c;也就是说定义一个全局变量供上层和下…