您的位置:首页 > 其它

Qwt源码解读之标尺相关类

2014-07-06 15:51 459 查看
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类

这里看一下QwtScaleMap的拷贝构造函数和拷贝赋值操作符函数,帮助理解上面 QwtScaleTransformation类的copy()函数。

//! 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类

QwtScaleDiv类共有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 ) // 防错性判断
return d_ticks[type];

static QList<double> noTicks;
return noTicks;
}
static QList<double> noTicks; // 定义一个局部的静态变量,只初始化一次即可。如果在一个循环中调用ticks(),恰好输入的参数有误,则能大幅度提高效率。

4、QwtAbstractScaleDraw类

数据:

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;// 标签缓存
};
实现:

QwtAbstractScaleDraw类使用了模板方法模式【Template Method】,draw()方法定义了绘制标尺的基本框架:

/*!
\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();
当然,也可以设置笔的宽度,刻度线的长度等属性显示不同风格的刻度。

5、QwtScaleDraw类

主要实现了QwtAbstractScaleDraw的四个纯虚函数,以及标尺的位置(原点)移动;标签旋转;刻度对齐;等功能。

6、QwtScaleWidget类

一个较好的接口命名示例代码:

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 * );
const QwtColorMap *colorMap() const;
QwtInterval colorBarInterval() 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 );
};
这样分类定义的静态函数明显优于全局函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: