基于QWT实现示波器余晖绘图模式

本文介绍了如何基于Qwt库重写QwtPlotCanvas类以实现示波器的余晖绘图功能。通过利用Qwt的BackingStore模式和自定义绘图模式,作者在位图缓存中保存历史数据,从而达到余晖效果。文章提供详细代码实现,包括MyPlotCanvas类的设计和关联QwtPlot的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Qwt提供了强大的图形绘制的功能,Qwt自带的refreshtest例子可以比较全面的展示了采用Qwt绘制动态曲线的功能。Qwt可以用来实现示波器的实时波形绘制,但示波器的余晖模式无法用Qwt的原生库来实现,因此,作者研究了Qwt绘图源码,通过重写QwtPlotCanvas类实现了示波器的余晖绘图功能,由于采用的是基于位图的实现方式,可以达到非常好的性能,和普通波形绘制没有差异。下图是余晖模式的效果。

下面,详细讲解采用重写QwtPlotCanvas的方式实现余晖绘图功能,并附上完整代码。要实现余晖功能,还需要对QwtPlot类和QwtPlotCanvas类的绘图实现方式有所了解,这些都是Qwt的基础功能,就不详细叙述了。

在QwtPlotCanvas类的私有成员变量中,定义了一个位图对象QPixmap *backingStore,位图对象存储的是采用BackingStore模式绘图时的位图缓存,大概用意就是绘制图形的时候先在位图对象缓存中绘制,然后再将位图缓存一次性显示到窗体中,以提高绘图效率,在这种模式下,每次在重新绘图时,会先将位图缓存清除,因此,无法保留历史的绘图数据。因此,利用位图缓存的机制,我们只要重写QwtPlotCanvas,自定义一种绘图模式(余晖模式),在余晖模式下不进行绘图缓存的清除,便可以达到余晖绘图的效果。并且,通过开发接口,可以实现从余晖模式和普通模式之间的动态切换。下面是详细的代码实现。

1、实现方式:MyPlotCanvas即为重写的QwtPlotCanvas类,需要将MyPlotCanvas对象与QwtPlot类进行关联,调用代码如下:

// 设置背景面板风格
    MyPlotCanvas *pCanvas = new MyPlotCanvas();
    pCanvas->setFrameStyle( QFrame::Box | QFrame::Plain );
    pCanvas->setLineWidth( 1 );
    pCanvas->setPalette( Qt::black );
    pPlot->setCanvas( m_pCanvas );

// 设置普通绘图模式(每次重绘前擦除)
    pCanvas->setPaintMode( MyPlotCanvas::PaintNormal );
// 设置余晖绘图模式(每次重绘不擦除)
    pCanvas->setPaintMode( MyPlotCanvas::PaintEmbers );

2、MyPlotCanvas头文件:

/************************************************************************
* 文件名称  : // my_plot_canvas.h
* 内容摘要  : // 基于QwtPlotCanvas改造,以支持无尽余晖绘图功能。
* 创建人员  : // YuJ([email protected])
* 创建日期  : // 2021年12月15日
************************************************************************/

#ifndef AMC_PLOT_CANVAS_H
#define AMC_PLOT_CANVAS_H

#include "qwt_global.h"
#include <qframe.h>
#include <qpainterpath.h>

class QwtPlot;
class QPixmap;

/*!
  \brief Canvas of a QwtPlot.

   Canvas is the widget where all plot items are displayed

  \sa QwtPlot::setCanvas(), QwtPlotGLCanvas
*/
class MyPlotCanvas : public QFrame
{
    Q_OBJECT

    Q_PROPERTY( double borderRadius READ borderRadius WRITE setBorderRadius )

public:

    /*!
      \brief Paint attributes

      The default setting enables BackingStore and Opaque.

      \sa setPaintAttribute(), testPaintAttribute()
     */
    enum PaintAttribute
    {
        /*!
          \brief Paint double buffered reusing the content
                 of the pixmap buffer when possible.

          Using a backing store might improve the performance
          significantly, when working with widget overlays ( like rubber bands ).
          Disabling the cache might improve the performance for
          incremental paints (using QwtPlotDirectPainter ).

          \sa backingStore(), invalidateBackingStore()
         */
        BackingStore = 1,

