QML實現數據可視化

界面樣式

項目開發流程

1.通過QtCreator創建一個Qt Quick插件,插件命名為CarPanMod;

2.通過QtCreator創建一個Qt  Quick Application,命名為QmlPro;

3.在插件CarPanMod中實現條形圖,折線圖和餅狀圖的繪制;

4.在應用程序QmlPro中,添加插件的導入路徑;

5.在應用程序中,通過import CarPanMod 1.0導入Qml文件即可訪問插件中實現的各種圖表.

C++代碼實現

條形圖實現

barchartitem.h

#ifndef BARCHARTITEM_H
#define BARCHARTITEM_H#include <QQuickPaintedItem>
#include <QVector>
#include <QPropertyAnimation>class BarChartItem : public QQuickPaintedItem {Q_OBJECTQ_PROPERTY(QVariantList data READ data WRITE setData NOTIFY dataChanged)Q_PROPERTY(QStringList labels READ labels WRITE setLabels NOTIFY labelsChanged)Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)Q_PROPERTY(QColor barColor READ barColor WRITE setBarColor NOTIFY barColorChanged)public:explicit BarChartItem(QQuickItem *parent = nullptr);void paint(QPainter *painter) override;// 屬性訪問器QVariantList data() const;void setData(const QVariantList &data);QStringList labels() const;void setLabels(const QStringList &labels);QString title() const;void setTitle(const QString &title);QColor barColor() const;void setBarColor(const QColor &color);protected:void hoverMoveEvent(QHoverEvent *event) override;void hoverLeaveEvent(QHoverEvent *event) override;signals:void dataChanged();void labelsChanged();void titleChanged();void barColorChanged();private:struct BarItem {QRectF rect;qreal value;bool highlighted = false;QColor color;};void updateChartLayout();void animateBar(int index, bool highlight);QVariantList m_data = {6324, 6793, 7476, 7892,8734, 9337, 9860, 10485,11230, 12100};QStringList m_labels = {"2014", "2015", "2016", "2017","2018", "2019", "2020", "2021","2022", "2023"};QString m_title = "全國平均房價(元/㎡)";QColor m_barColor = QColor("#3498db");QVector<BarItem> m_bars;int m_hoveredIndex = -1;QPropertyAnimation *m_animation;
};#endif // BARCHARTITEM_H

barchartitem.cpp

