目录

    • 前言
    • 相关系列
    • 代码示例详解(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步:找到工程文件的存储路径,并选中…