存档在 ‘qwt’ 分类

QwtPlotCurve::PaintAttribute解析

2014年4月21日

这个属性是为了修正画图算法用,默认的是使用了ClipPolygons和FilterPoints

ClipPolygons
Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance
//在画图之前对不在可视区的点进行裁剪

FilterPoints
Tries to reduce the data that has to be painted, by sorting out duplicates, or paintings outside the visible area. Might have a notable impact on curves with many close points. Only a couple of very basic filtering algorithms are implemented.
//进行点滤波,减少点的数目

MinimizeMemory
Minimize memory usage that is temporarily needed for the translated points, before they get painted. This might slow down the performance of painting
//最小化内存消耗,意味着一些临时在内存中的数据将被清除,将会影响性能

ImageBuffer
Render the points to a temporary image and paint the image. This is a very special optimization for Dots style, when having a huge amount of points. With a reasonable number of points QPainter::drawPoints() will be faster.
//渲染一些点到临时图片中,提高性能

Qwt定制离散线与连续线

2014年4月21日

因为QwtPlotCurve里有如下定义

  enum CurveStyle
    {
        /*!Don't draw a curve. Note: This doesn't affect the symbols.*/
        NoCurve = -1,
        Lines,
        Sticks,
        Steps,
        Dots,
        UserCurve = 100
    };

为了能够定制曲线,需要重载以下函数,在QwtPlotCurve里的实现为

