Log模块主要用于实时测井数据的显示和测后曲线数据的预览和打印,为更好的展示对Qt中相关知识点的应用,特以Log模块为例对其进行简要实现。

内容导图:

  

一、功能需求

1、界面效果图

  

  Log模块实现曲线数据的显示及相关属性(曲线颜色、画笔类型、画笔宽度等)的设置

  将上图划分为三个区域:右边为轨道信息显示和管理区,可以参看和设置相关轨道信息

             左上为轨道的Label信息区,轨道中包含的曲线及曲线对应的曲线名、曲线值范围、单位、曲线颜色

             左下为曲线数据显示区

  本实例展示了三个轨道(P、D、R),P轨道有两条曲线(gr、ccl),红色曲线对应的是GR曲线数据,D轨道为深度道,显示曲线数据对应的深度值(每个单元格实际高度为5mm)、R轨道有一条曲线(CCL)

2、功能需求

  (1)打开文件对话框选择log配置文件显示当前配置下的轨道信息(包括上图三个区域)

  (2)加载数据,对相应的曲线进行绘制

  (3)拖动滚动条查看对应深度的曲线数据

  (4)根据右边的区域对轨道和曲线进行管理(信息查看和设置)

二、详细设计

1、UI设计

  从上面的界面效果图可以看到:

  (1)菜单、工具栏、状态栏的实现

  (2)左边为QMidQrea多文档区域,再对单个的文档区域进行QSplitter切割分为TrackView和LogView,trackView用于显示label信息,LogView用于显示曲线数据

  (3)右边为QDockWidget,用于管理track信息,可以实现上下左右4多个区域停靠

2、整体架构设计

  

3. UML类图设计

(1)MainWindow布局

  

(2)类图

  说明:最开始的思想是使用QGraphicsView/QGraphicsScene/QGraphicsitem的视图架构来绘制,最终以失败告终,因为对scene的左上角位置始终无法固定到视口的最上角,窗口变化,滚动条变化会导致scene位置的变化。最终选择在QWidget上进行双缓存绘图。

  

三、Qt相关知识点

1. 菜单、工具栏、状态栏实现

  为了简明扼要直接说步骤(以File菜单下的Open xmlFile子菜单为例):

(1)添加各菜单项的QAction及信号槽

QAction* m_pFileAction;
m_pFileAction = new QAction(QIcon(":/images/openfile.png"), tr("Load Template"), this);
connect(m_pFileAction, SIGNAL(triggered(bool)), this, SLOT(onLloadTemplate()));

(2)添加菜单

QMenu* pFileMenu = menuBar()->addMenu("File");
pFileMenu->addAction(m_pFileAction);

(3)添加工具条

QToolBar* pToolbar = addToolBar(tr("file"));
pToolbar->addAction(m_pFileAction);

(4)添加状态栏

m_pFileAction->setStatusTip(tr("open config file"));
statusBar();

2. QTrackWidget、QMdiArea、QSplitter的实现

  该知识点内容可以看之间的博客:Qt容器组件(二)之QWidgetStack、QMdiArea、QDockWidget

  还是贴一下代码,方便后面查看:

    m_pMdiArea = new QMdiArea(this);
m_pMdiArea->setBackground(QBrush(Qt::white));
m_pMdiArea->setViewMode(QMdiArea::TabbedView);
m_pMdiArea->setTabsClosable(true);
m_pMdiArea->setTabsMovable(true);
m_pMdiArea->setTabShape(QTabWidget::TabShape::Triangular);
m_pMdiArea->setTabPosition(QTabWidget::TabPosition::North); setCentralWidget(m_pMdiArea);   // 停靠窗口
if (m_pTrackWidget == NULL)
{
m_pTrackWidget = new QTrackWidget(this);
QDockWidget* pDockWidget = new QDockWidget("TrackInfos", this);
pDockWidget->setFeatures(QDockWidget::DockWidgetFeature::AllDockWidgetFeatures);
pDockWidget->setWidget(m_pTrackWidget);
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, pDockWidget);
m_pTrackWidget->initWidget();
} QSplitter *pSplitter = new QSplitter(Qt::Vertical, this);
// track视图窗口
m_pScrollArea = new ScrollArea; m_pTrackView = new TrackView(pSplitter); m_pScrollArea->setBackgroundRole(QPalette::Light); // 添加滚动条
m_pScrollArea->setWidget(m_pTrackView);
m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// logview视图窗口
m_pLogView = new LogView(pSplitter); m_pLogScrollArea = new ScrollArea;
m_pLogScrollArea->setBackgroundRole(QPalette::Light); // 添加滚动条
m_pLogScrollArea->setWidget(m_pLogView);
m_pLogScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_pLogScrollArea->setStep(m_pLogView->getRatioY()); pSplitter->setWindowTitle(fielInfo.fileName());
pSplitter->addWidget(m_pScrollArea);
pSplitter->addWidget(m_pLogScrollArea);
pSplitter->setStretchFactor(, ); // 设置分隔比例
pSplitter->setStretchFactor(, );
m_pMdiArea->addSubWindow(pSplitter);

