Qt实现流动的管道效果代码示例

在现代图形用户界面(GUI)应用程序中,动态效果可以显著增强用户体验。本文将介绍如何使用Qt框架实现一个流动的管道效果。我们将通过自定义QWidget来绘制管道,并使用定时器来实现流动效果。

1. 准备工作

首先,确保你已经安装了Qt开发环境。如果没有,可以从Qt官方网站下载并安装。

2. 创建项目

打开Qt Creator,创建一个新的Qt Widgets应用程序项目。我们将在这个项目中实现流动的管道效果。

3. 自定义QWidget

我们将创建一个自定义的QWidget类来绘制管道并实现流动效果。以下是类的定义和实现:

#include <QWidget>
#include <QPainter>
#include <QTimer>
#include <QPainterPath>class PipeWidget : public QWidget {Q_OBJECTpublic:PipeWidget(QWidget *parent = nullptr);protected:void paintEvent(QPaintEvent *event) override;private slots:void updateOffset();private:int m_offset;void drawPipe(QPainter &painter);
};PipeWidget::PipeWidget(QWidget *parent): QWidget(parent), m_offset(0)
{QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &PipeWidget::updateOffset);timer->start(50); // 每50毫秒更新一次
}void PipeWidget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);drawPipe(painter);
}void PipeWidget::updateOffset()
{m_offset += 5;if (m_offset > width()) {m_offset = 0;}update(); // 重绘窗口
}void PipeWidget::drawPipe(QPainter &painter)
{QPainterPath path;path.moveTo(0, height() / 2);path.cubicTo(width() / 3, height() / 2 - 50, 2 * width() / 3, height() / 2 + 50, width(), height() / 2);QLinearGradient gradient(0, 0, width(), 0);gradient.setColorAt(0, Qt::blue);gradient.setColorAt(1, Qt::green);painter.setBrush(gradient);painter.setPen(Qt::NoPen);for (int i = 0; i < 10; ++i) {painter.save();painter.translate(m_offset - i * width() / 10, 0);painter.drawPath(path);painter.restore();}
}

4. 将自定义QWidget添加到主窗口

在主窗口的UI文件中,添加一个QWidget,并将其提升为我们的自定义QWidget类。具体步骤如下:

  1. 打开主窗口的UI文件。
  2. 添加一个QWidget到主窗口。
  3. 右键点击QWidget,选择“提升为...”。
  4. 在弹出的对话框中,填写提升的类名为PipeWidget,并添加头文件路径。
  5. 点击“添加”,然后点击“提升”。

5. 运行项目

现在,你可以运行项目,看到流动的管道效果。管道会从左到右流动,并且循环往复。

#include <QApplication>int main(int argc, char *argv[]) {QApplication app(argc, argv);HorizontalFlowPipeWidget widget;widget.resize(800, 400);widget.show();return app.exec();
}

上述实现的原理介绍:

translate 方法是 QPainter 类中的一个方法,用于平移(移动)绘图坐标系。通过调用 translate 方法,可以改变绘图的原点位置,从而实现图形的平移效果。

translate 方法的签名如下:

void QPainter::translate(const QPointF &offset);
void QPainter::translate(const QPoint &offset);
void QPainter::translate(qreal dx, qreal dy);

其中,offset 是一个 QPointF 或 QPoint 类型的点,表示平移的偏移量;dx 和 dy 分别表示在 x 轴和 y 轴方向上的平移量。

QPainterPath 是 Qt 框架中的一个类,用于创建和操作复杂的 2D 图形路径。它提供了一种方便的方式来定义和操作各种形状,如线条、曲线、矩形、椭圆等。QPainterPath 可以包含多个子路径,每个子路径可以是一个简单的形状或一个复杂的图形。

