Qwt源码解读之缩放操作类

    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 happens
QWidget *QwtMagnifier::parentWidget()
{
    if ( parent()->inherits( "QWidget" ) )
        return ( QWidget * )parent();

    return NULL;
}

//! \return Parent widget, where the rescaling happens
const 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:
QwtPlotZoomerQwtPlotPannerQwtPlot
由于大部分功能在其基类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 canvas
QwtPlotCanvas *QwtPlotMagnifier::canvas()
{
    return qobject_cast<QwtPlotCanvas *>( parent() );
}

//! Return Observed plot canvas
const QwtPlotCanvas *QwtPlotMagnifier::canvas() const
{
    return qobject_cast<const QwtPlotCanvas *>( parent() );
}
这里使用了  T qobject_cast ( QObject * object ) 。

4、一个好的防御性编码实现例子:

//! Return plot widget, containing the observed plot canvas
QwtPlot *QwtPlotMagnifier::plot()
{
    QwtPlotCanvas *w = canvas();
    if ( w )
        return w->plot();

    return NULL;
}

//! Return plot widget, containing the observed plot canvas
const 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、多次把一个图形放大后,怎么一键让它恢复到原样大小?

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值