【问题标题】:QCustomPlot replot QCPLayerQCustomPlot 重新绘制 QCPLayer
【发布时间】:2018-03-25 16:03:44
【问题描述】:

我正在尝试弄清楚如何使用 QCPLayer 仅重新绘制图中的某些项目。

qcustomplot documentation 声明如下:

如果你经常需要调用一个完整的 QCustomPlot::replot 只是因为一个非复杂对象(例如一个项目)发生了变化,而绘图中有相对静态但复杂的图形,请考虑将定期变化的对象放在自己的层上并将其模式 (QCPLayer::setMode) 设置为 QCPLayer::lmBuffered。这使得 QCustomPlot 为该层分配一个专用的绘制缓冲区,并允许使用 QCPLayer::replot 单独重新绘制它,独立于包含潜在复杂和缓慢图形的其他层。有关详细信息,请参阅相应方法的文档。

这是我在下面的示例中尝试做的事情:

我正在通过从QCustomPlot 继承来创建 custom qcustomplot:

QCustomPlot_custom.h

#pragma once
#include "qcustomplot.h"    
#define USING_LAYER false

struct QCPCursor{
   QCPItemLine *hLine;
   QCPItemLine *vLine;
   QCPItemText* cursorText;
};

class QCustomPlot_custom :
   public QCustomPlot
{
   Q_OBJECT    
private slots:
   void mouseMove(QMouseEvent*);

public:
   QCustomPlot_custom(QWidget* parent = NULL);
   ~QCustomPlot_custom(){}
private:
   QCPLayer* cursorLayer;
   QCPCursor cursor;   
   void manageCursor(double x, double y, QPen pen);
public:
   void init(QVector<double> xdata, QVector<double> ydata);
};

这个类用一些要绘制的数据进行初始化。它还重载mouseMove 事件来控制自定义光标。 USING_LAYER 设置为true 表示自定义光标添加到它自己的层(cursorLayer)。

通过将 USING_LAYER 设置为 false,我得到了如下所示的预期效果:

光标由水平和垂直线和坐标显示。

如果我在图中有很多图表和/或每个图表中有很多点,我会在移动光标时看到延迟。 (这就是我希望能够通过将光标设置在图层中来仅重新绘制光标的原因。)

QCustomPlot_custom.cpp

QCustomPlot_custom::QCustomPlot_custom(QWidget* parent)
{
   connect(this, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove(QMouseEvent*)));   
   QCustomPlot::setInteraction(QCP::iRangeDrag, true);
   QCustomPlot::setInteraction(QCP::iRangeZoom, true);
   if (USING_LAYER){
      this->addLayer("cursorLayer", 0, QCustomPlot::limAbove);
      cursorLayer = new QCPLayer(this, "cursorLayer");
      cursorLayer->setMode(QCPLayer::lmBuffered);
   }
}

void QCustomPlot_custom::init(QVector<double> xdata, QVector<double> ydata)
{   
   this->addGraph();
   this->graph(0)->setData(xdata, ydata);

   QColor colorPen(10, 25, 180, 255);
   QPen pen;
   pen.setWidth(50);
   pen.setColor(colorPen);
   this->graph()->setLineStyle(QCPGraph::lsLine);
   this->graph()->setPen(QPen(colorPen));
   this->xAxis->setLabel("X-axis");
   this->yAxis->setLabel("Y-axis");      
   this->rescaleAxes();
   this->replot();
}

void QCustomPlot_custom::mouseMove(QMouseEvent* event)
{
   //Cursor coordinates:
   double x = this->xAxis->pixelToCoord(event->pos().x());
   double y = this->yAxis->pixelToCoord(event->pos().y());
   manageCursor(x, y, QPen(Qt::DashDotLine));            
   if (USING_LAYER)
      cursorLayer->replot(); 
   else
      this->replot();
}

