Qt编写数据可视化大屏界面电子看板10-改造QCustomPlot

1、前言

为了抛弃对QChart的依赖,以及echart的依赖,(固然,后期也会作qchart的版本和echart的版本,尤为是echart的版本是确定会作的,毕竟echart的效果牛逼的一塌糊涂,全宇宙最牛逼吧。)特地对QCustomPlot进行了大刀阔斧的改造,固然这个改造不是直接在源码上修改,这个就破坏了源码的完整性,说不定被QCustomPlot的做者知道了有种被QJ的感受,我得改造是直接继承QCustomPlot中的部分类开始的,好比为了实现横向柱状图,特地继承自QCPItemRect类来实现的,包括了横向柱状图和横向柱状分组图。在这个横向柱状图的自动计算过程当中,竟然用到了十几年前学习的二元一次方程,自动计算数据和柱状图位置,给定两个数据点绘制矩形。linux

QCustomPlot类作的很是好,做者将曲线图和柱状图和其余几种形状的图,玩得神乎其神,本人直接跪了。尤为是如今的2.0版本,比之前的1.0版本更加上了一个档次,直接将各类功能拆分红一个个小类,分层绘制,至关牛逼,好比要作个游标,直接继承QCPLayerable类,而后在void draw(QCPPainter *painter);中绘制本身的东西便可,QCustomPlot提供了一个很是完美的鼠标拉动缩放的二维坐标系,还有对应的坐标与屏幕坐标转换的函数,继承自QCPItemRect这个东东,能够任意绘制任意图形,包括圆形矩形各类,本人有个大胆的想法就是,直接将那145个控件大全控件在QCustomPlot中绘制一遍,都是彻底可行的,这样的话还支持滚轮任意缩放呢。sql

2、电子看板介绍

电子看板是目视化管理的一种表现形式,即对数据的情况一目了然地表现,主要是对于管理项目,它经过利用形象直观而又色彩适宜的各类视觉感知信息来组织现场生产活动,目视管理依据人类的生理特征,在生产现场充分利用信号灯、标识牌、符号颜色等方式来发出视觉信号,鲜明准确地刺激人的神经末梢,快速地传递信息,形象直观地将潜在的问题和浪费现象都显现出来。以便任何人均可以及时掌握管理现状和必要的情报,从而可以快速制定并实施应对措施。所以,管理看板是发现问题、解决问题的很是有效且直观的手段,是优秀的现场管理必不可少的工具之一。数据库

3、功能特色

  1. 总体总共分三级界面,一级界面是总体布局,二级界面是单个功能模块,三级界面是单个控件。
  2. 子控件包括饼图+圆环图+曲线图+柱状图+柱状分组图+横向柱状图+横向柱状分组图+合格率控件+百分比控件+进度控件+设备状态面板+表格数据+地图控件(包括动态闪烁点+迁徙图等)+视频控件+其余控件等。
  3. 二级界面能够自由拖动悬浮,支持最小化最大化关闭,响应双击自定义标题栏。
  4. 数据源支持数据库采集(默认)、网络通讯、网络请求等,可自由设定每一个子界面的采集间隔即数据刷新频率。
  5. 采用纯QWidget编写,支持Qt4.6到Qt5.12.3任何版本,支持嵌入式linux好比树莓派、香橙派、全志、imx6等。
  6. 提供三个内核版本,自定义控件版本+qchart版本+echart版本。
  7. 内置多套配色风格样式,默认紫色,支持任何分辨率。
  8. 可设置标题+目标分辨率+布局方案,启动当即应用。
  9. 可设置主背景颜色+面板颜色+十字线游标颜色。
  10. 可设置多条曲线颜色,没有设置颜色的状况下内置15套精美颜色随机应用。
  11. 可设置标题栏背景颜色+文字颜色。
  12. 可设置曲线图表背景颜色+文字颜色+网格颜色。
  13. 可设置正常颜色+警惕颜色+报警颜色+禁用颜色+百分比进度颜色。
  14. 可分别设置各类字体大小,好比全局+软件名称+标题栏+子标题栏+加粗标签等。
  15. 可设置标题栏高度+表头高度+行高度。
  16. 曲线支持游标+悬停高亮数据点和显示值,柱状图支持顶部(可设置顶端+上部+中间+底部)显示数据,所有自适应计算位置。
  17. 主界面直接鼠标右键切换布局+配色方案+关闭开启某个二级窗体。
  18. 自动记忆全部子窗口的大小和位置,下次启动当即应用。
  19. 动态加载布局方案菜单,能够动态新建布局、恢复布局、保存布局、另存布局等,用户能够制造任意布局。
  20. 二级窗体,双击从主窗体分离出来浮动,能够自由调整大小。再次双击标题栏最大化,再次双击还原。
  21. 每一个模块均可以自定义采集速度,若是是数据库采集会自动排队处理。