#include "barchartitem.h"#include <QPainter>
#include <QFontMetrics>BarChartItem::BarChartItem(QQuickItem *parent): QQuickPaintedItem(parent), m_animation(new QPropertyAnimation(this)) {setAcceptHoverEvents(true);setFlag(ItemHasContents, true);setAntialiasing(true);m_animation->setPropertyName("barColor");m_animation->setDuration(300);
}void BarChartItem::paint(QPainter *painter) {painter->setRenderHint(QPainter::Antialiasing);// 繪制背景
//    painter->fillRect(boundingRect(), QColor("#f5f5f5"));painter->fillRect(boundingRect(),QColor("transparent"));// 計算布局updateChartLayout();// 繪制標題QFont titleFont = painter->font();titleFont.setPointSize(14);titleFont.setBold(true);painter->setFont(titleFont);painter->setPen(Qt::black);painter->drawText(QRectF(0, 10, width(), 30), Qt::AlignCenter, m_title);// 繪制坐標軸const qreal axisMargin = 50;const QLineF xAxis(axisMargin, height() - axisMargin, width() - axisMargin, height() - axisMargin);const QLineF yAxis(axisMargin, axisMargin, axisMargin, height() - axisMargin);painter->setPen(QPen(Qt::black, 2));painter->drawLine(xAxis);painter->drawLine(yAxis);// 繪制刻度QFont tickFont = painter->font();tickFont.setPointSize(8);painter->setFont(tickFont);// Y軸刻度qreal maxValue = 0;for (const auto &v : m_data) {maxValue = qMax(maxValue, v.toReal());}const int yTicks = 5;for (int i = 0; i <= yTicks; ++i) {qreal y = yAxis.y1() - (yAxis.length() / yTicks) * i;qreal value = maxValue / yTicks * i;painter->drawLine(QPointF(yAxis.x1() - 5, y), QPointF(yAxis.x1(), y));painter->drawText(QRectF(0, y - 10, yAxis.x1() - 10, 20),Qt::AlignRight | Qt::AlignVCenter,QString::number(value, 'f', 0));}// 繪制條形for (int i = 0; i < m_bars.size(); ++i) {const BarItem &bar = m_bars[i];QColor color = bar.highlighted ? bar.color.lighter(130) : bar.color;// 條形陰影painter->setPen(Qt::NoPen);painter->setBrush(QColor(0, 0, 0, 50));painter->drawRect(bar.rect.adjusted(3, 3, 3, 3));// 條形主體painter->setBrush(color);painter->setPen(QPen(Qt::white, 1));painter->drawRect(bar.rect);// 數值標簽painter->setPen(Qt::black);painter->drawText(QRectF(bar.rect.x(), bar.rect.y() - 25,bar.rect.width(), 20),Qt::AlignCenter,QString::number(bar.value, 'f', 0));// X軸標簽if (i < m_labels.size()) {painter->drawText(QRectF(bar.rect.x(), height() - axisMargin + 5,bar.rect.width(), 20),Qt::AlignCenter, m_labels[i]);}}#if 0// 繪制圖例if (!m_labels.isEmpty()) {QRectF legendRect(width() - 150, 40, 140, 30);painter->setBrush(m_barColor);painter->drawRect(legendRect.adjusted(0, 0, -110, 0));painter->drawText(legendRect, Qt::AlignRight | Qt::AlignVCenter, "房價趨勢");}
#endif
}QVariantList BarChartItem::data() const
{return  m_data;
}void BarChartItem::setData(const QVariantList &data)
{if(m_data != data){m_data = data;update();emit dataChanged();}
}QStringList BarChartItem::labels() const
{return m_labels;
}void BarChartItem::setLabels(const QStringList &labels)
{if (m_labels != labels) {m_labels = labels;update();emit labelsChanged();}
}QString BarChartItem::title() const
{return m_title;
}void BarChartItem::setTitle(const QString &title)
{if(m_title != title){m_title = title;update();emit titleChanged();}
}QColor BarChartItem::barColor() const
{return m_barColor;
}void BarChartItem::setBarColor(const QColor &color)
{if(m_barColor != color){m_barColor = color;update();emit barColorChanged();}
}void BarChartItem::updateChartLayout() {if (m_data.isEmpty()) return;const qreal axisMargin = 50;const qreal chartWidth = width() - axisMargin * 2;const qreal chartHeight = height() - axisMargin * 2;const qreal barSpacing = 10;const qreal barWidth = (chartWidth - barSpacing * (m_data.size() - 1)) / m_data.size();qreal maxValue = 0;for (const auto &v : m_data) {maxValue = qMax(maxValue, v.toReal());}m_bars.resize(m_data.size());for (int i = 0; i < m_data.size(); ++i) {qreal value = m_data[i].toReal();qreal barHeight = (value / maxValue) * chartHeight;m_bars[i].rect = QRectF(axisMargin + i * (barWidth + barSpacing),height() - axisMargin - barHeight,barWidth,barHeight);m_bars[i].value = value;m_bars[i].color = m_barColor;m_bars[i].highlighted = (i == m_hoveredIndex);}
}void BarChartItem::animateBar(int index, bool highlight) {if (index < 0 || index >= m_bars.size()) return;m_animation->setStartValue(m_bars[index].color);m_animation->setEndValue(highlight ? m_barColor.lighter(130) : m_barColor);m_animation->setDuration(1000);m_animation->start();
}void BarChartItem::hoverMoveEvent(QHoverEvent *event) {const QPointF pos = event->pos();for (int i = 0; i < m_bars.size(); ++i) {if (m_bars[i].rect.contains(pos)) {if (m_hoveredIndex != i) {m_hoveredIndex = i;
//                animateBar(i, true);update();}return;}}if (m_hoveredIndex != -1) {m_hoveredIndex = -1;update();}
}void BarChartItem::hoverLeaveEvent(QHoverEvent *) {if (m_hoveredIndex != -1) {
//        animateBar(m_hoveredIndex, false);m_hoveredIndex = -1;update();}
}

折線圖實現

linechartitem.h

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919083.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919083.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919083.shtml

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

相關文章

實時計算 記錄

《大數據架構師》海量實時廣告流平臺架構設計與實踐 《架構師必備技能之集群資源評估.pdf》 參考&#xff1a; 大型廣告系統架構與實現 架構圖

gitee_流水線搭配 Dockerfile 部署vue項目

使用 gitee流水線搭配docker,編寫Dockerfile文件進行自動部署Vue項目 gitee流水線 基本配置跟另外一篇文章中類似 gitee_配置自動部署vue項目-CSDN博客 需要修改的只是腳本執行 # 構建階段腳本echo 清理舊文件 rm -rf dist echo 配置 Git 參數 git config --global http.pos…

Win10快速安裝.NET3.5

按Windows鍵輸入CONTROL打開“控制面板”點擊“程序”點擊“啟用或關閉Windows功能”勾選“.NET Framework3.5&#xff08;包括.NET2.0和3.0&#xff09;”點擊確定隨后選擇從更新下載&#xff08;具體提示忘記了&#xff09;&#xff0c;之后windows會自動安裝

Docker Compose 入門教程

一、Docker Compose 簡介 Docker Compose 是 Docker 官方提供的多容器編排工具&#xff0c;通過 YAML 文件&#xff08;docker-compose.yml&#xff09;定義應用程序的服務、網絡和卷&#xff0c;實現一鍵式容器管理。其核心優勢包括&#xff1a; 簡化多容器管理&#xff1a;通…

Tomcat架構深度解析:從Server到Servlet的全流程揭秘

第一章&#xff1a;Tomcat架構概述1.1 Tomcat的角色與定位&#xff1a;Web服務器 vs Servlet容器Tomcat 是什么&#xff1f;它既是一種輕量級 Web 服務器&#xff0c;也是一種符合 Java EE 規范的 Servlet 容器。Web服務器&#xff1a;類似 Nginx、Apache HTTP Server&#xff…

【Java web】HTTP 協議詳解

一、什么是 HTTP&#xff1f;—— 互聯網的 "快遞員"你有沒有想過&#xff0c;當你在瀏覽器輸入www.baidu.com并按下回車時&#xff0c;背后發生了什么&#xff1f;為什么幾秒鐘后就能看到百度首頁&#xff1f;這一切的背后&#xff0c;都離不開一個叫HTTP的 "快…

流式數據服務端怎么傳給前端,前端怎么接收?

01 引言 大模型時代&#xff0c;尤其會話模型為了提高用戶的使用體驗&#xff0c;它不會將所有的數據加載完成一次響應給客戶端&#xff0c;而是通過數據流&#xff0c;一點點的將數據慢慢呈現出來。 正是這種有趣的交互方式一次次將SSE&#xff08;Server Sent Event&#x…

ML307C 4G通信板:工業級DTU固件,多協議支持,智能配置管理

產品概述 ML307C 4G通信板是一款基于中移物聯網ML307C模組的工業級DTU&#xff08;數據傳輸單元&#xff09;產品&#xff0c;專為工業物聯網應用設計。我們的固件支持多種工業協議&#xff0c;具備遠程配置、FOTA升級、數據加密等企業級功能&#xff0c;為您的工業設備提供穩定…

Sublime配置verilog開發環境-具備語法高亮、代碼補全、自定義代碼段及語法檢查等功能,提升FPGA開發效率!

對于在學習FPGA開發之前使用過其他集成開發工具如VS、pycharm、keil或編輯工具如Sublime、VScode、Notepad的朋友&#xff0c;在使用Vivado時可能會像博主一樣感覺自帶編輯器用起來不太舒服&#xff0c;比如不支持語法高亮顯示&#xff0c;不支持代碼自動補全等功能。因次&…

18_基于深度學習的煙霧檢測識別系統(yolo11、yolov8、yolov5+UI界面+Python項目源碼+模型+標注好的數據集)

目錄 項目介紹&#x1f3af; 功能展示&#x1f31f; 一、環境安裝&#x1f386; 環境配置說明&#x1f4d8; 安裝指南說明&#x1f3a5; 環境安裝教學視頻 &#x1f31f; 二、數據集介紹&#x1f31f; 三、系統環境&#xff08;框架/依賴庫&#xff09;說明&#x1f9f1; 系統環…

【計算機網絡架構】混合型架構簡介

引言在當今數字化浪潮席卷全球的背景下&#xff0c;網絡技術正以前所未有的速度迅猛發展&#xff0c;各種網絡架構如雨后春筍般涌現。從早期簡單的總線型、星型架構&#xff0c;到后來的環型、樹型架構&#xff0c;再到如今復雜的網狀型、云計算架構等&#xff0c;每一種架構都…

Hexo 雙分支部署指南:從原理到 Netlify 實戰

Hexo 雙分支部署指南&#xff1a;從原理到 Netlify 實戰 在 Hexo 博客部署中&#xff0c;很多人會困惑于hexo d自動部署與 GitHub 手動提交的區別&#xff0c;以及如何通過雙分支結構優雅地部署到 Netlify。本文將清晰拆解兩種部署方式的核心差異&#xff0c;并手把手教你用雙分…

【數據結構】深入理解單鏈表與通訊錄項目實現

文章目錄一、單鏈表的概念及結構1.1 什么是單鏈表&#xff1f;1.2 節點的組成1.3 單鏈表的特點二、單鏈表的實現2.1 類型定義2.2 基礎工具函數1. 鏈表打印函數2. 節點創建函數2.3 單鏈表的核心操作&#xff08;1&#xff09;插入操作1. 尾插&#xff08;SLTPushBack&#xff09…

《Python學習之字典(一):基礎操作與核心用法》

堅持用 清晰易懂的圖解 代碼語言&#xff0c;讓每個知識點變得簡單&#xff01; &#x1f680;呆頭個人主頁詳情 &#x1f331; 呆頭個人Gitee代碼倉庫 &#x1f4cc; 呆頭詳細專欄系列 座右銘&#xff1a; “不患無位&#xff0c;患所以立。” Python學習之字典&#xff08;…

[安洵杯 2019]Attack

BUUCTF在線評測BUUCTF 是一個 CTF 競賽和訓練平臺&#xff0c;為各位 CTF 選手提供真實賽題在線復現等服務。https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]Attack流量分析題&#xff0c;瀏覽的時候發現攻擊者上傳信息頁面&#xff0c; 直接搜索 flag 就…

復合機器人食品分揀生產線:一體化控制系統引領高效柔性新食代

在食品工業高速發展的今天&#xff0c;面對種類繁多、形態各異的原料分揀需求&#xff0c;以及日益嚴格的衛生安全與效率要求&#xff0c;傳統的固定式分揀設備已難以勝任。復合機器人食品分揀生產線憑借其融合移動&#xff08;AMR&#xff09;與操作&#xff08;機械臂&#x…

二十七、動態SQL

動態SQL介紹動態SQL&#xff1a;if與where標簽動態案例-動態更新EmpMapper&#xff08;接口&#xff09;中對應代碼塊 //動態更新員工public void update2(Emp emp);EmpMapper.xml中對應代碼塊 <!-- 動態更新員工--><update id"update2">update emp<s…

AI可行性分析:數據×算法×反饋=成功

3.1 從場景到AI可行性分析:需求拆解為“數據+算法+反饋” 核心公式: AI可行性 = 數據可獲得性 算法適配性 反饋閉環性 (任一要素為0則需求不可行) 一、傳統需求 vs AI需求本質差異 需求文檔對比(電商案例) 維度 傳統需求文檔(購物車功能) AI需求文檔(商品推薦系…

【圖論】分層圖 / 拆點

大多數都是同一個套路&#xff0c;將圖拆開成幾個圖&#xff0c;每一層都對應著一個不同的狀態&#xff0c;比如把到點 i 的狀態拆成經過了 j 次操作所得的 xx 結果&#xff0c;一般數據不會很大 目前遇到的可分為 3 類&#xff1a; ①.給你最多 k 次操作&#xff0c;求 xx 結…

VS Code配置MinGW64編譯MATIO庫

VS Code 使用 MinGW64 編譯 C 代碼并配置 MATIO 庫的完整步驟 1. 安裝 MSYS2 下載 MSYS2 訪問 MSYS2 官網下載安裝包&#xff08;選擇 x86_64 版本&#xff09;默認安裝路徑&#xff1a;C:\msys64 更新 MSYS2 包數據庫 打開 MSYS2 MinGW 64-bit&#xff08;注意不是 MSYS&…