        /*!
          \brief Try to fill the complete contents rectangle
                 of the plot canvas

          When using styled backgrounds Qt assumes, that the
          canvas doesn't fill its area completely
          ( f.e because of rounded borders ) and fills the area
          below the canvas. When this is done with gradients it might
          result in a serious performance bottleneck - depending on the size.

          When the Opaque attribute is enabled the canvas tries to
          identify the gaps with some heuristics and to fill those only.

          \warning Will not work for semitransparent backgrounds
         */
        Opaque       = 2,

        /*!
          \brief Try to improve painting of styled backgrounds

          QwtPlotCanvas supports the box model attributes for
          customizing the layout with style sheets. Unfortunately
          the design of Qt style sheets has no concept how to
          handle backgrounds with rounded corners - beside of padding.

          When HackStyledBackground is enabled the plot canvas tries
          to separate the background from the background border
          by reverse engineering to paint the background before and
          the border after the plot items. In this order the border
          gets perfectly antialiased and you can avoid some pixel
          artifacts in the corners.
         */
        HackStyledBackground = 4,

        /*!
          When ImmediatePaint is set replot() calls repaint()
          instead of update().

          \sa replot(), QWidget::repaint(), QWidget::update()
         */
        ImmediatePaint = 8
    };

    //! Paint attributes
    typedef QFlags<PaintAttribute> PaintAttributes;

    /*!
      \brief Focus indicator
      The default setting is NoFocusIndicator
      \sa setFocusIndicator(), focusIndicator(), drawFocusIndicator()
    */

    enum FocusIndicator
    {
        //! Don't paint a focus indicator
        NoFocusIndicator,

        /*!
          The focus is related to the complete canvas.
          Paint the focus indicator using drawFocusIndicator()
         */
        CanvasFocusIndicator,

        /*!
          The focus is related to an item (curve, point, ...) on
          the canvas. It is up to the application to display a
          focus indication using f.e. highlighting.
         */
        ItemFocusIndicator
    };

    enum PaintMode
    {
        PaintNormal, // 常规模式
        PaintEmbers, // 余烬模式
    };

    explicit MyPlotCanvas( QwtPlot * = NULL );
    virtual ~MyPlotCanvas();

    QwtPlot *plot();
    const QwtPlot *plot() const;

    void setFocusIndicator( FocusIndicator );
    FocusIndicator focusIndicator() const;

    void setBorderRadius( double );
    double borderRadius() const;

    void setPaintAttribute( PaintAttribute, bool on = true );
    bool testPaintAttribute( PaintAttribute ) const;

    const QPixmap *backingStore() const;
    void invalidateBackingStore();

    virtual bool event( QEvent * );

    Q_INVOKABLE QPainterPath borderPath( const QRect & ) const;

    void setPaintMode( PaintMode mode );

public Q_SLOTS:
    void replot();

protected:
    virtual void paintEvent( QPaintEvent * );
    virtual void resizeEvent( QResizeEvent * );

    virtual void drawFocusIndicator( QPainter * );
    virtual void drawBorder( QPainter * );

    void updateStyleSheetInfo();

private:
    void drawCanvas( QPainter *, bool withBackground );

    PaintMode m_ePaintMode;

    class PrivateData;
    PrivateData *d_data;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( MyPlotCanvas::PaintAttributes )

#endif

 MyPlotCanvas类实现:

#include "my_plot_canvas.h"
#include "qwt_painter.h"
#include "qwt_null_paintdevice.h"
#include "qwt_math.h"
#include "qwt_plot.h"
#include <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qpaintengine.h>
#include <qevent.h>

class QwtStyleSheetRecorder: public QwtNullPaintDevice
{
public:
    QwtStyleSheetRecorder( const QSize &size ):
        d_size( size )
    {
    }

    virtual void updateState( const QPaintEngineState &state )
    {
        if ( state.state() & QPaintEngine::DirtyPen )
        {
            d_pen = state.pen();
        }
        if (
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值