QML Charts組件之折線圖的鼠標交互

目錄

    • 前言
    • 相關系列
    • 代碼示例詳解(LineSeriesDemo3.qml)
      • 功能概覽
      • 運行效果
      • 代碼說明
    • 工程下載
    • 參考

前言

接上文(QML Charts組件之折線圖的基礎屬性),本文將重點介紹LineSeries的鼠標交互,包括:鼠標拖拽平移、滾輪縮放等操作。


相關系列

  • QML Charts組件之折線圖的基礎屬性
  • QML Charts組件之LineSeries、SplineSeries與ScatterSeries
  • QML Charts組件之坐標軸共有屬性

代碼示例詳解(LineSeriesDemo3.qml)

示例文件:Series/LineSeriesDemo3.qml

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtChartsRectangle {Layout.fillWidth: trueLayout.fillHeight: trueColumnLayout {anchors.fill: parentChartView {id: chartViewtitle: "折線圖示例"titleFont.bold: truetitleFont.pointSize: 14Layout.fillWidth: trueLayout.fillHeight: trueantialiasing: trueValueAxis {id: axis_xmin: 0max: 10tickCount: 11}ValueAxis {id: axis_ymin: 0max: 10tickCount: 11}LineSeries {id: seriesname: "line"color: "#1296FF"width: 3bestFitLineColor : "#00FF00"bestFitLineVisible : true// 設置點是否可見pointsVisible : true// 設置點標簽是否可見pointLabelsVisible : true// 設置點標簽文本顏色pointLabelsColor: "#FF0000"// 設置點標簽字體pointLabelsFont.bold: truepointLabelsFont.pointSize: 12pointLabelsFont.family: "Courier"// 設置點標簽顯示格式// 具體格式可能受Qt版本或平臺影響// 如果數據太多,會影響性能// 格式標簽限制:不支持更復雜的運算或格式化指令,如果是小數,可能需要對點數據預處理pointLabelsFormat : "(@xPoint,@yPoint)"// 控制當點標簽超出繪圖區域時是否被裁剪,默認為true// 設為false可允許標簽顯示在繪圖區域之外,但需要注意可能布局重疊。pointLabelsClipping : trueaxisX: axis_xaxisY: axis_yonClicked: function(point){console.log("onClicked: " + Math.round(point.x) + ", " + Math.round(point.y));}}// 交互:拖拽平移與滾輪縮放property real __panStartX: 0property real __panStartY: 0property real __panStartMinX: 0property real __panStartMaxX: 0property real __panStartMinY: 0property real __panStartMaxY: 0MouseArea {anchors.fill: parentacceptedButtons: Qt.LeftButtonhoverEnabled: truepreventStealing: trueonPressed: function(mouse) {var pa = chartView.plotAreaif (!(mouse.x >= pa.x && mouse.x <= pa.x + pa.width &&mouse.y >= pa.y && mouse.y <= pa.y + pa.height)) {return}chartView.__panStartX = mouse.xchartView.__panStartY = mouse.ychartView.__panStartMinX = axis_x.minchartView.__panStartMaxX = axis_x.maxchartView.__panStartMinY = axis_y.minchartView.__panStartMaxY = axis_y.max}onPositionChanged: function(mouse) {if (!pressed) returnvar pa = chartView.plotAreaif (pa.width <= 0 || pa.height <= 0) returnvar dx = mouse.x - chartView.__panStartXvar dy = mouse.y - chartView.__panStartYvar rangeX = chartView.__panStartMaxX - chartView.__panStartMinXvar rangeY = chartView.__panStartMaxY - chartView.__panStartMinY// 像素 -> 數值映射(注意Y軸方向)var valueDeltaX = -dx * rangeX / pa.widthvar valueDeltaY =  dy * rangeY / pa.heightaxis_x.min = chartView.__panStartMinX + valueDeltaXaxis_x.max = chartView.__panStartMaxX + valueDeltaXaxis_y.min = chartView.__panStartMinY + valueDeltaYaxis_y.max = chartView.__panStartMaxY + valueDeltaY}}WheelHandler {// 以光標為中心縮放,支持鼠標與觸控板acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPadtarget: chartViewonWheel: function(event) {var pa = chartView.plotArea//var pos = event.pointvar x = event.xvar y = event.yif (!(x >= pa.x && x <= pa.x + pa.width &&y >= pa.y && y <= pa.y + pa.height)) {return}// 計算縮放步數(15度/步),向上滾動放大var degrees = event.angleDelta.y / 8.0var steps = degrees / 15.0var factor = Math.pow(1.2, -steps)var minX = axis_x.minvar maxX = axis_x.maxvar minY = axis_y.minvar maxY = axis_y.maxvar rangeX = maxX - minXvar rangeY = maxY - minYif (rangeX <= 0 || rangeY <= 0) returnvar fx = (x - pa.x) / pa.widthvar fy = (y - pa.y) / pa.heightfx = Math.max(0, Math.min(1, fx))fy = Math.max(0, Math.min(1, fy))var newRangeX = rangeX * factorvar newRangeY = rangeY * factor// 以光標數值位置為錨點縮放var newMinX = minX + fx * (rangeX - newRangeX)var newMinY = minY + fy * (rangeY - newRangeY)axis_x.min = newMinXaxis_x.max = newMinX + newRangeXaxis_y.min = newMinYaxis_y.max = newMinY + newRangeYevent.accepted = true}}// Add data dynamically to the seriesComponent.onCompleted: {for (var i = 0; i <= 5; i++) {var num = Math.floor((Math.random()*10))series.append(i, num);}}}Row {Layout.minimumHeight: 50Button {text: "append"width: 100height: 25onClicked: {var num = Math.floor((Math.random()*10))series.append(series.count, num)axis_x.min++;axis_x.max++;}}Button {text: "remove"width: 100height: 25onClicked: {if (series.count > 0) {series.removePoints(series.count-1, 1)axis_x.min--;axis_x.max--;}}}}}
}

功能概覽

這段 QML 代碼實現了一個可交互的折線圖窗口,能夠進行鼠標拖拽平移和滾輪縮放操作。

功能實現方式
顯示折線圖使用ChartViewLineSeries
動態追加 / 刪除數據使用 series.appendseries.removePoints 方法。
鼠標拖拽平移使用MouseArea ,記錄按下/移動坐標。
滾輪縮放使用WheelHandler ,以光標為中心縮放,支持鼠標與觸控板。
point標簽顯示使用pointLabelsFormat : "(@xPoint,@yPoint)", 顯示坐標。
點擊數據點觸發onClicked 信號,打印坐標。

運行效果

請添加圖片描述


代碼說明

折線屬性: 詳細的屬性描述見上文 — QML Charts組件之折線圖的基礎屬性

拖拽平移(鼠標左鍵按住拖圖表):

MouseArea {anchors.fill: parentonPressed:  { /* 記錄初始狀態 */ }onPositionChanged: { /* 根據位移更新軸范圍 */ }
}

1. 按下瞬間干什么?
記住四件事:

  • 鼠標當時在屏幕的 x、y 坐標。
  • 當時 X 軸的最小值、最大值。
  • 當時 Y 軸的最小值、最大值。
    它們一起構成初始快照,后面所有計算都以這個快照為基準,不會累積誤差。

2. 拖動過程中干什么?

  • 把鼠標當前位置跟按下時的位置做減法,得到像素位移 dx、dy。
  • 用 dx 除以繪圖區寬度,得到橫向走了百分之幾;同樣處理 dy。
  • 把百分比乘以當時的軸范圍,就換算成全局坐標該走多少。
  • 右拖 → 畫面要向右,于是把軸整體向左平移相同的量;左拖相反。
  • 下拖 → 畫面要向上,于是把軸整體向下平移;上拖相反。
  • 每移動一次鼠標,就重新給軸的最小、最大值賦一次新結果,圖就實時跟過來了。

簡而言之 鼠標拖拽 是把鼠標像素差按寬高比例變成軸坐標差,然后整體平移軸范圍。


滾輪縮放(以光標為中心放大/縮小):

WheelHandler {onWheel: function(event) {// 計算縮放步數(15度/步),向上滾動放大...// 以光標數值位置為錨點縮放...}
}

1. 什么時候生效?
只在繪圖區內部滾輪才處理,滾到外邊就不管,避免整個窗口一起亂動。

2. 滾一次算幾步?
系統告訴你這次滾了多少度,15° 算一步。向上滾一步算 +1,向下滾一步算 ?1。
把步數代進公式 1.2^(-步數) 得到縮放因子:

  • 向上滾一步 → 因子 ≈ 1.2,表示放大 20%。
  • 向下滾一步 → 因子 ≈ 0.83,表示縮小 17%。

3. 怎樣以光標為中心?

  • 先算出光標在繪圖區里的橫向百分比 fx、縱向百分比 fy。
  • 縮放前后,光標對應的那個數據值必須保持不變。
  • 于是用百分比做插值:
    • 新范圍 = 舊范圍 × 因子。
    • 新最小值 = 舊最小值 + fx × (舊范圍 ? 新范圍)。
    • 這樣光標在舊矩形里占多少比例,在新矩形里還是同樣比例,視覺上就是以光標為錨點放大或縮小。

簡而言之 滾輪縮放 是把滾了幾步變成縮放因子,再用光標位置做插值,重新算軸邊界。


工程下載

Git Code 下載鏈接:QML Charts組件之折線圖的基礎屬性示例

在這里插入圖片描述


參考

  • Qt官方文檔 - LineSeries
  • Qt官方文檔 - XYSeries

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

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

相關文章

二值信號量——學習筆記12

本文是筆者在學習 正點原子官方 的《【正點原子】手把手教你學FreeRTOS實時系統》系列視頻時整理的筆記。 視頻講解清晰透徹&#xff0c;非常感謝UP主的無私奉獻&#xff01;原課程鏈接如下&#xff1a; &#x1f449; B站視頻鏈接&#xff1a;??????【正點原子】手把手教…

裸機開發 時鐘配置,EPIT

1.概念時鐘(clock)&#xff1a;在電子系統中是一個產生穩定、周期性振蕩信號的電路或組件。這個信號像節拍器或心跳一樣&#xff0c;為數字電路中的各種操作提供同步時序基準。PLL&#xff08;phase locked loop&#xff09;鎖相環電路: 倍頻PFD&#xff08;phase fractional P…

Linux-文本三劍客(grep、sed、awk)

Linux-文本三劍客前言一、grep二、sed三、awk模式 -- 正則表達式關系表達式、運算符表達模式匹配表達式動作 輸出流程控制參數傳遞&#xff0c;awk接受外部變量統計數組的使用分組統計練習常用內置函數前言 grep、sed、awk 被稱為 “文本三劍客”&#xff0c;它們是處理文本文…

主流反爬蟲、反作弊防護與風控對抗手段

文章目錄1. 寫在前面2. 指紋檢測3. 行為驗證3. 加固防護4. 鏈路檢測5. 風控埋點6. 游客注冊7. 數據防護8. 賬號權重9. 反調阻斷【&#x1f3e0;作者主頁】&#xff1a;吳秋霖 【&#x1f4bc;作者介紹】&#xff1a;擅長爬蟲與JS加密逆向分析&#xff01;Python領域優質創作者、…

金蝶云星空插件開發記錄(一)

實現目的&#xff1a;新增供應商保存后&#xff0c;觸發釘釘審批流程&#xff0c;并根據釘釘審批結果回寫是否合格供應商。實現思路&#xff1a;通過BOS平臺供在應商管理界面新增兩個復選框字段&#xff1a;是否釘釘審批、是否合格供應商&#xff0c;若在新建供應商檔案時勾選是…

企業跨區域組網新解:SD-WAN技術打造安全穩定網絡體系

前言在數字化浪潮席卷全球的今天&#xff0c;企業跨區域網絡互聯已成為支撐業務發展的關鍵基礎設施。傳統MPLS專線雖性能穩定&#xff0c;但高昂成本和漫長部署周期令眾多企業望而卻步。SD-WAN技術的出現&#xff0c;正以其智能、靈活和成本效益的優勢&#xff0c;重塑企業組網…

Docker 容器化

引言在解釋docker是什么之前&#xff0c;我們首先應該先了解的是容器化的概念。什么是容器&#xff1f;就是一個沙箱&#xff0c;在這個沙箱中涵蓋了特定應用運行的一切依賴的內容。但他不是一個操作系統&#xff0c;且和底層的操作系統是隔離的。什么是容器化&#xff1f;容器…

LeetCode刷題——hot 100(3)

題目1&#xff1a;矩陣置零題目&#xff1a;問題分析&#xff1a;使用兩個布爾數組來分別記錄哪行哪列出現了0&#xff0c;當出現0的行和列&#xff0c;對應的布爾數組值置為true。再次遍歷數組&#xff0c;當出現行數組和列數組中的值為true&#xff0c;則對應的原數組的值置為…

Ajax-day2(圖書管理)-渲染列表

本篇筆記素材來自“黑馬程序員” 渲染列表圖書管理一、獲取數據二、渲染數據完整代碼圖書管理 Bootstrap 框架渲染列表&#xff08;查&#xff09;新增圖書&#xff08;增&#xff09;刪除圖書&#xff08;刪&#xff09;編輯圖書&#xff08;改&#xff09; 自己的圖書數據&a…

MOS管的電路

MOS管的三極都會存在以下三個電容&#xff0c;分別是&#xff1a;Cgs,Cgd,Cds 輸入電容CissCgsCgd 輸出電容CossCgdCds 反向傳輸電容CrssCgd&#xff0c;也叫米勒電容 然而&#xff0c;這三個等效電容是構成串并聯組合關系&#xff0c;他們并不是獨立的&#xff0c;而是相互…

STM32_05_時鐘樹

時鐘 d用來輸入數據&#xff0c;CLK就是我們的時鐘&#xff0c;CPU1s中72000000HZ個時鐘周期STM32的時鐘樹鎖相環HSE時鐘源HSI時鐘源LSE時鐘源LSI時鐘源SystemInit函數SetSysClock函數SetSysClockTo72函數SystemInit()后時鐘頻率大小總結RCC標準庫函數定義變量a&…

C語言---判斷語句

文章目錄1. if 語句2. if...else 語句3. if...else if...else 語句4. switch 語句5. 三元運算符 ( ? : )總結與對比如何選擇C語言中的判斷語句用于根據給定的條件來決定執行哪一段代碼。其核心是條件為真&#xff08;必須&#xff09;則執行一段代碼&#xff0c;條件為假&…

[硬件電路-212]:電流的本質確實是電子的移動

1. 微觀機制&#xff1a;電子的定向漂移與熱運動定向漂移&#xff08;Drift Motion&#xff09;&#xff1a;在導體&#xff08;如金屬&#xff09;中&#xff0c;自由電子&#xff08;價電子&#xff09;受電場驅動&#xff0c;從負端向正端定向移動&#xff0c;形成宏觀電流。…

雙RFSOC47DR-16通道5GSPS ADC采集模塊

16通道5GSPS ADC采集板卡組成如圖1所示。該板卡的輸入接口為SMA單端輸入&#xff0c;ADC采集和處理采用Xilinx公司的XCZU47DR-2FFVE1156I芯片。板卡需配備4路QSFP28光口輸出&#xff0c;并需要集成網口、DDR4、SD卡、USB調試口。兩塊RF-Soc需確保連接通信功能。板卡的16通道需實…

pytest -- 中文文檔

前言 零基礎1小時快速入門pytest自動化測試教程&#xff0c;全套項目框架實戰pytest配置文件可以改變pytest的運行方式&#xff0c;它是一個固定的文件pytest.ini文件&#xff0c;讀取配置信息&#xff0c;按指定的方式去運行 非test文件 pytest里面有些文件是非test文件 pyt…

硬件開發2-ARM裸機開發3-IMX6ULL - 引入中斷

一、鋪墊引入中斷 → 按鍵1、概要&#xff1a;實現按鍵控制發光二極管和蜂鳴器輸入類型的外設&#xff1a;按鍵&#xff08;key&#xff09;2、參考手冊內容完成配置過程&#xff08;1&#xff09;key 按鍵原理圖&#xff08;2&#xff09;core 內核中命名 -- UART1 CTS&#x…

Ansible的 Playbook 模式詳解

目錄一、Playbook模式1.1 Playbook 的優勢1.2 Playbook 的組成1.3 安裝 httpd 服務案例1.4 Playbook 命令及常用參數1.5 Playbook 的語法 —— 權限相關1. remote_user2. become3. become_method1.6 Playbook 的通知與觸發機制1. notify2. handlers3. 使用示例4. 使用場景1.6 P…

猿輔導Java后臺開發面試題及參考答案

int 與 Integer 的區別是什么&#xff1f;若創建數量龐大的數字時使用 Integer&#xff0c;會對重復數字創建新對象嗎&#xff1f;int 是 Java 中的基本數據類型&#xff0c;直接存儲數值&#xff0c;占用 4 個字節&#xff0c;默認值為 0&#xff0c;不需要通過 new 關鍵字創建…

代碼隨想錄學習摘抄day9(回溯1-11)

一個樸實無華的目錄定義&#xff1a;回溯法也可以叫做回溯搜索法&#xff0c;它是一種搜索的方式。應用場景&#xff1a;回溯法解決的問題都可以抽象為樹形結構代碼模板題型第77題. 組合思路&#xff1a;每次從集合中選取元素&#xff0c;可選擇的范圍隨著選擇的進行而收縮&…

Altium Designer(AD24)打開工程文件的幾種方法

??《專欄目錄》 目錄 1,概述 2,源文件 2,菜單欄 4,工具欄 5,注意事項 1,概述 本文介紹幾種打開工程文件的方法。 2,源文件 找到工程的源文件存儲路徑,找到.PrjPcb的源工程文件,雙擊打開。 2,菜單欄 第1步:執行File→Open, 第2步:找到工程文件的存儲路徑,并選中…