QT_QCustomPlot学习

Posted Leslie X徐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT_QCustomPlot学习相关的知识,希望对你有一定的参考价值。

QCustomPlot学习

QCustomPlot默认提供了6个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。

1.在一张视图中表现两个线

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)

    ui->setupUi(this);
    demo();


Widget::~Widget()

    delete ui;


void Widget::demo()

    QVector<double> x,y,z;
    for (double i=0;i<10 ;i+=0.1 ) 
        x.append(i);
        y.append(i);
        z.append(i*i);
    
    ui->cw->addGraph();
    ui->cw->graph()->setData(x,y);

    ui->cw->addGraph();
    ui->cw->graph()->setData(x,z);
    ui->cw->graph()->setPen(QPen(QColor(Qt::green)));
    
    ui->cw->graph()->setLineStyle(QCPGraph::LineStyle::lsNone);//设置连线的样式
    ui->cw->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCross, 10));//设置散点的样式,ssCross为十字样式
    ui->cw->graph()->setSelectable(QCP::SelectionType::stMultipleDataRanges);//设置图形中可选的元素,这里配合选择框使用多点选择,可以通过选取框选择多个点,也可以按住ctrl多选

    ui->cw->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables|QCP::iMultiSelect);

    ui->cw->replot();


//可以把矩形框设置放在外面
void Widget::on_checkBox_2_clicked(bool checked)

    if(checked)
        ui->cw->setSelectionRectMode(QCP::SelectionRectMode::srmSelect);//添加鼠标选取矩形框,并设置为选择操作,此时鼠标的拖拽功能失效。按住ctrl可以多选
    else
        ui->cw->setSelectionRectMode(QCP::SelectionRectMode::srmNone);//取消矩形框选取,鼠标拖拽功能返回
        ui->cw->deselectAll();
        ui->cw->replot();
    


2.一张视图中多个图表:使用QCPLayoutGrid

void Widget::demo2()

    //一张视图中多个图表

    //创建QCPAxisRect
    QCPAxisRect* a = new QCPAxisRect (ui->cw);
    QCPAxisRect* b = new QCPAxisRect (ui->cw);

    //添加到QCPLayoutGrid
    ui->cw->plotLayout()->clear();
    QCPLayoutGrid* lay = ui->cw->plotLayout() ;
    lay->addElement(0,0,a);
    lay->addElement(1,0,b);


    //创建数据
    QVector<QCPGraphData> d1,d2;
    for (double i=0;i<10 ;i+=0.1 ) 
        d1.append(QCPGraphData(i,i));
        d2.append(QCPGraphData(i,i*i));
    

    //创建数据,添加到QCPGraph
    QCPGraph* ga = ui->cw->addGraph(a->axis(QCPAxis::atBottom),a->axis(QCPAxis::atLeft));
    ga->data()->set(d1);
    ga->rescaleAxes();

    QCPGraph* gb = ui->cw->addGraph(b->axis(QCPAxis::atBottom),b->axis(QCPAxis::atLeft));
    gb->data()->set(d2);
    gb->rescaleAxes();

    //同时改变X轴大小,可以用来进行对比
    ui->cw->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables);
    
    connect(ga->keyAxis(),SIGNAL(rangeChanged(QCPRange)),gb->keyAxis(),SLOT(setRange(QCPRange)));
    connect(gb->keyAxis(),SIGNAL(rangeChanged(QCPRange)),ga->keyAxis(),SLOT(setRange(QCPRange)));
    
    ui->cw->axisRect(0)->setRangeZoom(Qt::Horizontal);
    ui->cw->axisRect(1)->setRangeZoom(Qt::Horizontal);

同步X轴大小:

  
//同时改变X轴大小,可以用来进行对比
    ui->cw->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables);

    for(int i=0 ; i < ui->cw->graphCount(); ++i)
         connect(ui->cw->graph(i)->keyAxis(),SIGNAL(rangeChanged(QCPRange)),this,SLOT(setXRange(QCPRange)));
        ui->cw->axisRect(i)->setRangeZoom(Qt::Horizontal);
    


void Widget::setXRange(QCPRange range)

    for(int i=0 ; i < ui->cw->graphCount(); ++i)
        ui->cw->graph(i)->keyAxis()->setRange(range);
    

添加checkbox是否同步:

void Widget::on_checkBox_clicked(bool checked)

    if(checked)
        for(int i=0 ; i < ui->cw->graphCount(); ++i)
             connect(ui->cw->graph(i)->keyAxis(),SIGNAL(rangeChanged(QCPRange)),this,SLOT(setXRange(QCPRange)));
             ui->cw->axisRect(i)->setRangeZoom(Qt::Horizontal);
             ui->cw->axisRect(i)->setRangeDrag(Qt::Horizontal);
             ui->cw->graph(i)->rescaleAxes();
        
    else
        for(int i=0 ; i < ui->cw->graphCount(); ++i)
             disconnect(ui->cw->graph(i)->keyAxis(),SIGNAL(rangeChanged(QCPRange)),this,SLOT(setXRange(QCPRange)));
             ui->cw->axisRect(i)->setRangeZoom(Qt::Horizontal|Qt::Vertical);
             ui->cw->axisRect(i)->setRangeDrag(Qt::Horizontal|Qt::Vertical);
        
    

遗憾的是,现在QCPLayoutGrid这个方法还没找到有QSplitter这样可以分割的部件实现调整窗口的大小。

3.一张视图中多个图表:使用QSplitter

使用两个QCustomPlot窗口,加上一个QSplitter实现调整大小

void Widget::demo3()

    ui->cw->plotLayout()->clear();
    //创建数据
    QVector<QCPGraphData> d1,d2,d3;
    for (double i=0;i<10 ;i+=0.1 ) 
        d1.append(QCPGraphData(i,i));
        d2.append(QCPGraphData(i,i*i));
        d3.append(QCPGraphData(i,qSqrt(i)));
    

    QCustomPlot* qcp1 = new QCustomPlot();
    QCustomPlot* qcp2 = new QCustomPlot();
    QCustomPlot* qcp3 = new QCustomPlot();

    qcp1->addGraph()->data()->set(d1);
    qcp2->addGraph()->data()->set(d2);
    qcp3->addGraph()->data()->set(d3);

    qcp1->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables);
    qcp2->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables);
    qcp3->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom|QCP::iSelectPlottables);

    /*QSplitter**/ pSplitter = new QSplitter(Qt::Vertical,this);
    pSplitter->addWidget(qcp1);
    pSplitter->addWidget(qcp2);
    pSplitter->addWidget(qcp3);
    ui->show->addWidget(pSplitter); //注意这里的 ui->show为 QGridLayout类型

    QCustomPlot* q = nullptr;
    for(int i=0;i < pSplitter->count();++i)
        q = static_cast<QCustomPlot*>(pSplitter->widget(i));
        connect(q->graph()->keyAxis(),SIGNAL(rangeChanged(QCPRange)),this,SLOT(set3Range(QCPRange)));
    



void Widget::set3Range(QCPRange range)

    QCustomPlot* q = nullptr;
    for(int i=0;i < pSplitter->count();++i)
        q = static_cast<QCustomPlot*>(pSplitter->widget(i));
        q->graph()->keyAxis()->setRange(range);
        q->replot();
    


4.时间轴

double now = QDateTime::currentDateTime().toSecsSinceEpoch();
QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime);
dateTicker->setDateTimeFormat("d MMMM\\n yyyy");
ui->cw->xAxis2->setTicker(dateTicker);
ui->cw->xAxis2->setRange(now,now+24*3600*10);
ui->cw->xAxis2->setVisible(true);

5.实现鼠标左键选框,中键平移,右键菜单

以下鼠标键都在qcustomplot.cpp中修改,注意不要搞错成员函数所在的类名

左键选框:

把官方的框选功能限制在左键上,在函数void QCustomPlot::mousePressEvent(QMouseEvent *event)中修改如下:

void QCustomPlot::mousePressEvent(QMouseEvent *event)

  emit mousePress(event);
  // save some state to tell in releaseEvent whether it was a click:
  mMouseHasMoved = false;
  mMousePressPos = event->pos();
  //添加 event->button() == Qt::LeftButton ,将选取框按键绑定在左键
  if (event->button() == Qt::LeftButton && mSelectionRect && mSelectionRectMode != QCP::srmNone)
  
    if (mSelectionRectMode != QCP::srmZoom || qobject_cast<QCPAxisRect*>(axisRectAt(mMousePressPos))) // in zoom mode only activate selection rect if on an axis rect
      mSelectionRect->startSelection(event);
   else if(event->button() != Qt::LeftButton)//添加if
  //...
  

中键平移:

官方默认左键是平移曲线,我们把平移功能改到中键上去,以便右键菜单。直接在函数
void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)改,把Qt::LeftButton改成Qt::RightButton即可。

void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)

  Q_UNUSED(details)
  if (event->buttons() & Qt::midButton)//将Qt::LeftButton改成你要绑定的拖拽的按键
  
      //...
  

右键菜单:

void demo()
    ui->cw->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->cw,&QCustomPlot::customContextMenuRequested,this,&Widget::MenuRequested);


void Widget::MenuRequested(QPoint p)

    QMenu *menu = new QMenu(this);
    menu->setAttribute(Qt::WA_DeleteOnClose);
    menu->addAction("resize",this,[=]()
        ui->cw->rescaleAxes();
        ui->cw->replot();
    );
    menu->addAction("zoom",this,[=]()
        ui->cw->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    );
    menu->addAction("select",this,[=]()
        ui->cw->setSelectionRectMode(QCP::SelectionRectMode::srmSelect);
    );
    menu->addAction("None",this,[=]()
        ui->cw->setSelectionRectMode(QCP::SelectionRectMode::srmNone);
    );
    menu->popup(ui->cw->mapToGlobal(p));//必须要,否则不显示菜单

写进新的类:plotView

//hpp
#include "../../plotLib/qcustomplot.h"
class plotView : public QCustomPlot

public:
    plotViewHalcon三 依据点关系计算物体三维位姿Halcon

监督机器学习:数据点数量和变量之间的关系

机器学习1-关于回归问题的准确性评价

[ML]简单的Normal Equation对数据点进行线性回归

facets学习:什么是facets

资源|常用聚类算法学习推荐