3. XML文件解析

  Qt提供了DOM、SAX和流方法三种方式进行XML文件解析,这里主要介绍三种解析方法的特点和Dom解析的使用方法,若想了解更多,可以查看官方文档。

(1)DOM解析XML文档的特点

  基于DOM的解析器的核心是在内存中建立和XML文档相对应的树状结构。XML文件的标记、标记中的文本数据和实体等都是内存中的树状结构的某个节点相对应。

 优点:可以方便地操作内存中的树状节点

 缺点:如果XML文件较大,或者只需要解析XML文档的一部分数据,就会占用大量的内存空间

(2)SAX解析XML文档的特点

  SAX解析的核心是事件处理机制,SAX采用事件机制的方式来解析XML文档。使用SAX解析器对XML文档进行解析时,SAX解析器根本不创建任何对象,只是在遇到XML文档的各种标签如文档开始、元素开始、文本、元素结束时触发对应的事件,并将XML元素的内容封装成事件传出去。而程序员则负责提供事件监听器来监听这些事件,从而触发相应的事件处理方法,并通过这些事件处理方法实现对XML文档的访问。

  优点:具有占用内存少,效率高等特点。

  缺点:不便于随机访问任意节点。

(3)流方式解析XML文档的特点 

  QXmlStreamReader使用了递增式的解析器,适合于在整个XML文档中查找给定的标签、读入无法放入内存的大文件以及处理XML的自定义数据。

 优点:快速、方便,分块读取XML文件,可读取大文件

 缺点:递增式解析器,只能顺序遍历XML文件的元素,不能随机访问

 QXmlStreamWriter类提供了简单流接口的XML写入器,写入XML文档只需要调用相应的记号写入函数来写入相关数据。

 优点:快速、方便

 缺点:只能按顺序写入元素,不能删除、修改

(4)DOM方式解析XML文件

   http://blog.51cto.com/9291927/1879135

4. Q_PROPERTY

  关于Q_PROPERTY的相关知识,可以查看直接的博客:Qt属性系统(Qt Property System)

5. QVariant自定义数据类型使用

(1)定义自定义类型,如class QTrack

  需要注意:需实现拷贝构造函数和赋值构造函数

    explicit QTrack(QObject *parent=Q_NULLPTR);
QTrack(const QTrack& ther) {*this = ther;}
QTrack& operator=(const QTrack& ther);

(2)Q_DECLARE_METATYPE(QTrack)声明

(3)自定义类型的使用

m_pTrackComb->addItem(pTrack->getName(), QVariant::fromValue(pTrack));

// 得到track对象
QVariant variant = m_pTrackComb->currentData(Qt::UserRole);
QTrack* pTrack = variant.value<QTrack*>();

6. QFileDialog使用

static QString getOpenFileName(QWidget *parent = Q_NULLPTR,
const QString &caption = QString(),
const QString &dir = QString(),
const QString &filter = QString(),
QString *selectedFilter = Q_NULLPTR,
Options options = Options());
QString strFilePath = QFileDialog::getOpenFileName(this, "open xmlFile", "E:/qtquick/Log/config", "file(*.xml)");
QFileInfo fielInfo(strFilePath);

7. QColorDialog使用

static QColor getColor(const QColor &initial = Qt::white,
QWidget *parent = Q_NULLPTR,
const QString &title = QString(),
ColorDialogOptions options = ColorDialogOptions());
QColor color = QColorDialog::getColor(Qt::blue, this, tr("颜色选择对话框"));

8. QScrollArea

  QScrollArea提供了一个滚动视图到另一个部件。

  滚动区域用于显示一个画面中的子部件的内容。如果部件超过画面的大小,视图可以提供滚动条,这样就都可以看到部件的整个区域。

  为QWidget添加滚动条:

(1)继承QScrollArea

