Qt之log数据展示模块简要实现

摘要:
Log模块主要用于实时测井数据的显示和测后曲线数据的预览和打印,为更好的展示对Qt中相关知识点的应用,特以Log模块为例对其进行简要实现。最终选择在QWidget上进行双缓存绘图。

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

内容导图:

Qt之log数据展示模块简要实现第1张

一、功能需求

1、界面效果图

Qt之log数据展示模块简要实现第2张

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、整体架构设计

Qt之log数据展示模块简要实现第3张

3. UML类图设计

(1)MainWindow布局

Qt之log数据展示模块简要实现第4张

(2)类图

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

Qt之log数据展示模块简要实现第5张

三、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 = newScrollArea;

    m_pTrackView = newTrackView(pSplitter);
m_pScrollArea->setBackgroundRole(QPalette::Light);     //添加滚动条
    m_pScrollArea->setWidget(m_pTrackView);
    m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    //logview视图窗口
    m_pLogView = newLogView(pSplitter);
    m_pLogScrollArea = newScrollArea;
    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(0, 1);  //设置分隔比例
    pSplitter->setStretchFactor(1, 4);
    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)定义自定义类型,如classQTrack

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

    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 : publicQScrollArea
{
    Q_OBJECT

public:
    explicit ScrollArea(QWidget *parent =Q_NULLPTR);
    ~ScrollArea();

    void scrollContentsBy(int dx, intdy) Q_DECL_OVERRIDE;
};
#include "scrollarea.h"#include "logview.h"
#include <QScrollBar>
ScrollArea::ScrollArea(QWidget *parent)
    :QScrollArea(parent)
{

}

ScrollArea::~ScrollArea()
{

}

void ScrollArea::scrollContentsBy(int dx, intdy)
{
    m_pLogView->setDepthOffset(dy);
    returnQScrollArea::scrollContentsBy(dx,dy);
}

voidScrollArea::setStep(qreal fRatioY)
{
    QScrollBar *pScrollBar =verticalScrollBar();
    pScrollBar->setSingleStep(fRatioY * 25);   //25mm
    pScrollBar->setPageStep(fRatioY * 50);    //50mm
}

(2)为QWidget添加滚动条

m_pLogScrollArea = newScrollArea;
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 = newQPixmap(size());    
QPainter *pMemDc = newQPainter;
m_pPix->fill(Qt::white);
pMemDc->begin(m_pPix);
QPointF point(10, 0);
pMemDc->drawLine()..........
pMemDc->end();

QPainter painter(this);
QPointF pixPoint(0, 0);
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 = newQPixmap(size());
        pNewPix->fill(Qt::white);

        QPainter p;
        p.begin(pNewPix);
        p.drawPixmap(QPoint(0,0), *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(intfOffset)
{
    m_fDepthOffset = fOffset / m_fYRatio /m_nCellMM ;

    m_fMinDepth -=m_fDepthOffset;
    if (m_fMinDepth < 0) m_fMinDepth = 0;
    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 namespacestd;
using namespacechrono;

classTimer
{
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数据展示模块简要实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【网络开发】组播问题分析python之tkinter使用-复选框操作下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Apache/Nginx/IIS 访问日志详解

Apache日志详解 1.Apache日志文件名称及所在路径 日志文件一般都是保存在在apache/logs目录下,实际情况可以根据Apache的配置文件去查找日志文件所在的路径。 例如phpstudy(windows)在 :phpstudy/Extensions/apache/logs; wdcp(linux)在 :www/wdlinux/apache/...

docker 日志在常见系统中的查看方法

1、查看docker日志的方法: 1) ubuntu(14.04)   /var/log/upstart/docker.log 2) ubuntu(16.04)   journalctl -u docker.service 3) centos7/rhel7     journalctl -u docker.service 4) coreos        ...

基于Docker的主从复制搭建

利用Docker搭建主从服务器 首先拉取docker镜像,我们这里使用5.7版本的mysql: docker pull mysql:5.7.19 然后使用此镜像启动容器,这里需要分别启动主从两个容器 Master(主): docker run -p 3339:3306 --name mymysql -e MYSQL_ROOT_PASSWORD=12345...

Promise.resolve解析

总结自:https://blog.csdn.net/lq15310444798/article/details/81275278 Promise.resolve返回一个Promise实例 参数分4种情况: 1.参数为Promise实例 返回此实例 可能执行catch ---------------------------------------------...

MySQL查询截取分析

一、查询优化 1,mysql的调优大纲 慢查询的开启并捕获 explain+慢SQL分析 show profile查询SQL在Mysql服务器里面的执行细节和生命周期情况 SQL数据库服务器的参数调优 2,小表驱动大表 mysql的join实现原理是,以驱动表的数据为基础,“嵌套循环”去被驱动表匹配记录。驱动表的索引会失效,而被驱动表的索引有效。 #假...

C++开源库详细介绍

C++在“商业应用”方面,曾经是天下第一的开发语言,但这一桂冠已经被java抢走多年。因为当今商业应用程序类型,已经从桌面应用迅速转移成Web应 用。当Java横行天下之后,MS又突然发力,搞出C#语言,有大片的曾经的C++程序员,以为C++要就此沉沦,未料,这三年来,C++的生命力突然被 严重地增强了。主力原因就是开源的软件、基础软件(比如并发原生支持,...