4、配置文件说明

(1)、基本配置参数

字段 描述 默认值
WorkMode 工做模式 timer-模拟数据 db-数据库采集 tcp-网络采集 http-post请求 db
MapStyle 中间地图样式 image-静态图片 point-闪烁点 move-迁徙图 point
Title 软件标题,显示在软件中间顶部 数字化工厂信息中心
Ratio 分辨率,目前无心义 4096*216
Layout 布局方案,每次切换布局方案之后都会保存 完整布局
Theme 配色方案,每次切换配色方案之后都会保存 紫色风格
VideoAddr 视频流地址,视频模块播放的视频地址 凤凰卫视
AutoRun 是否开机启动 false
MoveEnable 模块是否能够拖动,启用之后模块能够任意拖动 true
CutLeftBottom 底部布局左侧是否切掉 true
CutRightBottom 底部布局右侧是否切掉 true
StaticLine 是否绘制静态定位线,为假则绘制游标十字线 true
ShowPercent Y轴是否显示百分比 true
StepY Y轴大尺度步长 6
CursorHideTime 用户不操做鼠标自动隐藏鼠标的时间间隔,单位秒 5

(2)、颜色配置参数

字段 描述 默认值
ColorMainBg 主背景颜色 QColor(4, 7, 38)
ColorPanelBg 面板背景颜色 QColor(26, 29, 60)
ColorLine 十字线定位线颜色 QColor(255, 0, 0)
ColorLine1 线条1颜色 QColor(0, 176, 180)
ColorLine2 线条2颜色 QColor(32, 159, 223)
ColorLine3 线条3颜色 QColor(255, 192, 0)
ColorTitleBg 标题栏背景颜色 QColor(48, 48, 85)
ColorTitleText 标题栏文字颜色 QColor(255, 255, 255)
ColorChartBg 曲线图表背景颜色 QColor(38, 41, 74)
ColorChartText 曲线图表文字颜色 QColor(250, 250, 250)
ColorChartGrid 曲线图表网格颜色 QColor(180, 180, 180)
ColorOk 正常颜色 QColor(0, 176, 180)
ColorLow 警惕颜色 QColor(255, 192, 0)
ColorAlarm 报警颜色 QColor(214, 77, 84)
ColorDisable 禁用背景颜色 QColor(210, 210, 210)
ColorPercent 环形百分比背景颜色 QColor(0, 254, 254)

(3)、字体和尺寸配置参数

字段 描述 默认值
MainFont 全局字号 微软雅黑,12
NameFont 软件名称字号 19
LabFont 加粗标签字号 12
DeviceFont 设备面板字号 12
SubTitleFont 模块子标题栏字号 13
TitleFont 模块标题栏字号 15
TitleHeight 模块标题栏高度 23
HeadHeight 表格表头高度 28
RowHeight 表格行高度 25

(4)、采集速度配置参数

字段 描述 默认值
IntervalModule1 模块1采集间隔 5000
IntervalModule2 模块2采集间隔 5000
IntervalModule3 模块3采集间隔 5000
IntervalModule4 模块4采集间隔 5000
IntervalModule5 模块5采集间隔 5000
IntervalModule6 模块6采集间隔 5000
IntervalModule7 模块7采集间隔 5000
IntervalModule8 模块8采集间隔 5000

(5)、本地数据库配置参数

字段 描述 默认值
LocalDBType 本地数据库类型,Sqlite、Mysql等 Mysql
LocalDBIP 本地数据库主机地址 127.0.0.1
LocalDBPort 本地数据库端口 3306
LocalDBName 本地数据库名称 bigscreen
LocalUserName 本地数据库用户名 root
LocalUserPwd 本地数据库密码 root

5、特别说明

  1. 可执行文件同级文件夹有layout+layout_1440+layout_1920,程序默认自动识别分辨率并加载对应的布局文件夹,好比1920分辨率则从layout_1920文件夹加载布局,并做为总体布局文件夹。
  2. 程序默认是模拟数据,若是须要从数据库采集则修改配置文件WorkMode=db便可。
  3. 若是发现布局拖动乱了,能够直接鼠标右键选择恢复布局便可,在保存布局之前。
  4. 在中间地图模块鼠标右键能够弹出菜单,切换布局和配色方案等。
  5. 在模块的标题栏上右键能够弹出默认的dock菜单,用来显示和隐藏各模块。
  6. 软件关闭过程当中会自动保存布局,下次启动之后自动应用。
  7. 若是使用的默认的默认的配色方案好比紫色风格,则配置文件中的颜色所有无效,会自动应用代码中的颜色,若是须要启用自定义的颜色,则将配置文件的 Theme=\x81ea\x5b9a\x4e49\x98ce\x683c 便可。此时打开软件会应用配置文件中的颜色。
  8. 右键菜单能够截图保存,默认命名为 配色方案名称_布局方案名称.png 保存在snap目录下。
  9. 若是是XP系统请先执行fixff.cmd,用来修复ffmpeg在XP上不可用的BUG。
  10. 在二级窗体的标题栏上右键弹出模块菜单,能够对单个模块打开关闭,其余地方右键全局菜单。
  11. 可执行文件下载地址:https://pan.baidu.com/s/1o97IGvZgTgDhlkuXQa4B0w 提取码:r2bv。
  12. 会不按期更新程序,欢迎各位提出批评和建议。

