赞
踩
一直说要讲2.0.0版本,但总是想把1.3.2版本拿出来比较一下,这篇文章也不例外。QCustomPlot2.0.0beta版本比1.3.2release版本有一个很大的改进那就是分层绘制,所谓分层绘制就是把一张图分几张图来绘制,最后在把这分开的几张图统一绘制到一张图上,比如一张图A,需要分开成3张图B、C和D来绘制,当图A需要重新绘制时,我们一次判断B、C和D是否需要重新绘制,如果不需要绘制的我们直接把图贴到A上,那就很大的减少了重新绘制的时间,而这部分时间其实是没有必要花费的。
QCustomPlot默认提供了6个层,如下代码所示,分别是:背景层、网格层、主层、坐标轴层、图例层和矩形选择区域层。
- mLayers.append(new QCPLayer(this, QLatin1String("background")));
- mLayers.append(new QCPLayer(this, QLatin1String("grid")));
- mLayers.append(new QCPLayer(this, QLatin1String("main")));
- mLayers.append(new QCPLayer(this, QLatin1String("axes")));
- mLayers.append(new QCPLayer(this, QLatin1String("legend")));
- mLayers.append(new QCPLayer(this, QLatin1String("overlay")));
实现分层绘制的关键类QCPAbstractPaintBuffer,这是一个抽象基类,通过该类可以拿到一个QCPPainter指针,然后绘制东西的时候,都会绘制在这个指针所指的绘图设备上。QCPAbstractPaintBuffer类一共有3个子类,分别是QCPPaintBufferPixmap、QCPPaintBufferGlPbuffer和QCPPaintBufferGlFbo,这3个类分别使用了不同绘图技术来实现分层绘制。默认使用的是QCPPaintBufferPixmap来绘制,如果想使用QCPPaintBufferGlPbuffer或者QCPPaintBufferGlFbo来绘制,首先要使用setOpenGl接口打开使用opengl开关,然后定义QCP_OPENGL_FBO宏来默认使用QCPPaintBufferGlFbo绘制,或者定义QCP_OPENGL_PBUFFER宏来让默认使用QCPPaintBufferGlPbuffer方式绘制
下图所示是QCPLayer图层类的部分头文件,代码里的大多数成员变量和成员方法我都给出了注释,大家看看并仔细揣摩一下,应该就基本能理解了。
- class QCP_LIB_DECL QCPLayer : public QObject
- {
- enum LayerMode {//分层绘制原理
- lmLogical ///< Layer is used only for rendering order, and shares paint buffer with all other adjacent logical layers.
- , lmBuffered ///< Layer has its own paint buffer and may be replotted individually (see \ref replot).
- };
-
- QCPLayer(QCustomPlot* parentPlot, const QString &layerName);
- virtual ~QCPLayer();
-
- // setters:
- void setVisible(bool visible);//设置层是否可见
- void setMode(LayerMode mode);//绘制时,painter使用模式
-
- // non-virtual methods:
- void replot();//重新绘制层
-
- protected:
- QCustomPlot *mParentPlot;//所在图表
- QString mName;//层名称
- int mIndex;//层序,决定绘制先后顺序
- QList<QCPLayerable*> mChildren;//层中所有元素
- bool mVisible;//是否可见标记
- LayerMode mMode;//绘制模式标记
-
- // non-property members:
- QWeakPointer<QCPAbstractPaintBuffer> mPaintBuffer;//绘制缓冲区
-
- // non-virtual methods:
- void draw(QCPPainter *painter);//使用painter绘制
- void drawToPaintBuffer();//绘制到缓冲区
- void addChild(QCPLayerable *layerable, bool prepend);//新增元素
- void removeChild(QCPLayerable *layerable);//移除元素
- };
如图1中所示的黑色十字线,就是我在自定义层中绘制的,下面我将我实现的代码贴出来
图1
实现头文件
- class CrossLinePlot : public QCPLayerable
- {
- Q_OBJECT
- signals :
- void DrawCrossLine(const QPoint & pos);
-
- public:
- CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot);
- ~CrossLinePlot();
-
- public:
- QString LayerName() const;//层名称
- void SetVisible(bool visible);//设置层是否绘制
-
- void SetPen(const QPen & pen);/设置十字线画笔
-
- bool MouseButtonDown() const ;
- bool GetLineVisible(QCP::LineState line) const;
- void SetLineShow(QCP::LineState lines);//设置线是否显示
-
- //十字线同步注册接口
- bool RegisiterBortherLine(CrossLinePlot * line);
- bool UnregisiterBortherLine(CrossLinePlot * line);
-
- protected:
- virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const{};
- virtual void draw(QCPPainter * painter);
-
- private:
- void DrawLine(QCPAxis * axis, Qt::Orientation orientation);//画指定方向的坐标轴十字线(严格来说应该是一部分,一条线)
- void SyncLinePosition(const QPoint & pos, double x);//同步线位置
-
- private slots:
- void MouseMoveHandle(QMouseEvent * event);
-
- private:
- QScopedPointer<CrossLinePlotPrivate> d_ptr;
- static std::vector<CrossLinePlot *> m_BrotherLine;//同步其他十字线
- };
实现文件
- std::vector<CrossLinePlot *>CrossLinePlot::m_BrotherLine;
-
- struct CrossLinePlotPrivate
- {
- QCP::LineStates m_bIsVisible;
- bool m_bLeftButtonPress = false;
- double m_dAxisXValue = -1;
- QPoint m_MousePoint;
- QCPPainter * m_pPainter = nullptr;
- QPen m_Pen = QPen(Qt::black, 1, Qt::DashDotLine);
- PlotCallback * m_pParentPlot = nullptr;
- };
-
- CrossLinePlot::CrossLinePlot(PlotCallback * basePlot, QCustomPlot * plot)
- : QCPLayerable(plot)
- , d_ptr(new CrossLinePlotPrivate)
- {
- d_ptr->m_pParentPlot = basePlot;
- mParentPlot->addLayer(LayerName());
-
- setLayer(LayerName());
-
- connect(mParentPlot, &QCustomPlot::mousePress, this, [this](QMouseEvent * event){
- if (event->button() & Qt::LeftButton)
- {
- d_ptr->m_bLeftButtonPress = true;
- }
- });
- connect(mParentPlot, &QCustomPlot::mouseRelease, this, [this](QMouseEvent * event){
- if (event->button() & Qt::LeftButton)
- {
- d_ptr->m_bLeftButtonPress = false;
- }
- });
- connect(mParentPlot, &QCustomPlot::mouseMove, this, &CrossLinePlot::MouseMoveHandle);
-
- QVector<qreal> dashes;
- qreal space = 4;
- dashes << 3 << space << 9 << space;
- d_ptr->m_Pen.setDashPattern(dashes);
- }
-
- CrossLinePlot::~CrossLinePlot()
- {
-
- }
-
- QString CrossLinePlot::LayerName() const
- {
- return QStringLiteral("crossline");
- }
-
- void CrossLinePlot::SetVisible(bool visible)
- {
- QCPLayer * layer = mParentPlot->layer(LayerName());
- if (layer)
- {
- layer->setVisible(visible);
- }
- }
-
- void CrossLinePlot::SetPen(const QPen & pen)
- {
- d_ptr->m_Pen = pen;
- }
-
- bool CrossLinePlot::MouseButtonDown() const
- {
- return d_ptr->m_bLeftButtonPress;
- }
-
- bool CrossLinePlot::GetLineVisible(QCP::LineState line) const
- {
- switch (line)
- {
- case Qt::Horizontal:
- return d_ptr->m_bIsVisible.testFlag(QCP::E_Horizontal);
- break;
- case Qt::Vertical:
- return d_ptr->m_bIsVisible.testFlag(QCP::E_Vertical);
- break;
- }
-
- return false;
- }
-
- void CrossLinePlot::SetLineShow(QCP::LineState lines)
- {
- switch (lines)
- {
- case QCP::E_NULL:
- d_ptr->m_bIsVisible = QCP::E_NULL;
- break;
- case QCP::E_Horizontal:
- d_ptr->m_bIsVisible = QCP::E_Horizontal;
- break;
- case QCP::E_Vertical:
- d_ptr->m_bIsVisible = QCP::E_Vertical;
- break;
- case QCP::E_ALL:
- d_ptr->m_bIsVisible = QCP::E_ALL;
- break;
- }
-
- if (QCPLayer * layer = mParentPlot->layer(LayerName()))
- {
- layer->replot();
- }
-
- if (d_ptr->m_bIsVisible == QCP::E_NULL)
- {
- for (CrossLinePlot * crossline : CrossLinePlot::m_BrotherLine)
- {
- if (crossline != this)
- {
- crossline->SyncLinePosition(QPoint(), d_ptr->m_dAxisXValue);
- }
- }
- }
- }
有兴趣的同学可以自行看实现文件,代码都不难理解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。