QwtPlot类是一个二维绘图部件,继承自QFrame 和 QwtPlotDict。不过严格的说来,它只是一个视图窗口,真正的绘制设备是它的中心部件QwtPlotCanvas类。在QwtPlot的画布上可以显示不限数量的图元项(plot items)。这些图元项可以是曲线(QwtPlotCurve),标签(QwtPlotMarker),网格(QwtPlotGrid),或者其它任意的从QwtPlotItem派生出来的子类。 一个QwtPlot有四条坐标抽,每一个项都依附于X轴或者Y轴。每一个轴的刻度可以通过set (QwtScaleDiv)或者根据绘制的图元通过算法(QwtScaleEngine)单独配置。
QwtPlotDict类是一个Item的字典,用于管理添加到QwtPlot上的所有图元项。QwtPlotDict 按照Z值的递增顺序组织items. 如果autoDelete()设置为可用,所有依附的items会在QwtPlotDict的析构函数中被删除。
QwtPlotCanvas类:QwtPlot的画布【Canvas of a QwtPlot】,继承自QFrame。
在QwtPlot上所有图元(QwtPlotItem)的绘制都是源于QwtPlotCanvas类的paintEvent(). paintEvent()调用QwtPlotCanvas::drawCanvas(), QwtPlotCanvas::drawCanvas() 调用 QwtPlot::drawCanvas( QPainter *painter ), QwtPlot::drawCanvas( QPainter *painter )会调用QwtPlot::drawItems(), QwtPlot::drawItems()会调用所有图元的纯虚函数QwtPlotItem::draw() = 0; 绘制图元自己。
因此,从上面的绘制流程来看,QwtPlot只是一个呈现图元的视口,相当于View; 而QwtPlotCanvas 才是真正的画布(即绘制设备),它是QwtPlot的一个成员,或者说中心部件,用于展现所有的图元,相当于QGraphicsView::setViewport( QWidget * widget ); 【从QAbstractScrollArea继承而来】中的widget;QwtPlotDict是一个非常重要的类,它被QwtPlot继承,用于协助QwtPlot管理所有的图元项,感觉相当于Scene; QwtPlotItem 即为图元,相当于Item。
如何添加一个图元?看看这两个接口的具体实现:
/*! \brief Attach the item to a plot. This method will attach a QwtPlotItem to the QwtPlot argument. It will first detach the QwtPlotItem from any plot from a previous call to attach (if necessary). If a NULL argument is passed, it will detach from any QwtPlot it was attached to. \param plot Plot widget \sa detach() */ void QwtPlotItem::attach( QwtPlot *plot ) { if ( plot == d_data->plot ) return; // remove the item from the previous plot if ( d_data->plot ) { if ( d_data->plot->legend() ) d_data->plot->legend()->remove( this ); d_data->plot->attachItem( this, false ); if ( d_data->plot->autoReplot() ) d_data->plot->update(); } d_data->plot = plot; if ( d_data->plot ) { // insert the item into the current plot d_data->plot->attachItem( this, true ); itemChanged(); // 这个函数里面实现了QwtPlot的更新和图元对应示例图QwtLegendItem的更新 } } /*! \brief This method detaches a QwtPlotItem from any QwtPlot it has been associated with. detach() is equivalent to calling attach( NULL ) \sa attach() */ void QwtPlotItem::detach() { attach( NULL ); }
再看看itemChanged()的实现代码,有助于我们理解QwtPlotItem 和 QwtLegend 是如何实现绑定的。
/*! Update the legend and call QwtPlot::autoRefresh for the parent plot. \sa updateLegend() */ void QwtPlotItem::itemChanged() { if ( d_data->plot ) { if ( d_data->plot->legend() ) updateLegend( d_data->plot->legend() ); d_data->plot->autoRefresh(); } }
上面的updateLegend()是在QwtLegendItemManager中定义的纯虚函数:
virtual void QwtLegendItemManager::updateLegend( QwtLegend *legend ) const = 0;
在QwtPlotItem及其派生类中会根据需要重新实现updateLegend( QwtLegend *legend )函数,实现代码中会为QwtPlotItem在QwtLegend中创建(通过legendItem())对应的示例图示。
而legendItem()是在QwtLegendItemManager中定义的纯虚函数:
virtual QWidget *legendItem() const = 0;