void QwtPlotCurve::drawCurve( QPainter *painter, int style,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
{
    switch ( style )
    {
        case Lines:
            if ( testCurveAttribute( Fitted ) )
            {
                // we always need the complete
                // curve for fitting
                from = 0;
                to = dataSize() - 1;
            }
            drawLines( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Sticks:
            drawSticks( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Steps:
            drawSteps( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Dots:
            drawDots( painter, xMap, yMap, canvasRect, from, to );
            break;
        case NoCurve:
        default:
            break;
    }
}

通过CurveStyle来分发不同的画线方式,我们可以使用UserCurve来区分
1.首先定义一个派生于QwtPlotCurve的类

class MyCurve: public QwtPlotCurve

2.重新定义

virtual void drawCurve( QPainter *p, int style, const QwtScaleMap &xMap,
                            const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const
    {

        p->setPen(pen);
        switch ( style )
        {
            case QwtPlotCurve::UserCurve:
                drawMyCurve(p,  xMap, yMap, canvasRect, from, to);
                break;
            default:
                 QwtPlotCurve::drawCurve(p, style, xMap, yMap,canvasRect, from, to);
                break;
       }
    }

3.最后重新实现drawMyCurve即可。

至此,完美解决。

使用Qwt之QwtDateScaleDraw时间标尺

2014年4月20日

Qwt是用于绘制科学图形的Qt库。其中用于绘制坐标和曲线的类是QwtPlot类。QwtPlot提供的坐标默认以数值为单位,例如:(1,2,3,…)。但是有些时候需要以时间或日期为单位刻度的标尺。Qwt是提供了这样的功能的。

QwtPlot类会默认创建两个Scale,也就是标尺,另外QwtPlot提供了方法,允许开发人员对将默认的Scale替换成定制的标尺。因此,只需要创建一个QwtDateScaleDraw对象QwtDateScaleDraw是以时间为刻度的标尺类,并用其替换Plot的默认Scale即可。QwtDateScaleDraw类的继承关系如下所示:
1
替换Plot的默认Scale代码如下:

QwtDateScaleDraw *timeScale = new QwtDateScaleDraw(Qt::LocalTime);
QwtPlot *plot = new QwtPlot();
plot->setAxisScaleDraw(QwtPlot::xBottom, timeScale);
delete plot;

Qwt帮助文档中setAxisScaleDraw()方法的原型和解释如下:
void QwtPlot::setAxisScaleDraw (int axisId,QwtScaleDraw *scaleDraw )
By passing scaleDraw it is possible to extend QwtScaleDrawfunctionality and let it take place in QwtPlot. Please note that scaleDraw has to be created with new and will be deleted by the corresponding QwtScale member ( like a child object ).
翻译过来是说:通过传入scaleDraw参数,可以替代QwtPlot中的QwtScaleDraw,并扩展其功能。请注意,scaleDraw必须使用new关键字创建,作为相关的QwtScale成员,会被像子对象一样删除。
这就是在上述代码中,只需要delete plot,而不用再delete timeScale了。

QwtDateScaleDraw允许开发人员对时间刻度的显示方式进行设置,下面的代码将设置在毫秒级别以“Sec 秒:毫秒”的方式显示与在秒及其以上级别以“时:分:秒\n年-月-日”的方式进行显示,其中“\n”表示换行。

QString *scaleFormat;
scaleFormat = new QString("Sec ss:zzz");
timeScale->setDateFormat(QwtDate::Millisecond, *scaleFormat);
delete scaleFormat;
scaleFormat = new QString("hh:mm:ss\nyy-MM-dd");
timeScale->setDateFormat(QwtDate::Second, *scaleFormat);
delete scaleFormat;

第二段代码段生成的图片为:
2

利用qwt自定义时间标尺TimeScale

2014年4月20日

需要重载QwtScaleDraw类的virtual QwtText label(double)const;方法该方法在需要绘制scale label时会调用。

主要思路是标尺上的点对应QDateTime::toTime_t()的值。然后重载label方法,在QwtText label(double v) const 方法中将参数v转化为QDateTime对象,再转为QString。
timescaledraw.h

#ifndef TIMESCALEDRAW_H
#define TIMESCALEDRAW_H

#include <qwt_scale_draw.h>
#include <QDateTime>

class TimeScaleDraw : public QwtScaleDraw
{public:
    TimeScaleDraw();
    virtual QwtText label(double) const;
};

#endif // TIMESCALEDRAW_H

timescaledraw.cpp

#include "timescaledraw.h"

TimeScaleDraw::TimeScaleDraw()
{
}

QwtText TimeScaleDraw::label(double v) const
{
    QDateTime datetime;datetime.setTime_t((uint)v);
    return QwtText(datetime.date().toString(Qt::ISODate);
}

调用方法:

qwtplot->setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw());

实现之后发现一个问题,就是当qwt标尺的label在左右两端显示时,会把标尺撑得变形。可以利用重载的label方法判断在左右两端附近时返回一个空的QwtText即可。
具体代码如下:
timescaledraw.h

#ifndef TIMESCALEDRAW_H
#define TIMESCALEDRAW_H

#include <qwt_scale_draw.h>
#include <QDateTime>

class TimeScaleDraw : public QwtScaleDraw
{
    double minLabelPos, maxLabelPos;
public:
    TimeScaleDraw(const double minLabelPos, const double maxLabelPos);
    virtual QwtText label(double) const;
    void myinit(const double minLabelPos, const double maxLabelPos);
};

#endif // TIMESCALEDRAW_H

timescaledraw.cpp

#include "timescaledraw.h"

TimeScaleDraw::TimeScaleDraw(const double minLabelPos, const double maxLabelPos)
{
    myinit(minLabelPos, maxLabelPos);
}

QwtText TimeScaleDraw::label(double v) const
{
    QDateTime datetime;

    if(v < minLabelPos || v > maxLabelPos)
        return QwtText();

    datetime.setTime_t((uint)v);return QwtText(datetime.date().toString(Qt::ISODate);
}

void TimeScaleDraw::myinit(const double minLabelPos, const double maxLabelPos)
{
    this->minLabelPos = minLabelPos;
    this->maxLabelPos = maxLabelPos;
}

调用方法:

qwtplot->setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw(xx, xxxx));

Qwt 自定义坐标轴tick

2014年4月20日

Interval and all tick positions of a scale are stored in a QwtScaleDiv object.

You can manually create a QwtScaleDiv and assign it to a plot axis (QwtPlot::setAxisScaleDiv()) , or you can use a QwtScaleEngine ( QwtPlot has one for each axis), that calculates it for you. When autoscaling ( QwtPlot::setAxisAutoScale() ) is enabled, the interval for the calculation of the scale is taken from the bounding rectangle of the plot items ( f.e. curves ), otherwise interval/step size are passed with QwtPlot::setAxisScale().

The default scale engines try to calculate ticks for linear decimal scales, what doesn’t need to be the right thing for date/time scales. ( QwtDateTimeScaleEngine is on my TODO list ). To improve your scale divisions you can derive and assign ( QwtPlot::setAxisScaleEngine()) your own scale engine or simply use QwtPlot::setAxisScaleDiv instead.

QwtScaleDraw is responsible for painting a QwtScaleDiv. QwtScaleDraw::label() maps a tick value into a string.
In the cpuplot example the values on the x-axis are seconds elapsed since the system is up. TimeScaleDraw::label() maps them into time strings – that’s all.
先改输出tick在横坐标位置,

    QList<double> ticks[QwtScaleDiv::NTickTypes];
    ticks[QwtScaleDiv::MajorTick] << 60 << 120;  //只在60和120个sample点tick
    QwtScaleDiv scaleDiv(
        ticks[QwtScaleDiv::MajorTick].first(),
        ticks[QwtScaleDiv::MajorTick].last(),
        ticks );
    plot->setAxisScaleDiv(QwtPlot::xBottom, scaleDiv);

再改tick具体值, 需要重载QwtText label函数,

class RealScaleDraw: public QwtScaleDraw
{
public:
    RealScaleDraw()
    {
    }
    virtual QwtText label(double v) const
    {
        //return QwtScaleDraw::label(v);
            return QwtText(QString::number(v/10)); //60和120都除以10
        }
};

主函数调用,

plot->setAxisScaleDraw(QwtPlot::xBottom, new RealScaleDraw());

QwtPlot

2014年4月16日
QwtPlot是用来绘制二维图像的widget。在它的画板上可以无限制的显示绘画组件。绘画组件可以是曲线(QwtPlotCurve)、标记(QwtPlotMarker)、网格(QwtPlotGrid)、或者其它从QwtPlotItem继承的组件。

QwtPlot拥有4个axes(轴线)

yLeft
Y axis left of the canvas.
yRight Y axis right of the canvas.
xBottom X axis below the canvas.
xTop X axis above the canvas.

常用函数接口

setAxisTitle 设置轴标题
enableAxis 主要是显示xTop,yRight坐标轴
setAxisMaxMajor 设置某个某个坐标轴扩大比例尺的最大间隔数目
setAxisMaxMinor 设置某个某个坐标轴缩小比例尺的最大间隔数目
setAxisScale 禁用自动缩放比例尺,为某个坐标轴指定一个修改的比例尺
insertLegend 添加图例(标注)

常用组件

QwtPlotCurve 曲线
QwtPlotMarker 标记
QwtPlotGrid 网格
QwtPlotHistogram 直方图
other 从QwtPlotItem继承的组件
QwtPlotItem plot能显示的类,如果想要实现自己绘画图形,要继承此类实现rtti和draw接口
QwtPlotPanner 平移器    (用鼠标左键平移)
QwtPlotMagnifier  放大器    (用鼠标滚轮缩放)
QwtPlotCanvas 画布
QwtScaleMap 比例图—可以提供一个逻辑区域到实际区域的坐标转换
QwtScaleWidget 比例窗口
QwtScaleDiv 比例布局
QwtLegent 标注
QwtPlotLayout 布局管理器
QwtScaleDraw 自画坐标轴

QwtPlotCure简介

常见接口
setPen 设置画笔
setData 设置曲线的数据
setStyle 设置曲线形式,点、直线、虚线等等
setCurveAttribute 设置曲线属性,一般设置Fitted
attch 把曲线附加到QwlPlot上