Qt5绘制仪表盘dashboard
说明
- 本文演示Qt版本: Qt5.14.
- 本文将使用QPainter一步一步绘制仪表盘:刻度、指针、刻度值
- 注意: 绘制顺序,如果先绘制,则后来绘制的将会覆盖住先前绘制的。
- 如果需要绘制半透明, 请设置QColor的第四个参数 alpha , 范围: 0~255, 0 - 全透明, 255-不透明
样式
- 比较粗糙, 后面在优化
- 这是工作上遇到的需要绘制的图形。
- 蓝色的是指针indicator
下面一步一步开始绘制
开始前之前
- 重写函数paintEvent( QPaintEvent *event )。QtGuiApplication1继承自QWidget.
- 设置反走样(抗锯齿)
QPainter painter( this );
painter.setRenderHint( QPainter::Antialiasing, true);
绘制圆
代码
void QtGuiApplication1::draw_ellipse_( QPainter& painter )
{
painter.save();
/// -----------------------------------------------------------------
/// 设置画笔颜色
painter.setPen(QPen(QColor(100, 200, 100), 2));
/// 直接绘制圆
painter.drawEllipse( circle_config_.start_x_, circle_config_.start_y_,
circle_config_.radius_ * 2, circle_config_.radius_ * 2 );
/// -----------------------------------------------------------------
painter.restore();
}
效果
绘制刻度
每10度绘制一个刻度线,每30度绘制一个较长的刻度线
代码
void QtGuiApplication1::draw_dial_( QPainter& painter )
{
painter.save();
painter.setPen(QPen(QColor(200, 100, 200), 2));
/// 旋转坐标
/// 第一个参数: 坐标起点X
/// 第二个参数: 坐标起点Y
/// 第三个参数: 相对当前坐标系 向目标坐标系需要旋转多少度
/// 第四个参数: 是否绘制较长的刻度
auto draw_dial = [&]( const double& xxx, const double& yyy, const double& angle, const bool& is_longer )
{
int dial_len = 8;
if (true == is_longer)
dial_len = 30;
/// 重置坐标系
painter.resetTransform();
/// 将其移动到目标点
painter.translate(xxx, yyy );
/// 再旋转指定角度
painter.rotate( angle );
/// 绘制刻度
painter.drawLine( QLine(QPoint(0, 0), QPoint(-dial_len, 0)) );
};
/// 圆。 360度, 每10度绘制一个刻度线
for (int angle = 0; angle <= 360; angle += 10)
{
double xxx = 0;
double yyy = 0;
/// 根据圆心得到园周边的点坐标
get_dial_config_(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, xxx, yyy, angle);
/// 每30°绘制一个长一点的刻度
bool is_longer = ( 0 == ( angle % 30 ) ? true : false );
/// 绘制刻度
draw_dial( xxx, yyy, angle, is_longer);
}
painter.restore();
}
效果
绘制指针
- 这里是用扇形标识指针
- 注意: X轴正方向是3点钟反向
代码
/// --------------------------------------------------------------------------------------------------------
/// @brief: 绘制指针
/// --------------------------------------------------------------------------------------------------------
void QtGuiApplication1::draw_indicator_( QPainter& painter )
{
painter.save();
/// -----------------------------------------------------------------
painter.setPen(QPen(QColor(0, 0, 239)));
QBrush brush( QBrush( QColor( 0, 0, 239, 100) ) );
painter.setBrush(brush);
/// 在矩形内切椭圆上画,3点钟为0度,逆时针为正,角度要乘以16(参考文档)
/// 起点,
int startAngle = -3 * 16;
/// 圆弧的角度大小
int spanAngle = 6 * 16;
painter.drawPie(circle_config_.start_x_, circle_config_.start_y_, circle_config_.radius_ * 2, circle_config_.radius_ * 2,
startAngle, spanAngle);
/// -----------------------------------------------------------------
painter.restore();
}
效果
绘制刻度数字
- 刻度数字其实也是绘制在圆周边上的,比如,上图的中的半径为R,而刻度文字所在圆的半径则是 0.8倍R,这样就可以将文字绘制圈圈内了。
代码
void QtGuiApplication1::draw_scale_number_( QPainter& painter )
{
painter.save();
/// -----------------------------------------------------------------
double rrr = circle_config_.radius_ * 0.8 ;
painter.setFont( QFont( "Microsoft Yahei", 10 ) );
QFontMetrics fm( painter.font() );
/// for (int index = -150; index <= 150; index += 30)
for (int index = 0; index < 360; index += 30)
{
double xxx = 0;
double yyy = 0;
/// 根据圆心得到园周边的点坐标
get_dial_config_( circle_config_.center_x_, circle_config_.center_y_, rrr, xxx, yyy, index );
int dial_num = index - 270;
/// 3点为X轴, 故这里要特殊显示为90 ~ 150
if (90 > index)
dial_num = index + 90;
/// 180不显示
if (-180 == dial_num)
continue;
/// 下面这一步是为了得到绘制文字的宽和高, 从而决定文字的起点坐标
/// -----------------------------------------------------------------
/// 字体的高度
int fontw = fm.width(QString::number( dial_num));
/// 字体的宽度
int fonth = fm.height();
xxx -= fontw / 2.0;
yyy += fonth / 4.0;
/// -----------------------------------------------------------------
painter.drawText( xxx, yyy, QString::number( dial_num));
}
painter.restore();
}
效果
下面我们让指针动起来
开始之前
- UI增加控件 QSlider,设置其范围是0 ~360
- 关联滑块的信号,当值发生变化,则触发重绘
void QtGuiApplication1::slot_slider_value_changed_( int value )
{
/// 指针当前角度
circle_config_.cur_angle_ = ( double ) value;
QWidget::update();
}
绘制指针
这里只需要将 起始角度 -3 改为 当前滑块的值即可。 完整代码如下
代码
void QtGuiApplication1::draw_indicator_( QPainter& painter )
{
painter.save();
/// -----------------------------------------------------------------
painter.setPen(QPen(QColor(0, 0, 239)));
QBrush brush( QBrush( QColor( 0, 0, 239, 100) ) );
painter.setBrush(brush);
/// 在矩形内切椭圆上画,3点钟为0度,逆时针为正,角度要乘以16(参考文档)
/// 起点,
int startAngle = (circle_config_.cur_angle_ - 3.0) * 16;
/// 圆弧的角度大小
int spanAngle = 6 * 16;
painter.drawPie(circle_config_.start_x_, circle_config_.start_y_, circle_config_.radius_ * 2, circle_config_.radius_ * 2,
startAngle, spanAngle);
/// -----------------------------------------------------------------
painter.restore();
}
效果
补充
- 实战中,发现使用 扇形绘制的指针,指针填充渐变色的时候 不太理想, 因为按照公式计算的半径得到的坐标总是不对。 于是 换了中绘制指针的方法: 画两根线, 两根线中间用画刷刷成指定的渐变色。
- 为了见刻度显示在指针的上面, 因此,先与刻度绘制指针。
效果图
代码
这里是先绘制的指针,再绘制的周围的刻度
draw_indicator2_(painter);
/// 绘制指针
//draw_indicator_(painter);
/// 绘制圆
draw_ellipse_(painter);
/// 绘制刻度
draw_dial_(painter);
/// 绘制刻度值
draw_scale_number_(painter);
绘制指针
/// --------------------------------------------------------------------------------------------------------
/// @brief: 绘制指针
/// --------------------------------------------------------------------------------------------------------
void QtGuiApplication1::draw_indicator2_(QPainter& painter)
{
painter.save();
/// -----------------------------------------------------------------
/// 计算指针两条线的坐标, 方法: 以圆心为起点,旋转指定角度绘制两条只想, 夹角暂定为6度
/// 起始角度为当前角度 - 3(3 = 6 / 2.0)
auto draw_line = [&](const double& startx, const double& starty, const double& radius, const double& angle)
{
painter.resetTransform();
painter.translate(startx, starty);
painter.rotate(angle);
painter.drawLine(0, 0, radius, 0);
};
/// 因为是逆时针绘制的夹角,
draw_line(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, circle_config_.cur_angle_ - 3);
draw_line(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, circle_config_.cur_angle_ + 3);
/// -----------------------------------------------------------------
painter.restore();
}
加填充色填充
- 这里以填充渐变色, 还能学学 渐变色 QLinearGradient类的用法
- 老规矩, 上效果:
代码
/// --------------------------------------------------------------------------------------------------------
/// @brief: 绘制指针
/// --------------------------------------------------------------------------------------------------------
void QtGuiApplication1::draw_indicator2_(QPainter& painter)
{
painter.save();
/// -----------------------------------------------------------------
/// 计算指针两条线的坐标, 方法: 以圆心为起点,旋转指定角度绘制两条只想, 夹角暂定为6度
/// 起始角度为当前角度 - 3(3 = 6 / 2.0)
auto draw_line = [&](const double& startx, const double& starty, const double& radius, const double& angle)
{
painter.save();
painter.resetTransform();
painter.translate(startx, starty);
painter.rotate(angle);
painter.drawLine(0, 0, radius, 0);
painter.restore();
};
/// 因为是逆时针绘制的夹角,
draw_line(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, circle_config_.cur_angle_ - 3);
draw_line(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, circle_config_.cur_angle_ + 3);
/// 计算渐变色的坐标
/// 渐变色的坐标起点是圆心 终点 就是 指针与圆周边的交点
/// 这里的指针是用一个三角形代替指针的,当周围的刻度绘制在指针的上面,哈哈遮住了 圆弧那段没有填充色的部分
/// 指针的两条直线之一A与圆周边的焦点A
double lg_a_end_x = 0;
double lg_a_end_y = 0;
get_dial_config_(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, lg_a_end_x, lg_a_end_y, circle_config_.cur_angle_ - 3);
/// 指针的两条直线之一B与圆周边的焦点A
double lg_b_end_x = 0;
double lg_b_end_y = 0;
get_dial_config_(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, lg_b_end_x, lg_b_end_y, circle_config_.cur_angle_ + 3);
/// 三角区域
const QPointF triganle_points[3] =
{
QPointF(circle_config_.center_x_, circle_config_.center_y_),
QPointF(lg_a_end_x, lg_a_end_y),
QPointF(lg_b_end_x, lg_b_end_y)
};
/// 当前角度与圆的交点坐标,用于确定填充区域
double lg_end_x = 0;
double lg_end_y = 0;
get_dial_config_(circle_config_.center_x_, circle_config_.center_y_, circle_config_.radius_, lg_end_x, lg_end_y, circle_config_.cur_angle_);
QLinearGradient lg(circle_config_.center_x_, circle_config_.center_y_, lg_end_x, lg_end_y);
/// 0 ~ 0.3的区域填充 红色
lg.setColorAt(0.3, QColor(230, 0, 0));
/// 0.3 ~ 0.6的区域填充绿色
lg.setColorAt(0.6, QColor(0, 230, 0));
/// 0.6~1之间的区域填充蓝色
lg.setColorAt(1.0, QColor(0, 0, 230));
/// 设置划线的颜色
painter.setPen(QPen(QColor(30, 30, 30), 2));
/// 设置画刷颜色
painter.setBrush(QBrush(lg));
painter.drawPolygon(triganle_points, 3, Qt::OddEvenFill);
/// -----------------------------------------------------------------
painter.restore();
}
gif效果图
Qt5绘制仪表盘dashboard的更多相关文章
- OpenStack-Ocata版+CentOS7.6 云平台环境搭建 — 8.仪表盘 Dashboard(horizon)安装配置
仪表盘Dashboard(horizon)是一个web接口,使得云平台管理员以及用户可以管理不同的Openstack资源以及服务.这个部署示例使用的是 Apache Web 服务器. 节点配置信息说明 ...
- C# GDI绘制仪表盘(纯代码实现)
纯代码实现GDI绘制仪表盘,效果在代码下面. public partial class HalfDashboardUc : UserControl { /// <summary> /// ...
- Qt自定义控件之仪表盘2--QPaint绘制仪表盘
0.前言 前面一篇文章写道了仪表盘的特点,实现了一个贴图的仪表盘,属于低配版本的仪表盘. 主要是有任何改动时候就需要重新设计图片,不能适配不同控件大小,即使让它自由拉伸,但仪表盘放大缩小时候显示 ...
- Python pyecharts绘制仪表盘
一.仪表盘gauge.add方法简介 gauge.add()方法签名 add(name,attr,value, scale_range=none, angle_range=none,**kwargs) ...
- Kibana仪表盘(Dashboard)详解
Kibana 仪表板(Dashboard) 展示保存的可视化结果集合. 在编辑模式下,您可以根据需要安排和调整可视化结果集,并保存仪表板,以便重新加载和共享. 创建一个仪表板 如何创建一个仪表板: 点 ...
- Qt之自绘制饼图
1.说明 最近在搞绘图方面的工作,说实话C++的第三方绘图库并不算多,总之我了解的有:qtcharts.ChartDirector.qwt.kdchart和QCustomPlot.这几个库各有利弊. ...
- IOS自定义仪表盘
登录|注册 周海锋 的专栏 Objective-C/Cocos2d/Cocos2d-x/Php/JS 目录视图 摘要视图 订阅 2016软考项目经理实战班 学院周年礼-顶 ...
- C++制作电压表电流表仪表盘(vs2008)
Meter类 Meter.h #if !defined(AFX_METER_H__D5802279_6502_4453_BE21_58604877AD39__INCLUDED_) #define AF ...
- d3.js 入门指南 - 仪表盘
D3的全称是Data-Driven Documents(数据驱动的文档),是一个用来做数据可视化的JavaScript函数库,而JavaScript文件的后缀通常为.js,所以D3被称为D3.js. ...
随机推荐
- Hive-删除表(drop、truncate的区别)
Hive删除操作主要分为几大类:删除数据(保留表).删除库表.删除分区.我将以下图为例清空iot_devicelocation中的数据,之后再删除表.库等. 解释: use xpu123; #使用 ...
- EXCEL-对筛选出(单独手动隐藏行还是在统计范围内)的表格数据进行统计
=SUBTOTAL(3,A1:A5) #计算筛选出的表格中A1:A5中有几个值. =SUBTOTAL(3,I71:I21447) ,在I71:I21447之间计数,会自动略去没有筛选上的隐藏单元格 ...
- fastboot烧写Andriod 以及SD 卡烧写LinuxQT,
EMMC是一种FLASH,SD(TF)卡是另外的一种存储,通过控制拨码开关指引CPU去读EMMC还是SD卡的u-boot文件. u-boot的作用 初始化内存控制区,访问存储器,把内核从存储器读取出来 ...
- ChromeDriver的安装和使用
用于驱动Chrome浏览器,适用于有界面的操作系统. 一.安装ChromeDriver 要先安装Chrome浏览器,然后安装ChromeDriver. 官方网站:https://sites.googl ...
- SpringCloud微服务实战——搭建企业级开发框架(二十八):扩展MybatisPlus插件DataPermissionInterceptor实现数据权限控制
一套完整的系统权限需要支持功能权限和数据权限,前面介绍了系统通过RBAC的权限模型来实现功能的权限控制,这里我们来介绍,通过扩展Mybatis-Plus的插件DataPermissionInterce ...
- Kubernetes-存储(一)
前言 本篇是Kubernetes第十二篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战. Kubernetes系列文章: Kubernetes介绍 Kubernetes环境搭建 Kubern ...
- Yarn 公平调度器案例
目录 公平调度器案例 需求 配置多队列的公平调度器 1 修改yarn-site.xml文件,加入以下从参数 2 配置fair-scheduler.xml 3 分发配置文件重启yarn 4 测试提交任务 ...
- day08 索引的创建与慢查询优化
day08 索引的创建与慢查询优化 昨日内容回顾 视图 视图:将SQL语句查询结果实体化保存起来,方便下次查询使用. 视图里面的数据来源于原表,视图只有表结构 # 创建视图 create view 视 ...
- 23. 关于Ubuntu中Could not get lock /var/lib/dpkg/lock解决方案
原文:https://blog.csdn.net/u011596455/article/details/60322568 版权声明:本文为博主原创文章,转载请附上博文链接! 在Ubuntu中,有时候运 ...
- d3 CSS
CSS的inline.block与inline-block 块级元素(block):独占一行,对宽高的属性值生效:如果不给宽度,块级元素就默认为浏览器的宽度,即就是100%宽. 行内元素(inline ...