class ScrollArea : public QScrollArea
{
Q_OBJECT public:
explicit ScrollArea(QWidget *parent = Q_NULLPTR);
~ ScrollArea(); void scrollContentsBy(int dx, int dy) Q_DECL_OVERRIDE;
};
#include "scrollarea.h"
#include "logview.h" #include <QScrollBar> ScrollArea::ScrollArea(QWidget *parent)
:QScrollArea(parent)
{ } ScrollArea::~ScrollArea()
{ } void ScrollArea::scrollContentsBy(int dx, int dy)
{
m_pLogView->setDepthOffset(dy);
return QScrollArea::scrollContentsBy(dx,dy);
} void ScrollArea::setStep(qreal fRatioY)
{
QScrollBar *pScrollBar = verticalScrollBar();
pScrollBar->setSingleStep(fRatioY * ); // 25mm
pScrollBar->setPageStep(fRatioY * ); // 50mm
}

(2)为QWidget添加滚动条

m_pLogScrollArea = new ScrollArea;
m_pLogScrollArea->setBackgroundRole(QPalette::Light); // 添加滚动条
m_pLogScrollArea->setWidget(m_pLogView);
m_pLogScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

9. LogView的实现

  曲线数据的绘制关键:

(1)双缓存绘图

  先在QPixmap上绘图,然后将位图贴到窗口设备上

 void LogView::paintEvent(QPaintEvent *event)
m_pPix = new QPixmap(size());
QPainter *pMemDc = new QPainter;
m_pPix->fill(Qt::white);
pMemDc->begin(m_pPix);
QPointF point(, );
pMemDc->drawLine()..........
pMemDc->end(); QPainter painter(this);
QPointF pixPoint(, );
painter.drawPixmap(pixPoint, *m_pPix);

  当窗口大小改变时重绘位图m_pPix

 void LogView::resizeEvent(QResizeEvent *event)
void LogView::resizeEvent(QResizeEvent *event)
{
if (height() > m_pPix->height() || width() > m_pPix->width())
{
QPixmap *pNewPix = new QPixmap(size());
pNewPix->fill(Qt::white); QPainter p;
p.begin(pNewPix);
p.drawPixmap(QPoint(,), *m_pPix);
p.end(); m_pPix = pNewPix;
} QWidget::resizeEvent(event);
}

(2)得到设备DPI

QPaintDevice* pDevice = painter.device();
int nDpix = pDevice->logicalDpiX(); // 每英寸多少个点
int nDpiy = pDevice->logicalDpiY();

  若绘图以mm为单位,需得到mm与像素比例:

m_fXRatio = nDpix / 25.4;  // 1mm多少个像素点
m_fYRatio = nDpiy / 25.4;

(3)根据滚动区域和窗口变化设置最大深度和最小深度

void LogView::setDepthOffset(int fOffset)
{
m_fDepthOffset = fOffset / m_fYRatio / m_nCellMM ; m_fMinDepth -= m_fDepthOffset;
if (m_fMinDepth < ) m_fMinDepth = ;
m_fMaxDepth = m_fMinDepth + m_pPix->size().height() / m_fYRatio / m_nCellMM; update(); // 更新视图,重绘
}

10. C++11实现计时器

#ifndef TIMER_H
#define TIMER_H #include <chrono>
using namespace std;
using namespace chrono; class Timer
{
public:
Timer() : m_begin(high_resolution_clock::now()){}
void reset() {m_begin = high_resolution_clock::now();} template<typename Duration=milliseconds>
int64_t elapsed() const
{
return duration_cast<Duration>(high_resolution_clock::now() - m_begin).count();
} // 微妙
int64_t elapsed_micro() const
{
return elapsed<microseconds>();
} // 秒
int64_t elapsed_seconds() const
{
return elapsed<seconds>();
} // 纳秒
int64_t elapsed_nano() const
{
return elapsed<nanoseconds>();
}
private:
time_point<high_resolution_clock> m_begin;
}; #endif // TIMER_H

  计时器使用:

Timer t;
qDebug() << t.elapsed();

源码下载:

  https://pan.baidu.com/s/1dezpcpQDGYxW9Z_4BH3avw

