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 transformationQwtScaleTransformation *QwtScaleTransformation::copy() const{ return new QwtScaleTransformation( d_type );}
2、QwtScaleMap類
這裡看一下QwtScaleMap的拷貝建構函式和拷貝賦值操作符函數,協助理解上面 QwtScaleTransformation類的copy()函數。
//! Copy constructorQwtScaleMap::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 operatorQwtScaleMap &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 constructorQwtScaleMap::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 operatorQwtScaleMap &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 ) // 防錯性判斷,OK! 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 * ); 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 );};
這樣分類定義的靜態函數明顯優於全域函數。