Qwt中添加标尺是非常方便和漂亮的。除了有普通的直尺外,还有环形标尺。这里我们先学习一下直尺的相关类。直尺的相关类共有下面几个:
1、QwtScaleMap:标尺值映射类。
QwtScaleMap类用于提供标尺坐标系与绘制设备坐标系之间的映射关系。其主要的功能依托 QwtScaleTransformation 类来实现。
2、QwtScaleDiv:标尺刻度划分类。
QwtScaleDiv类表征刻度划分。一个标尺的刻度划分包括它的起始值和3个刻度列表(分别为主刻度列表,次刻度列表和最小刻度列表)。大部分情况下,刻度划分是由QwtScaleEngine(应该说是由它的派生类)自动计算的。
3、QwtScaleDraw:绘制标尺类。
QwtScaleDraw类继承自抽象基类QwtAbstractScaleDraw,用于绘制普通标尺。一个标尺也由多个部分组成(如下列表),其由变量QwtAbstractScaleDraw::ScaleComponent 标识。
1)Backbone 标尺沿线。
2)Ticks 刻度线。
3)Labels 值标签。
4、QwtScaleWidget:标尺部件。
QwtScaleWidget类是呈现或者说被用于绘制标尺的部件,继承自QWidget。 在实际的开发中,这个类用得比较多。代码分析:
1、QwtScaleTransformation 类
除了构造函数和习惯函数外,QwtScaleTransformation 类提供了以下接口:标尺坐标值与绘制设备坐标值之间的转化。virtual double xForm( double s, double s1, double s2, double p1, double p2 ) const; virtual double invXForm( double p, double p1, double p2, double s1, double s2 ) const;
由于禁用了拷贝构造函数和拷贝赋值操作符函数,因此还提供了克隆函数:
//! Create a clone of the transformation QwtScaleTransformation *QwtScaleTransformation::copy() const { return new QwtScaleTransformation( d_type ); }2、QwtScaleMap类
//! Copy constructor QwtScaleMap::QwtScaleMap( const QwtScaleMap& other ): d_s1( other.d_s1 ), d_s2( other.d_s2 ), d_p1( other.d_p1 ), d_p2( other.d_p2 ), d_cnv( other.d_cnv ) { d_transformation = other.d_transformation->copy(); } //! Assignment operator QwtScaleMap &QwtScaleMap::operator=( const QwtScaleMap & other ) { d_s1 = other.d_s1; d_s2 = other.d_s2; d_p1 = other.d_p1; d_p2 = other.d_p2; d_cnv = other.d_cnv; delete d_transformation; d_transformation = other.d_transformation->copy(); return *this; } //! Copy constructor QwtScaleMap::QwtScaleMap( const QwtScaleMap& other ): d_s1( other.d_s1 ), d_s2( other.d_s2 ), d_p1( other.d_p1 ), d_p2( other.d_p2 ), d_cnv( other.d_cnv ) { d_transformation = other.d_transformation->copy(); } //! Assignment operator QwtScaleMap &QwtScaleMap::operator=( const QwtScaleMap & other ) { d_s1 = other.d_s1; d_s2 = other.d_s2; d_p1 = other.d_p1; d_p2 = other.d_p2; d_cnv = other.d_cnv; delete d_transformation; d_transformation = other.d_transformation->copy(); return *this; }然后,QwtScaleMap的参数设置接口和完成坐标系统之间值转化的功能函数:
void setPaintInterval( double p1, double p2 ); void setScaleInterval( double s1, double s2 ); double transform( double s ) const; double invTransform( double p ) const;3、QwtScaleDiv类
/*! Construct QwtScaleDiv instance. \param interval Interval \param ticks List of major, medium and minor ticks */ QwtScaleDiv::QwtScaleDiv( const QwtInterval &interval, QList<double> ticks[NTickTypes] ): d_lowerBound( interval.minValue() ), d_upperBound( interval.maxValue() ), d_isValid( true ) { for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i] = ticks[i]; }再看一下其实现值得借鉴的函数接口:
/*! Return a list of ticks \param type MinorTick, MediumTick or MajorTick */ const QList<double> &QwtScaleDiv::ticks( int type ) const { if ( type >= 0 || type < NTickTypes ) // 防错性判断,OK! return d_ticks[type]; static QList<double> noTicks; return noTicks; }static QList<double> noTicks; // 定义一个局部的静态变量,只初始化一次即可。如果在一个循环中调用ticks(),恰好输入的参数有误,则能大幅度提高效率。
class QwtAbstractScaleDraw::PrivateData { public: PrivateData(): spacing( 4.0 ), penWidth( 0 ), minExtent( 0.0 ) { components = QwtAbstractScaleDraw::Backbone | QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels; tickLength[QwtScaleDiv::MinorTick] = 4.0; tickLength[QwtScaleDiv::MediumTick] = 6.0; tickLength[QwtScaleDiv::MajorTick] = 8.0; } ScaleComponents components; // 标尺包含哪些部分 QwtScaleMap map; QwtScaleDiv scldiv; double spacing; double tickLength[QwtScaleDiv::NTickTypes]; // 刻度线的长度 int penWidth; double minExtent; QMap<double, QwtText> labelCache;// 标签缓存 };实现:
/*! \brief Draw the scale \param painter The painter \param palette Palette, text color is used for the labels, foreground color for ticks and backbone */ void QwtAbstractScaleDraw::draw( QPainter *painter, const QPalette& palette ) const { painter->save(); QPen pen = painter->pen(); pen.setWidth( d_data->penWidth ); pen.setCosmetic( false ); painter->setPen( pen ); if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { painter->save(); painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style const QList<double> &majorTicks = d_data->scldiv.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < majorTicks.count(); i++ ) { const double v = majorTicks[i]; if ( d_data->scldiv.contains( v ) ) drawLabel( painter, majorTicks[i] ); // 绘制标签,纯虚函数,具体的实现延迟到子类中 } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList<double> &ticks = d_data->scldiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( d_data->scldiv.contains( v ) ) drawTick( painter, v, d_data->tickLength[tickType] ); // 绘制刻度,纯虚函数,具体的实现延迟至子类中 } } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); drawBackbone( painter ); // 绘制标尺底线,纯虚函数,具体的实现延迟至子类中 painter->restore(); } painter->restore(); }
void setScaleDiv( const QwtScaleDiv &s ); const QwtScaleDiv& scaleDiv() const; void setTransformation( QwtScaleTransformation * ); const QwtScaleMap &scaleMap() const; QwtScaleMap &scaleMap();当然,也可以设置笔的宽度,刻度线的长度等属性显示不同风格的刻度。
void getMinBorderDist( int &start, int &end ) const; // 通过引用返回两个值 void setMinBorderDist( int start, int end );设置坐标转化和刻度划分:
void setScaleDiv( QwtScaleTransformation *, const QwtScaleDiv &sd ); void setScaleDraw( QwtScaleDraw * ); const QwtScaleDraw *scaleDraw() const; QwtScaleDraw *scaleDraw();色标的使用:
void setColorMap( const QwtInterval &, QwtColorMap * ); QwtInterval colorBarInterval() const; const QwtColorMap *colorMap() const;7、最后再看标尺用到的一个“静态工具类”QwtScaleArithmetic:
/*! \brief Arithmetic including a tolerance */ class QWT_EXPORT QwtScaleArithmetic { public: static double ceilEps( double value, double intervalSize ); static double floorEps( double value, double intervalSize ); static double divideEps( double interval, double steps ); static double ceil125( double x ); static double floor125( double x ); };这样分类定义的静态函数明显优于全局函数。