Qwt提供了自己的縮放機制。
QwtMagnifier類:提供逐步放大縮小功能的抽象基類。被QwtPlotMagnifier繼承。繼承關係如所示:
程式碼分析:
一、QwtMagnifier類
1、建構函式:
/*! Constructor \param parent Widget to be magnified*/QwtMagnifier::QwtMagnifier( QWidget *parent ): QObject( parent ){ d_data = new PrivateData(); setEnabled( true );} 建構函式要求傳入被放大縮小的組件parent (通常是QwtPlotCanvas)。
2、安裝/卸載事件過濾器:
QwtMagnifier對象對“滑鼠、滾輪,鍵盤”事件的響應(擷取)是通過事件機制傳遞的。在setEnabled()函數中,通過安裝/卸載事件過濾器來達到開啟/禁用縮放功能的目的。
/*! \brief En/disable the magnifier When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter()*/void QwtMagnifier::setEnabled( bool on ){ if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QObject *o = parent(); if ( o ) { if ( d_data->isEnabled ) o->installEventFilter( this ); else o->removeEventFilter( this ); } }}這是一個利用Qt事件機制的極好例子。 注意以上代碼:如果開啟,則為對象o(即parent)安裝this(即QwtMagnifier)的事件過濾器,也就是說,所有發送到對象o的事件都會先傳給QwtMagnifier的eventFilter()函數過濾(即處理)。如果要禁用縮放功能,則只需卸載即可。
3、看一下事件過濾器函數的代碼:
/*! \brief Event filter When isEnabled() the mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent() widgetKeyReleaseEvent()*/bool QwtMagnifier::eventFilter( QObject *object, QEvent *event ){ if ( object && object == parent() ) // 判斷事件屬主對象 { switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::Wheel: { widgetWheelEvent( ( QWheelEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } default:; } } return QObject::eventFilter( object, event );}4、再看看擷取父類對象的函數,可以學習一個新的方法: bool QObject::inherits ( const char * className ) const:
//! \return Parent widget, where the rescaling happensQWidget *QwtMagnifier::parentWidget(){ if ( parent()->inherits( "QWidget" ) ) return ( QWidget * )parent(); return NULL;}//! \return Parent widget, where the rescaling happensconst QWidget *QwtMagnifier::parentWidget() const{ if ( parent()->inherits( "QWidget" ) ) return ( const QWidget * )parent(); return NULL;} 判斷一個對象是否是名稱為className 的類的執行個體或其子類執行個體。代碼如下:
inline bool inherits(const char *classname) const { return const_cast<QObject *>(this)->qt_metacast(classname) != 0; }不過有一個疑問:這個地方為什麼不使用 T qobject_cast ( QObject * object ) ???
5、QwtMagnifier是一個抽象基類,有一個負責具體實現放大縮小的功能函數:
protected: /*! Rescale the parent widget \param factor Scale factor */ virtual void rescale( double factor ) = 0;
純虛函數,其具體實現被延遲到子類中。
二、QwtPlotMagnifier類
首先我們看看Qwt文檔對QwtPlotMagnifier類的說明:
QwtPlotMagnifier provides
zooming, by magnifying in steps.
Using QwtPlotMagnifier a
plot can be zoomed in/out in steps using keys, the mouse wheel or moving a mouse button in vertical direction.
Together with QwtPlotZoomer and QwtPlotPanner it
is possible to implement individual and powerful navigation of the plot canvas.
-
See also:
-
QwtPlotZoomer, QwtPlotPanner, QwtPlot
由於大部分功能在其基類QwtMagnifier中已經實現,QwtPlotMagnifier只需要重新實現純虛函數rescale( factor )即可,因此QwtPlotMagnifier類的代碼也較為簡單:
1、建構函式:
/*! Constructor \param canvas Plot canvas to be magnified*/QwtPlotMagnifier::QwtPlotMagnifier( QwtPlotCanvas *canvas ): QwtMagnifier( canvas ){ d_data = new PrivateData();}注意:傳遞進去的參數是QwtPlotCanvas而非QwtPlot。
2、可以只“設定指定的軸”被放大或縮小,而其它軸保持不變:
/*! \brief En/Disable an axis Only Axes that are enabled will be zoomed. All other axes will remain unchanged. \param axis Axis, see QwtPlot::Axis \param on On/Off \sa isAxisEnabled()*/void QwtPlotMagnifier::setAxisEnabled( int axis, bool on ){ if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->isAxisEnabled[axis] = on;}3、返回QwtPlotMagnifier類操作的畫布對象QwtPlotCanvas:
//! Return observed plot canvasQwtPlotCanvas *QwtPlotMagnifier::canvas(){ return qobject_cast<QwtPlotCanvas *>( parent() );}//! Return Observed plot canvasconst QwtPlotCanvas *QwtPlotMagnifier::canvas() const{ return qobject_cast<const QwtPlotCanvas *>( parent() );}這裡使用了 T qobject_cast ( QObject * object ) 。
4、一個好的防禦性編碼實現例子:
//! Return plot widget, containing the observed plot canvasQwtPlot *QwtPlotMagnifier::plot(){ QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL;}//! Return plot widget, containing the observed plot canvasconst QwtPlot *QwtPlotMagnifier::plot() const{ const QwtPlotCanvas *w = canvas(); if ( w ) return w->plot(); return NULL;}我經常寫成:
return canvas()->plot();
編碼時總是求快,著急看到效果,沒有防錯意識。這樣的編碼習慣何談提高代碼品質? 差距啊!
5、最後,也貼上功能函數rescale( factor )的實現代碼:
/*! Zoom in/out the axes scales \param factor A value < 1.0 zooms in, a value > 1.0 zooms out.*/void QwtPlotMagnifier::rescale( double factor ){ factor = qAbs( factor ); if ( factor == 1.0 || factor == 0.0 ) return; bool doReplot = false; QwtPlot* plt = plot(); const bool autoReplot = plt->autoReplot(); plt->setAutoReplot( false ); for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { const QwtScaleDiv *scaleDiv = plt->axisScaleDiv( axisId ); if ( isAxisEnabled( axisId ) && scaleDiv->isValid() ) { const double center = scaleDiv->lowerBound() + scaleDiv->range() / 2; const double width_2 = scaleDiv->range() / 2 * factor; plt->setAxisScale( axisId, center - width_2, center + width_2 ); doReplot = true; } } plt->setAutoReplot( autoReplot ); if ( doReplot ) plt->replot();}以後實現自己特定的縮放類時可以參考。
三、疑問:
現在對縮放操作類QwtMagnifier裡的滑鼠、滾輪、鍵盤的設定的作用不清楚。
void setMouseButton( int button, int buttonState = Qt::NoButton ); void setWheelButtonState( int buttonState ); void setZoomInKey( int key, int modifiers ); void setZoomOutKey( int key, int modifiers );
1、試了很多情況,也沒看出有什麼效果?
2、多次把一個圖形放大後,怎麼一鍵讓它恢複到原樣大小?