QPainterPath 的主要用途包括:

  1. 绘制复杂图形:通过组合多个基本形状和路径,可以创建复杂的图形。
  2. 路径操作:可以对路径进行平移、旋转、缩放等变换操作。
  3. 填充和描边:可以对路径进行填充和描边,使用不同的画笔和画刷样式。
  4. 剪裁:可以将路径用作剪裁区域,限制绘图操作的范围。

以下是一些 QPainterPath 的常见用法示例:

QPainterPath path;// 添加一个矩形
path.addRect(10, 10, 80, 50);// 添加一个椭圆
path.addEllipse(100, 10, 80, 50);// 添加一个贝塞尔曲线
path.moveTo(200, 30);
path.cubicTo(250, 10, 300, 50, 350, 30);// 使用 QPainter 绘制路径
QPainter painter(this);
painter.setPen(Qt::blue);
painter.setBrush(Qt::green);
painter.drawPath(path);

通过这些方法,你可以创建复杂的图形路径,并在 Qt 应用程序中进行绘制和操作。

使用 QLinearGradient 绘制了一个从左上角到右下角的线性渐变效果。渐变的颜色从红色过渡到绿色,再过渡到蓝色。通过调整 setColorAt 方法的参数,可以控制渐变过程中不同位置的颜色。

QLinearGradient 是 Qt 框架中的一个类,用于创建线性渐变效果。线性渐变是指颜色从一个点线性地过渡到另一个点。QLinearGradient 可以用于填充图形、控件背景等,以实现平滑的颜色过渡效果。

QLinearGradient 的主要构造函数如下:

QLinearGradient(const QPointF &start, const QPointF &finalStop);

其中,start 是渐变的起始点,finalStop 是渐变的结束点。你可以通过调用 setColorAt 方法来设置渐变过程中不同位置的颜色。

使用 QPainterPath 绘制了一条水平曲线。通过使用 QTimer 定时更新偏移量 m_offset,我们可以实现水平流动的效果。每次定时器触发时,偏移量会增加,然后调用 update() 函数重绘窗口,从而实现水平流动的视觉效果。

cubicTo 方法用于绘制三次贝塞尔曲线。三次贝塞尔曲线由四个点定义:起始点、两个控制点和结束点。cubicTo 方法的签名如下:

void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint);

其中,c1 和 c2 是两个控制点,endPoint 是结束点。通过调整这些点的位置,可以控制曲线的形状。

6. 进一步完善

上述代码示例中,显示的动态曲线为贝塞尔曲线,在流动管道中,我们可能想要的是如三角形状的箭头符号。且管道的方向可能有上下左右四个方向,实现的方法是不一样的。可以自定义实现个Widget,继承自QLabel。

在界面上使用时,可以将 QLabel 提升为自定义的 QWidget。在 Qt 中,提升(Promotion)是一种机制,允许你将一个标准的 Qt 控件(如 QLabel)提升为一个自定义的控件(如自定义的 QWidget)。这样,你可以在设计器中使用标准的控件,但在运行时使用自定义的控件。

以上效果的代码实现:

#ifndef PIPEWIDGET_H
#define PIPEWIDGET_H#include <QLabel>
#include <QPainter>
#include <QTimer>
#include <QPainterPath>class PipeWidget : public QLabel
{
public:PipeWidget(QWidget *parent=0);enum Direction {Up,Down,Left,Right};void setDirection(Direction newDirect);void setStart(bool newStart);protected:void paintEvent(QPaintEvent *event) override;private slots:void updateOffset();private:int  m_offset;bool m_start = false;Direction m_direct = Up; // 默认向上void upDirect(QPainter &painter);    //向上void downDirect(QPainter &painter);  //向下void leftDirect(QPainter &painter);  //左向void rightDirect(QPainter &painter); //右向
};#endif // PIPEWIDGET_H

 

