Qwt源碼解讀之縮放操作類

來源:互聯網
上載者:User

    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、多次把一個圖形放大後,怎麼一鍵讓它恢複到原樣大小?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.