6、效果图

7、核心代码

void CustomPlot::mouseMove(QMouseEvent *event)
{
    if (tracer == 0 || textTip == 0) {
        return;
    }

    //跟踪鼠标点击事件点击位置
    QCPGraph *graph = (QCPGraph *)customPlot->plottableAt(event->pos(), true);
    QRect rect(0, 0, 1, 1);

    QString labx, laby;
    int offset = 10;
    bool toolTip = false;

    if(graph != 0) {
        double posKey;
        double key = 0, value = 0;
        QPoint p;
        p.setX(event->pos().x());
        p.setY(event->pos().y());

#ifdef old
        foreach(QCPData data, graph->data()->values()) {
            key = data.key;
            value = data.value;
#else
        for (int i = 0; i < graph->dataCount(); i++) {
            key = graph->dataMainKey(i);
            value = graph->dataMainValue(i);
#endif
            //取出对应key处的label标签,若是标签为空则取key的字符串
            labx = customPlot->xAxis->tickVectorLabels().at(key);
            labx = labx.isEmpty() ? QString::number(key) : labx;

            //若是启用了百分比则须要后面显示百分比
            if (this->getPercentY()) {
                laby = QString("%1%").arg(value);
            } else {
                laby = QString("%1").arg(value);
            }

            posKey = customPlot->xAxis->coordToPixel(key);
            if(qAbs(posKey - event->pos().x()) <= offset) {
                double posx = graph->keyAxis()->coordToPixel(key);
                double posy = graph->valueAxis()->coordToPixel(value);
                rect.setRect(posx - offset, posy - offset, offset * 2, offset * 2);
                if(!rect.contains(event->pos())) {
                    continue;
                } else {
                    break;
                }
            }

            if(posKey - event->pos().x() > offset) {
                break;
            }
        }

        if(!graph->realVisibility()) {
            toolTip = false;
            tracer->setVisible(false);
            customPlot->replot();
        } else if(rect.contains(event->pos())) {
            toolTip = true;
            tracer->setVisible(true);
            tracer->setGraph(graph);
            tracer->setGraphKey(key);
            customPlot->replot();
        } else if(tracer->visible()) {
            toolTip = false;
            tracer->setVisible(false);
            customPlot->replot();
        }
    }
    else if(tracer->visible()) {
        toolTip = false;
        tracer->setVisible(false);
        customPlot->replot();
    }

    //处理提示信息
    if(toolTip) {
        //根据设定的提示信息位置调整
        double x = event->pos().x();
        double y = event->pos().y();
        if (toolTipPosition == 0) {
            //判断曲线控件的位置已经当前鼠标位置作出调整
            bool right = (customPlot->width() - x < 90);
            bool bottom = (customPlot->height() - y < 50);
            if (right) {
                if (bottom) {
                    x = x - 80;
                    y = y - 50;
                } else {
                    x = x - 80;
                    y = y - 20;
                }
            } else {
                if (bottom) {
                    x = x + 10;
                    y = y - 50;
                } else {
                    x = x + 10;
                    y = y - 20;
                }
            }
        } else if (toolTipPosition == 1) {
            x = x - 30;
            y = y - 50;
        } else if (toolTipPosition == 2) {
            x = x + 10;
            y = y - 50;
        } else if (toolTipPosition == 3) {
            x = x + 10;
            y = y - 20;
        } else if (toolTipPosition == 4) {
            x = x + 10;
            y = y + 10;
        } else if (toolTipPosition == 5) {
            x = x - 30;
            y = y + 10;
        } else if (toolTipPosition == 6) {
            x = x - 75;
            y = y + 10;
        } else if (toolTipPosition == 7) {
            x = x - 80;
            y = y - 20;
        } else if (toolTipPosition == 8) {
            x = x - 80;
            y = y - 50;
        }

        QString text = "横坐标: " + labx + "\n当前值: " + laby;
        textTip->position->setCoords(x, y);
        textTip->setText(text);
        textTip->setVisible(true);
        customPlot->replot();
    } else {
        if (textTip->visible()) {
            textTip->setVisible(false);
            customPlot->replot();
        }
    }
}
相关文章
相关标签/搜索