#include "pipewidget.h"PipeWidget::PipeWidget(QWidget *parent):QLabel(parent), m_offset(0) {QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &PipeWidget::updateOffset);timer->start(50); // 每50毫秒更新一次
}void PipeWidget::paintEvent(QPaintEvent *event) {Q_UNUSED(event);if(m_start){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);//m_direct = 1;switch (m_direct) {case Up: upDirect(painter);break;case Down: downDirect(painter);break;case Left: leftDirect(painter);break;case Right: rightDirect(painter);break;default:break;}}
}void PipeWidget::updateOffset() {switch (m_direct) {case Up:{//上m_offset -= 5;if (m_offset < 0) {m_offset = height() / 2;}}break;case Down:{//下m_offset += 5;if (m_offset > (height() / 2)) {m_offset = 0;}}break;case Left:{//左m_offset -= 5;if (m_offset < 0) {m_offset = width() / 2;}}break;case Right:{//右m_offset += 5;if (m_offset > (width() / 2)) {m_offset = 0;}}break;default:break;}update();
}void PipeWidget::setStart(bool newStart)
{m_start = newStart;
}void PipeWidget::setDirection(Direction newDirect)
{m_direct = newDirect;
}void PipeWidget::upDirect(QPainter &painter)
{QPainterPath path;//朝上的三角形path.moveTo(width() / 2 , height()/2-15); // 三角形顶点path.lineTo(0 , height()/2); // 三角形左下角path.lineTo(width(),height()/2); // 三角形右下角path.closeSubpath(); // 闭合路径QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, Qt::blue);gradient.setColorAt(0, Qt::green);painter.setBrush(gradient);painter.setPen(Qt::NoPen);for (int i = 0; i < 10; ++i) {painter.save();painter.translate(0, m_offset - i *  (height() / 4) );painter.drawPath(path);painter.restore();}
}void PipeWidget::downDirect(QPainter &painter)
{QPainterPath path;//朝下的三角形path.moveTo(width() / 2 , height()/2+15); // 三角形顶点path.lineTo(0 , height()/2); // 三角形左下角path.lineTo(width(),height()/2); // 三角形右下角path.closeSubpath(); // 闭合路径QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, Qt::blue);gradient.setColorAt(0, Qt::green);painter.setBrush(gradient);painter.setPen(Qt::NoPen);for (int i = 0; i < 10; ++i) {painter.save();painter.translate(0, m_offset - i *  (height() / 4) );painter.drawPath(path);painter.restore();}
}void PipeWidget::leftDirect(QPainter &painter)
{QPainterPath path;//贝塞尔曲线//path.moveTo(width() / 2, 0);//path.cubicTo(width() / 2 - 50, height() / 3, width() / 2 + 50, 2 * height() / 3, width() / 2, height());//朝左的三角形path.moveTo(width() / 2 , 0); // 三角形顶点path.lineTo(width() / 2 , height()); // 三角形左下角path.lineTo(width()/2-15,height()/2); // 三角形右下角path.closeSubpath(); // 闭合路径QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, Qt::blue);gradient.setColorAt(0, Qt::green);painter.setBrush(gradient);painter.setPen(Qt::NoPen);for (int i = 0; i < 10; ++i) {painter.save();painter.translate(m_offset - i *  (width() / 4) , 0);painter.drawPath(path);painter.restore();}
}void PipeWidget::rightDirect(QPainter &painter)
{QPainterPath path;//贝塞尔曲线//path.moveTo(width() / 2, 0);//path.cubicTo(width() / 2 - 50, height() / 3, width() / 2 + 50, 2 * height() / 3, width() / 2, height());//朝右的三角形path.moveTo(width() / 2 , 0); // 三角形顶点path.lineTo(width() / 2 , height()); // 三角形左下角path.lineTo(width()/2+15,height()/2); // 三角形右下角path.closeSubpath(); // 闭合路径QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, Qt::blue);gradient.setColorAt(0, Qt::green);painter.setBrush(gradient);painter.setPen(Qt::NoPen);for (int i = 0; i < 10; ++i) {painter.save();//painter.translate(0, 0);//painter.translate(m_offset - i * width() / 2 , 0);painter.translate(m_offset - i *  (width() / 4) , 0);painter.drawPath(path);painter.restore();}
}

使用:

void MainWindow::on_pushButton_clicked()
{//ui->pipe->show();//向左ui->lb_h->setDirection(PipeWidget::Right);ui->lb_h->setStart(true);//向上ui->lb_v->setDirection(PipeWidget::Down);ui->lb_v->setStart(true);
}

 

7. 总结

通过本文的介绍,我们学习了如何使用Qt框架实现一个流动的管道效果。我们创建了一个自定义的QWidget类,并使用定时器和绘图API来实现流动效果。这个示例展示了Qt强大的图形绘制和动画功能,可以用于创建各种动态效果的GUI应用程序。

希望这篇文章对你有所帮助,欢迎进一步探索Qt框架的其他功能和特性。

其他资源

qt 虚线流动效果实现_qt制作 流动 虚线-CSDN博客

 

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

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

相关文章

HMI 的 UI 风格创造奇迹

HMI 的 UI 风格创造奇迹

Laravel5+mycat 报错 “Packets out of order”

背景 近期对负责项目&#xff0c;配置了一套 主从复制的 MySQL 集群 使用了中间件 mycat 但测试发现&#xff0c;替换了原来的数据连接后&#xff0c;会出现 Packets out of order 的报错 同时注意到&#xff0c;有的框架代码中竟然也会失效&#xff0c;比如 controller 类中&…

Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)

上次结束了基础IO&#xff1a;Linux&#xff1a;基础IO&#xff08;三.软硬链接、动态库和静态库、动精态库的制作和加载&#xff09; 文章目录 1.认识进程间通信2.管道2.1匿名管道2.2pipe()函数 —创建匿名管道2.3匿名管道的四种情况2.4管道的特征 3.基于管道的进程池设计4.命…

Vue3学习笔记(n.0)

vue指令之v-for 首先创建自定义组件&#xff08;practice5.vue&#xff09;&#xff1a; <!--* Author: RealRoad1083425287qq.com* Date: 2024-07-05 21:28:45* LastEditors: Mei* LastEditTime: 2024-07-05 21:35:40* FilePath: \Fighting\new_project_0705\my-vue-app\…

重载一元运算符

自增运算符 #include<iostream> using namespace std; class CGirl { public:string name;int ranking;CGirl() { name "zhongge"; ranking 5; }void show() const{ cout << "name : "<<name << " , ranking : " <…

cmake编译源码教程(一)

1、介绍 本次博客介绍使用cmake编译平面点云分割的源代码,其对室内点云以及TLS点云中平面结构进行分割,分割效果如下: 2、编译过程 2.1 源代码下载 首先,下载源代码,如下所示,在该文件夹下新建一个build文件夹,用于后续生成sln工程。 同时,由于该库依赖open…

自动化设备上位机设计 二

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 namespace 自动化上位机设计 {public partial class Form1 : Form{public Form1(){InitializeComponent();timer1.Enabled true;timer1.Tick Timer1_Tick;}private void Timer1_Tick(object? sender, EventArgs e)…

您的私人办公室!-----ONLYOFFICE8.1版本的桌面编辑器测评

随时随地创建并编辑文档&#xff0c;还可就其进行协作 ONLYOFFICE 文档是一款强大的在线编辑器&#xff0c;为您使用的平台提供文本文档、电子表格、演示文稿、表单和 PDF 编辑工具。 网页地址链接&#xff1a; https://www.onlyoffice.com/zh/office-suite.aspxhttps://www…

AJAX-day1:

注&#xff1a;文件布局&#xff1a; 一、AJAX的概念&#xff1a; AJAX是浏览器与服务器进行数据通信的技术 >把数据变活 二、AJAX的使用&#xff1a; 使用axios库&#xff0c;与服务器进行数据通信 基于XMLHttpRequest封装&#xff0c;代码简单 Vue,React项目使用 学习…

哪个品牌的加密软件稳定方便使用?

一、什么是企业加密软件&#xff1f; 企业加密软件是一种用于保护企业内部数据安全的工具。在数字化时代&#xff0c;随着数据量的爆炸式增长&#xff0c;信息安全和隐私保护变得愈发重要。企业加密软件作为保障数据安全的关键工具&#xff0c;受到越来越多用户的青睐。 企业…

昆虫学(书籍学习资料)

包括昆虫分类&#xff08;上下册&#xff09;、昆虫生态大图鉴等书籍资料。

如何使用 SwiftUI 构建 visionOS 应用

文章目录 前言WindowsVolumes沉浸式空间结论 前言 Apple Vision Pro 即将推出&#xff0c;现在是看看 SwiftUI API 的完美时机&#xff0c;这使我们能够将我们的应用程序适应 visionOS 提供的沉浸式世界。苹果表示&#xff0c;构建应用程序的最佳方式是使用 Swift 和 SwiftUI。…

2024年软件测试岗必问的100+个面试题【含答案】

一、基础理论 1、开场介绍 介绍要领&#xff1a;个人基本信息、工作经历、之前所做过的工作及个人专长或者技能优势。扬长避短&#xff0c;一定要口语化&#xff0c;语速适中。沟通好的就多说几句&#xff0c;沟通不好的话就尽量少说两句。举例如下&#xff1a; 面试官你好&…

鸿蒙 HarmonyOs 网络请求 快速入门

官方文档&#xff1a; ArkUI简介-ArkUI&#xff08;方舟UI框架&#xff09;-应用框架 | 华为开发者联盟 (huawei.com) 一、通过原有的http组件进行网络请求&#xff08;方式一&#xff09; 1.1 HttpRequestOptions的操作 名称类型描述methodRequestMethod请求方式&#xff…

12款超良心好用APP推荐,每一款都值得下载!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/分享是奉献的果实&#xff0c;分享是快乐的前提。每天给小伙伴们分享自己认可的软件&#xff0c;也是莫大的幸福&#xff0c;今天获得12款好用的软…

class类和style内联样式的绑定

这里的绑定其实就是v-bind的绑定&#xff0c;如代码所示&#xff0c;div后面的引号就是v-bind绑定&#xff0c;然后大括号将整个对象括起来&#xff0c;对象内先是属性&#xff0c;属性后接的是变量&#xff0c;这个变量是定义在script中的&#xff0c;后通过这个变量&#xff…

flutter:监听路由的变化

问题 当从路由B页面返回路由A页面后&#xff0c;A页面需要进行数据刷新。因此需要监听路由变化 解决 使用RouteObserver进行录音监听 创建全局变量&#xff0c;不在任何类中 final RouteObserver<PageRoute> routeObserver RouteObserver<PageRoute>();在mai…

面试-微服务篇

springcloud组件有哪些&#xff1f; eureka、ribbon负载均衡、feign、hystrix、zuul/gateway网关 nacos、ribbon、feign、sentinel、gateway 服务注册和发现是什么意思&#xff1f;springcloud如何实现服务注册发现&#xff1f; 微服务中必须要使用的组件&#xff0c;考察我们使…

LeetCode刷题记录:(15)三角形最小路径和

知识点&#xff1a;倒叙的动态规划 题目传送 解法一&#xff1a;二维动态规划【容易理解】 class Solution {public int minimumTotal(List<List<Integer>> triangle) {int n triangle.size();if (n 1) {return triangle.get(0).get(0);}// dp[i][j]:走到第i层第…

Java+前后端分离架构+ MySQL8.0.36产科信息管理系统 产科电子病历系统源码

Java前后端分离架构 MySQL8.0.36产科信息管理系统 产科电子病历系统源码 产科信息管理系统—住院管理 数字化产科住院管理是现代医院管理中的重要组成部分&#xff0c;它利用数字化技术优化住院流程&#xff0c;提升医疗服务质量和效率。以下是对数字化产科住院管理的详细阐述…