news 2026/9/5 15:04:38

QPainter 绘制坐标轴,数据散点,连线,可拖动

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QPainter 绘制坐标轴,数据散点,连线,可拖动

最开始使用 qchart 实现项目要求 qchart不知道怎么实现XY轴上面的箭头 囧

后面 轴上面显示的单位 移动不到 箭头附近 而且数据点需要散点类,也需要连线,数据list也有标题,数据多 一点管理太麻烦,数据拖动弄的一团糟。

整了几天 还有一些细节还是不知道怎么设置,查来查去 都是一些基础的东西

还是太菜了,学无止境!

后面等不起 用qpainter 实现 需要的功能 类似 qchart

这是demo

主要代码:

数据list使用结构体

struct paint_point_struct { bool is_paint_data_title; // 是否绘制数据标题 QString title; // 数据标题 QList<QPointF>data_list; // 绘图数据 bool is_draw_line; // 是否将数据点用线连接 Qt::PenStyle ps; // 线类型 bool is_draw_point; // 数据点是否绘制为圆点 int point_marker_size; // 圆点大小 paint_point_struct() { is_paint_data_title = true; // 默认绘制数据标题 title.clear(); is_draw_line = true; // 默认数据点用线连接 data_list.clear(); ps = Qt::SolidLine; // 默认是实线 //ps = Qt::DotLine; // 默认是虚线 is_draw_point = true; // 默认数据点绘制为圆点 point_marker_size = 5; // 圆点大小默认为5 } };
/* 绘制标题 */ void mychart::paint_title(QPainter *painter) { if(title_string.isEmpty()) { title_height = 0; return; } ResetDefaultCoordinate(painter); painter->setFont(*title_font); int width = this->width() / 2; // int height = this->height(); QFontMetrics fm(*title_font); int axis_x_string_width = fm.width(title_string); int axis_x_string_heigh = fm.height(); // X轴字符的高度 int rect_y = 0 + 5; title_height = rect_y + axis_x_string_heigh + 5; if(coordinate_dir) { rect_y = 0; title_height = 0; } QRectF rect(width - axis_x_string_width / 2, rect_y, axis_x_string_width, axis_x_string_heigh); painter->drawText(rect,title_string); title_height = rect_y + axis_x_string_heigh + 5; }
/* 绘制数据点 */ void mychart::paint_points(QPainter *painter) // 绘制数据点 { for(int i = 0;i < paint_point_list.length();i++) { if(coordinate_dir) SetMathCoordinate(painter); else ResetDefaultCoordinate(painter); // 左上角 QPointF point_end; for(int j = 0;j < paint_point_list.at(i).data_list.length();j++) { QPointF point_at_list = paint_point_list.at(i).data_list.at(j); QPointF point; point.setX(m_ptStartPos.x() + (point_at_list.x() - axis_x_range.x()) * m_axisWidth / (axis_x_range.y() - axis_x_range.x())); point.setY(m_ptStartPos.y() + (point_at_list.y() - axis_y_range.x()) * m_axisHeight / (axis_y_range.y() - axis_y_range.x())); if(paint_point_list.at(i).is_draw_point) painter->drawEllipse(point,paint_point_list.at(i).point_marker_size,paint_point_list.at(i).point_marker_size); if(paint_point_list.at(i).is_draw_line) // 数据点用线连接 { if(j != 0) { QPen pen; pen.setStyle(paint_point_list.at(i).ps); painter->setPen(pen); painter->drawLine(point, point_end);// 绘制数据连接线(折线) } point_end = point; } } /* 绘制数据标题 */ if(paint_point_list.at(i).is_paint_data_title && !paint_point_list.at(i).title.isEmpty()) { ResetDefaultCoordinate(painter); // 左上角 QFont font("SimSun", 16, 50); painter->setFont(font); /* 确定字符的长宽 */ QFontMetrics fm(font); int axis_x_string_width = fm.width(paint_point_list.at(i).title); int axis_x_string_heigh = fm.height(); // X轴字符的高度 int rect_x = point_end.x() + paint_point_list.at(i).point_marker_size + 10; int rect_y = (point_end.y() - axis_x_string_heigh / 2); if(coordinate_dir) rect_y = this->height() - rect_y - axis_x_string_heigh; QRectF rect(rect_x, rect_y, axis_x_string_width, axis_x_string_heigh); painter->drawText(rect,paint_point_list.at(i).title); } } }

坐标轴刻度可能是其他乱七八糟的字符

/* 绘制刻度文本 */ void mychart::paint_coordinate_scale_text(QPainter *painter) { ResetDefaultCoordinate(painter); painter->setFont(*text_font); /* 确定字符的长宽 */ QFontMetrics fm(*text_font); int axis_x_string_width = fm.width("0"); int axis_x_string_heigh = fm.height(); // X轴字符的高度 for(int i = 0;i < axis_y_count;i++) { /* 确定Y轴上的字符最大宽度 */ QString y_string = (y_scale_string_list.isEmpty())? QString::number((axis_y_range.y() - axis_y_range.x()) / (axis_y_count - 1) * i,'f',2): y_scale_string_list.at(i); int string_width = fm.width(y_string); axis_x_string_width = (string_width > axis_x_string_width)?string_width:axis_x_string_width; } QPoint axisStartPoint; // 刻度线坐标 int string_scale_base = 0; // 第一个刻度文本结束点坐标(根据刻度范围动态显示刻度文本,防止文本全部叠在一起) /* 画X刻度文本标识 */ int count = (!x_scale_list.isEmpty())?x_scale_list.length():axis_x_count; for(int i = count - 1;i >= 0;i--) // 从最后一个刻度文本开始,优先绘制最大刻度文本 { qreal x = m_ptStartPos.x() + m_axisWidth / (count - 1) * i; if(!x_scale_list.isEmpty()) x = m_ptStartPos.x() + (x_scale_list.at(i) - x_scale_list.at(0)) * m_axisWidth / (x_scale_list.last() - x_scale_list.at(0)); axisStartPoint.setX(x); axisStartPoint.setY(m_ptStartPos.y()); QString scale_str = (x_scale_string_list.isEmpty())? QString::number((axis_x_range.y() - axis_x_range.x()) / (count - 1) * i,'f',0): x_scale_string_list.at(i); axis_x_string_width = fm.width(scale_str); axis_x_string_heigh = fm.height(); // X轴字符的高度 int rect_y = axisStartPoint.y() - scale_value - axis_x_string_heigh; if(coordinate_dir) rect_y = this->height() - rect_y - axis_x_string_heigh; QRectF rect(axisStartPoint.x() - axis_x_string_width / 2, rect_y, axis_x_string_width, axis_x_string_heigh); if(scale_str.isEmpty())continue; if(i == count - 1) // 从最后一个刻度文本开始 { string_scale_base = axisStartPoint.x() - axis_x_string_width / 2; // 计算文本起点X坐标 } if((axisStartPoint.x() + axis_x_string_width / 2 > string_scale_base) && (i < count - 1)) { continue; // 文本重叠 } else { string_scale_base = axisStartPoint.x() - axis_x_string_width / 2; } painter->drawText(rect,scale_str); } /* 画Y刻度文本标识 */ count = (!y_scale_string_list.isEmpty())?y_scale_string_list.length():axis_y_count; for(int i = count - 1;i >= 0;i--) { qreal y = m_ptStartPos.y() + m_axisHeight / (count - 1) * i; if(!y_scale_list.isEmpty()) y = m_ptStartPos.y() + (y_scale_list.at(i) - y_scale_list.at(0)) * m_axisHeight / (y_scale_list.last() - y_scale_list.at(0)); axisStartPoint.setX(m_ptStartPos.x()); axisStartPoint.setY(y); QString scale_str = (y_scale_string_list.isEmpty())? QString::number((axis_y_range.y() - axis_y_range.x()) / (count - 1) * i,'f',2): y_scale_string_list.at(i); axis_x_string_width = fm.width(scale_str); axis_x_string_heigh = fm.height(); // X轴字符的高度 int rect_y = axisStartPoint.y() - axis_x_string_heigh / 2; if(coordinate_dir) rect_y = this->height() - rect_y - axis_x_string_heigh; QRectF rect(axisStartPoint.x() - scale_value - axis_x_string_width, rect_y, axis_x_string_width, axis_x_string_heigh); if(scale_str.isEmpty())continue; if(i == count - 1) // 从最后一个刻度文本开始,优先绘制最大刻度文本 { string_scale_base = axisStartPoint.y() - axis_x_string_heigh / 2; // 计算文本起点X坐标 } if((axisStartPoint.y() + axis_x_string_heigh / 2 > string_scale_base) && (i < count - 1)) { continue; // 文本重叠 } else { string_scale_base = axisStartPoint.y() - axis_x_string_heigh / 2; } painter->drawText(rect,scale_str); } /* 设置XY轴单位字符 */ if(!x_unit_string.isEmpty()) { axis_x_string_width = fm.width(x_unit_string); axis_x_string_heigh = fm.height(); // X轴字符的高度 int rect_y = m_ptStartPos.y() + m_ptStartPos.x() / 10; if(coordinate_dir) rect_y = this->height() - rect_y - axis_x_string_heigh; QRectF rect(m_ptStartPos.x() + m_axisWidth + m_ptStartPos.x() / 2 - axis_x_string_width / 2, rect_y, axis_x_string_width, axis_x_string_heigh); painter->drawText(rect,x_unit_string); } if(!y_unit_string.isEmpty()) { axis_x_string_width = fm.width(y_unit_string); axis_x_string_heigh = fm.height(); // Y轴字符的高度 int rect_y = (m_ptStartPos.y() + m_axisHeight + m_ptStartPos.y() - axis_x_string_heigh); if(coordinate_dir) rect_y = this->height() - rect_y - axis_x_string_heigh; QRectF rect(m_ptStartPos.x() + m_axisHeight / 75 * 2, rect_y, axis_x_string_width, axis_x_string_heigh); painter->drawText(rect,y_unit_string); } }

https://download.csdn.net/download/zsj_rainsy/87032911

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 15:04:05

工业触摸屏LCD测试工具:从原理到Python自动化实现

简介&#xff1a;本资源是一套面向嵌入式开发与FPGA工程师的AN871触摸屏LCD联合调试工具包&#xff0c;聚焦于工业人机交互设备的底层功能验证与驱动适配。资源提供完整的lcdtesttool测试框架及配套工程文件&#xff0c;支持对AN871触摸控制器与液晶屏组合进行初始化、坐标校准…

作者头像 李华
网站建设 2026/9/5 15:03:30

JavaWeb美食网站实战:从零部署可商用系统

简介&#xff1a;本资源是一套基于JavaWeb技术栈开发的美食网站完整项目源码&#xff0c;面向Java初学者与Web开发入门者&#xff0c;解决动态网站开发实践缺位、MVC架构理解不深、数据库交互与前后端协同难上手等典型学习痛点。压缩包共含多个核心模块文件&#xff0c;涵盖JSP…

作者头像 李华
网站建设 2026/9/5 15:00:15

CentOS Linux 7 DHCP服务器搭建

DHCP服务器搭建前言一、DHCP是什么&#xff1f;二、安装DHCP服务器三、一些重要相关的命令总结前言 学习Linux系统过程中&#xff0c;搭建DHCP服务器是必须要学会的&#xff0c;本次教程教大家如何搭建DHCP服务器&#xff0c;讲解DHCP服务器的功能概况。 一、DHCP是什么&#…

作者头像 李华
网站建设 2026/9/5 14:59:48

快速了解Ifconfig命令使用

快速了解Ifconfig命令使用 ifconfig快速了解Ifconfig命令使用1、什么是ifcongif2、安装ifconfig工具3、ifconfig命令使用1、什么是ifcongif ifconfig是linux系统的网络配置命令(interfaces config)&#xff0c;通常是以root身份登入。依赖于ifconfig命令中一些选项属性&#x…

作者头像 李华
网站建设 2026/9/5 14:58:51

第11章 案例研究: 文本统计

到目前为止&#xff0c;你见到的代码片段大多只有几行&#xff0c;旨在演示某项Python功能。编程新手会很快发现&#xff0c;将小小的代码片段组织成完整的程序是一大步。要编写规模较大的程序&#xff0c;必须更详尽地规划&#xff0c;还需对如何以最佳方式结合使用各项Python…

作者头像 李华
网站建设 2026/9/5 14:56:57

kubeadm搭建k8s v1.13.3及部署dashboard

PS&#xff1a;由于部署这套环境用到的镜像和相关文件难以下载&#xff0c;特上传到百度网盘&#xff0c;供大家使用&#xff01; 链接&#xff1a;https://pan.baidu.com/s/1Zrmuf0ddUQlpw6ErmRoLow 提取码&#xff1a;t9pl一、环境说明 平台&#xff1a;OpenStack 操作系统…

作者头像 李华