void QCustomPlot_custom::manageCursor(double x, double y, QPen pen)
{
   if (cursor.hLine)
      this->removeItem(cursor.hLine);
   cursor.hLine = new QCPItemLine(this);   
   cursor.hLine->setPen(pen);
   cursor.hLine->start->setCoords(-QCPRange::maxRange, y);
   cursor.hLine->end->setCoords(QCPRange::maxRange, y);

   if (cursor.vLine)
      this->removeItem(cursor.vLine);
   cursor.vLine = new QCPItemLine(this);   
   cursor.vLine->setPen(pen);
   cursor.vLine->start->setCoords(x, -QCPRange::maxRange);
   cursor.vLine->end->setCoords(x, QCPRange::maxRange);

   //Coordinates as text:   
   if (cursor.cursorText)
      this->removeItem(cursor.cursorText);
   cursor.cursorText = new QCPItemText(this);
   cursor.cursorText->setText(QString("(%1, %2)").arg(x).arg(y));
   cursor.cursorText->position->setCoords(QPointF(x, y));
   QPointF pp = cursor.cursorText->position->pixelPosition() + QPointF(50.0, -15.0);
   cursor.cursorText->position->setPixelPosition(pp);
   cursor.cursorText->setFont(QFont(font().family(), 8));

   //Add to layer:
   if (USING_LAYER){
      cursor.hLine->setLayer(cursorLayer); 
      cursor.vLine->setLayer(cursorLayer); 
      cursor.cursorText->setLayer(cursorLayer);
   }
}

初始化类成员的函数:

void Qt_PlotTest::testPlot(){
   //Create some data and initalize plot:
   QVector<double> yData, xData;
   int imax = 100000;
   for (int i = 0; i < imax; i++){
      double x = double(i) / imax;
      xData.push_back(x);
      yData.push_back(pow(x, 2)*( 1.0 + 0.5*cos(20*x) + 0.1*sin(500*x - 0.1)));
   }
   ui.custom_QWidgetPlot->init(xData, yData);
}

使用 layer 方法时,光标不渲染。我尝试理解文档,但我不清楚如何正确使用QCPLayers。

我应该怎么做?

【问题讨论】:

    标签: c++ qt qcustomplot


    【解决方案1】:

    添加图层后

    this->addLayer("cursorLayer", 0, QCustomPlot::limAbove);
    

    不要调用QCPLayer 构造函数来获取层指针。使用提供的带有层或索引名称的 getter:

    QCPLayer * QCustomPlot::layer ( const QString & name) const

    QCPLayer * QCustomPlot::layer ( int index) const

    cursorLayer = this->layer("cursorLayer");
    

    还将每个 Graph 和 Item 添加到 currentLayer 中,在您的情况下,它不是 cursorLayer,而是 main。您需要更改当前图层

    bool QCustomPlot::setCurrentLayer ( const QString & name)

    bool QCustomPlot::setCurrentLayer ( QCPLayer * layer)

    即:

    this->setCurrentLayer("cursorLayer");
    this->addGraph();
    ...
    this->setCurrentLayer("main");
    

    或者你可以为每个QCPLayerable指定层

    bool QCPLayerable::setLayer ( QCPLayer * layer)

    bool QCPLayerable::setLayer ( const QString & layerName)

    someGraph->setLayer("cursorLayer);
    

    【讨论】:

    • 我试过cursorLayer = this-&gt;layer("cursorLayer");。在QCustomPlot_custom::manageCursor 中创建hlinevlinecursorText 之前,我还尝试了this-&gt;setCurrentLayer("cursorLayer");,并使用f.ex 将每个项目设置为图层。 hline-&gt;setLayer("cursorLayer);。现在发生的情况是,我的光标仅在我缩放或拖动视图时才会呈现(因为可能会调用 this-&gt;replot())。如果我调试并深入研究cursorLayer-&gt;replot(),我发现它失败了,因为bool QCustomPlot::hasInvalidatedPaintBuffers() 返回true
    • 我不确定为什么要在每个 mouseMove(QMouseEvent* event) 之后删除并再次创建游标。在init中创建一次,然后在mouseMove中调用setCoords
    • 我同意。该方法取自某处的不同示例。我只是想在更改之前解决此重新绘制问题。但是,如果我总是在重新创建光标后将其添加到图层中,它不应该对这个问题产生影响。但也许,我会仔细看看。
    【解决方案2】:

    正如@EligijusPupeikis 提醒我的那样,我每次移动光标时都会删除并重新创建光标。

    我认为这不会对我的问题产生任何影响,但显然确实如此,因为重新绘制包含新项目的图层需要先重新绘制绘图(来源:将检查 qcustomplot文档并添加链接)。

    所以我的代码现在看起来像这样:

    QCustomPlot_custom::QCustomPlot_custom(QWidget* parent)
    {
       connect(this, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove(QMouseEvent*)));   
       QCustomPlot::setInteraction(QCP::iRangeDrag, true);
       QCustomPlot::setInteraction(QCP::iRangeZoom, true);
    }
    
    void QCustomPlot_custom::init(QVector<double> xdata, QVector<double> ydata)
    {   
       this->addGraph();
       this->graph(0)->setData(xdata, ydata);
    
       QColor colorPen(10, 25, 180, 255);
       QPen pen;
       pen.setWidth(50);
       pen.setColor(colorPen);
       this->graph()->setLineStyle(QCPGraph::lsLine);
       this->graph()->setPen(QPen(colorPen));
       this->xAxis->setLabel("X-axis");
       this->yAxis->setLabel("Y-axis");      
       this->rescaleAxes();
       this->replot();
    
       if (USING_LAYER){
          this->addLayer("cursorLayer", 0, QCustomPlot::limAbove);
          cursorLayer = this->layer("cursorLayer");
          //cursorLayer = new QCPLayer(this, "cursorLayer");
          cursorLayer->setMode(QCPLayer::lmBuffered);
       }
    
       //Cursor:
       QPen qpen = QPen(Qt::DashDotLine);
       cursor.hLine = new QCPItemLine(this);
       cursor.hLine->setPen(qpen);
       cursor.vLine = new QCPItemLine(this);
       cursor.vLine->setPen(qpen);
       cursor.cursorText = new QCPItemText(this);
       cursor.cursorText->setFont(QFont(font().family(), 8));
    
       //Add to layer:
       if (USING_LAYER){
          cursor.hLine->setLayer("cursorLayer");  //"cursorLayer"
          cursor.vLine->setLayer("cursorLayer");
          cursor.cursorText->setLayer("cursorLayer");
       }
    
    }
    
    void QCustomPlot_custom::mouseMove(QMouseEvent* event)
    {
       //Cursor coordinates:
       double x = this->xAxis->pixelToCoord(event->pos().x());
       double y = this->yAxis->pixelToCoord(event->pos().y());
       manageCursor(x, y);            
       if (USING_LAYER)
          this->layer("cursorLayer")->replot();
       else
          this->replot();
    }
    
    void QCustomPlot_custom::manageCursor(double x, double y)
    {
       cursor.hLine->start->setCoords(-QCPRange::maxRange, y);
       cursor.hLine->end->setCoords(QCPRange::maxRange, y);
    
       cursor.vLine->start->setCoords(x, -QCPRange::maxRange);
       cursor.vLine->end->setCoords(x, QCPRange::maxRange);
    
       cursor.cursorText->setText(QString("(%1, %2)").arg(x).arg(y));
       cursor.cursorText->position->setCoords(QPointF(x, y));
       QPointF pp = cursor.cursorText->position->pixelPosition() + QPointF(50.0, -15.0);      
     cursor.cursorText->position->setPixelPosition(pp);
    }
    

    作为测试,如果我绘制 10 000 000 个点,并将 USING_LAYER 设置为 false,我会在移动鼠标时注意到光标明显滞后。将其设置为true 时,将导致平滑的光标移动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      相关资源
      最近更新 更多