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.pswp.cn/web/40295.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40295.shtml
英文地址,請注明出處:http://en.pswp.cn/web/40295.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LeetCode.68文本左右對齊

問題描述 給定一個單詞數組 words 和一個長度 maxWidth &#xff0c;重新排版單詞&#xff0c;使其成為每行恰好有 maxWidth 個字符&#xff0c;且左右兩端對齊的文本。 你應該使用 “貪心算法” 來放置給定的單詞&#xff1b;也就是說&#xff0c;盡可能多地往每行中放置單詞…

HMI 的 UI 風格創造奇跡

HMI 的 UI 風格創造奇跡

Table-driven Declarative Rewrite Rule (DRR)

Table-driven Declarative Rewrite Rule (DRR 好處規則定義原模式基于位置的匹配操作的匹配有向無環圖&#xff08;DAG&#xff09;(AOp (BOp), $attr): 綁定操作的結果 好處 模式創建者只需要聲明性地指定重寫模式&#xff0c;而不必擔心調用具體的C方法。 消除樣板代碼&…

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.命…

基于java將dicom轉化為jpg的幾種方式

參考1 JAVA代碼實現DICOM文件轉換JPG package com.example;import java.awt.image.BufferedImage; import java.io.File;import javax.imageio.ImageIO;import ij.plugin.DICOM;/*** dicom文件java解析&#xff0c;生成圖片* 不過這里不能解析壓縮的dicom文件*/ public class …

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項目使用 學習…

自定義控件繪圖篇(一)基本幾何圖形繪制

在Android開發中&#xff0c;自定義控件是一種強大的技術&#xff0c;它允許開發者創建具有獨特外觀和行為的UI組件。通過自定義控件&#xff0c;你可以實現標準組件庫中沒有的功能和設計。自定義控件通常涉及兩個主要方面&#xff1a;布局和繪圖。本回答將重點介紹如何在自定義…

哪個品牌的加密軟件穩定方便使用?

一、什么是企業加密軟件&#xff1f; 企業加密軟件是一種用于保護企業內部數據安全的工具。在數字化時代&#xff0c;隨著數據量的爆炸式增長&#xff0c;信息安全和隱私保護變得愈發重要。企業加密軟件作為保障數據安全的關鍵工具&#xff0c;受到越來越多用戶的青睞。 企業…

昆蟲學(書籍學習資料)

包括昆蟲分類&#xff08;上下冊&#xff09;、昆蟲生態大圖鑒等書籍資料。

調和均值

文章目錄 調和均值的定義和公式調和均值的幾何解釋調和均值的應用調和均值與算術平均和幾何平均的比較示例 調和均值的定義和公式 調和均值是一種特殊的平均數&#xff0c;適用于處理涉及比率或速度的數據。對于一組正數 x 1 , x 2 , … , x n x_1, x_2, \ldots, x_n x1?,x2…

Java中的AQS

Java中的AbstractQueuedSynchronizer&#xff08;AQS&#xff09;是Java并發框架的核心組件之一&#xff0c;它位于java.util.concurrent.locks包下。AQS為Java的鎖和其他同步工具提供了基礎架構&#xff0c;它使用模板設計模式和一種稱為“CLH鎖”的算法來實現高效的線程同步。…

如何使用 SwiftUI 構建 visionOS 應用

文章目錄 前言WindowsVolumes沉浸式空間結論 前言 Apple Vision Pro 即將推出&#xff0c;現在是看看 SwiftUI API 的完美時機&#xff0c;這使我們能夠將我們的應用程序適應 visionOS 提供的沉浸式世界。蘋果表示&#xff0c;構建應用程序的最佳方式是使用 Swift 和 SwiftUI。…

2024年軟件測試崗必問的100+個面試題【含答案】

一、基礎理論 1、開場介紹 介紹要領&#xff1a;個人基本信息、工作經歷、之前所做過的工作及個人專長或者技能優勢。揚長避短&#xff0c;一定要口語化&#xff0c;語速適中。溝通好的就多說幾句&#xff0c;溝通不好的話就盡量少說兩句。舉例如下&#xff1a; 面試官你好&…

Java中Predicate(謂詞),方法引用,以及正則的一些講解

1.Predicate接口簡述 FunctionalInterface public interface Predicate<T> {boolean test(T t);default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}default Pred…