Qt之log数据展示模块简要实现的更多相关文章

  1. 大数据技术之_25_手机APP信息统计系统项目_01_APP 数据生成模块 + 数据收集模块 + 数据处理模块框架搭建 + 业务需求处理 + 数据展示模块 +项目总结 + 问题总结

    一 项目概述1.1 角色1.2 业务术语1.3 项目效果展示二 项目需求三 项目概要3.1 项目技术架构3.2 项目目录结构3.3 项目技术选型3.4 项目整体集群规划3.5 创建项目工程四 APP ...

  2. layui数据表格使用(一:基础篇,数据展示、分页组件、表格内嵌表单和图片)

    表格展示神器之一:layui表格 前言:在写后台管理系统中使用最多的就是表格数据展示了,使用表格组件能提高大量的开发效率,目前主流的数据表格组件有bootstrap table.layui table ...

  3. 手把手教你写带登录的NodeJS爬虫+数据展示

    其实在早之前,就做过立马理财的销售额统计,只不过是用前端js写的,需要在首页的console调试面板里粘贴一段代码执行,点击这里.主要是通过定时爬取https://www.lmlc.com/s/web ...

  4. UITaleView的基础使用及数据展示操作

    UITableView表视图,是实用的数据展示的基础控件,是继承于UIScrollView,所以也可以滚动.但不同于UIScrollView,UITableView只可以上下滚动,而不能左右滚动. 因 ...

  5. 性能测试五十:Jmeter+Influxdb+Grafana实时数据展示系统搭建

    如果用生成jtl文件再分析结果的方式的话,每一次请求就会往jtl里面写一条数据,在进行长时间的稳定性测试的时候,特别是当TPS很高的时候,写入的数据会非常的大,这个时候等稳定性测试完成,再对jtl进行 ...

  6. 服务追踪数据使用 RabbitMQ 进行采集 + 数据存储使用 Elasticsearch + 数据展示使用 Kibana

    服务追踪数据使用 RabbitMQ 进行采集 + 数据存储使用 Elasticsearch + 数据展示使用 Kibana https://www.cnblogs.com/xishuai/p/elk- ...

  7. jQuery 源码分析(十) 数据缓存模块 data详解

    jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...

  8. 万字详解 TDengine 2.0 数据复制模块设计

    ​导读:TDengine分布式集群功能已经开源,集群功能中最重要的一个模块是数据复制(replication),现将该模块的设计分享出来,供大家参考.欢迎大家对着设计文档和GitHub上的源代码一起看 ...

  9. vue+echarts+datav大屏数据展示及实现中国地图省市县下钻

    随着前端技术的飞速发展,大数据时代的来临,我们在开发项目时越来越多的客户会要求我们做一个数据展示的大屏,可以直观的展示用户想要的数据,同时炫酷的界面也会深受客户的喜欢. 大屏展示其实就是一堆的图表能够 ...

随机推荐

  1. VC进程间通信之消息传递PostMessge()或SendMessage()

    1.  进程内消息: (1). 仅仅传消息码 (2). 传送消息串 发送端: void CTestDlg::OnBnClickedButtonSend() { CString* msg = new C ...

  2. leetCode 83.Remove Duplicates from Sorted List(删除排序链表的反复) 解题思路和方法

    Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...

  3. 【转】AngularJs 弹出框 model(模态框)

    原文转至 http://blog.csdn.net/violet_day/article/details/17170585 $modal是一个可以迅速创建模态窗口的服务,创建部分页,控制器,并关联他们 ...

  4. ie6中利用jquery居中

    1.利用jquery居中代码 <script type="text/javascript"> $hwidth=parseInt($(window).width()); ...

  5. 吐血整理:PyTorch项目代码与资源列表 | 资源下载

    http://www.sohu.com/a/164171974_741733   本文收集了大量基于 PyTorch 实现的代码链接,其中有适用于深度学习新手的“入门指导系列”,也有适用于老司机的论文 ...

  6. grunt前端打包——css篇

    [导读] 前端打包的工具有很多,我用的习惯的就是这个grunt,无论是你要在github上做开源,还是让自己的项目变得更易于维护,grunt都是首选. 前端打包的工具有很多,我用的习惯的就是这个gru ...

  7. 讲真,你是因为什么才买华为P20系列手机!

    华为P20系列手机上市两个半月发货600万台!600万台?!看到这个亮瞎我钛合金狗眼的数据,且容我掰着手指脚趾算一下,算了,还是容我毫不夸张的感叹一句吧:华为做手机不用桨,不需风,全靠“浪”……. 两 ...

  8. 使用Erlang和Thrift,与Hbase通信(转)

    操作系统是Ubuntu Server 12.10 先安装Thrift sudo apt-get install libboost-dev libboost-test-dev \ libboost-pr ...

  9. 用array_search 数组中查找是否存在这个 值

    #判读里面是否还有id=1的超级管理员 $key=array_search(1, $ids); #判读这个是否存在 if($key!==FALSE){ #如果存在就unset掉这个 unset($id ...

  10. UVALive 6530 Football (水

    题目链接:点击打开链 #include <cstdio> #include <vector> #include <algorithm> using namespac ...