Qwt源码解读之平移操作类——QwtPanner and QwtPlotPanner

来源:互联网 发布:vnr网络连接不畅 编辑:程序博客网 时间:2024/04/26 19:17

  先看一看Qwt文档对QwtPanner类的说明:

QwtPanner provides panning of a widget.

QwtPanner grabs the contents of a widget, that can be dragged in all directions. The offset between the start and the end position is emitted by the panned signal.

QwtPanner grabs the content of the widget into a pixmap and moves the pixmap around, without initiating any repaint events for the widget. Areas, that are not part of content are not painted while panning. This makes panning fast enough for widgets, where repaints are too slow for mouse movements.

For widgets, where repaints are very fast it might be better to implement panning manually by mapping mouse events into paint events.

类继承关系

如下图所示:


QwtPanner类提供了对图形部件的平移操作,其实就是在平移时,通过将图形绘制在另一个部件(QWidget)上实现了平移的效果(抓取)。这一切都是通过Qt的事件机制实现的。

QwtPanner && QwtPlotPanner类:用于对QwtPlotCanvas进行平移操作。

代码分析

一、QwtPanner类:

1、构造函数

/*!  Creates an panner that is enabled for the left mouse button.  \param parent Parent widget to be panned*/QwtPanner::QwtPanner( QWidget *parent ):    QWidget( parent ){    d_data = new PrivateData();    setAttribute( Qt::WA_TransparentForMouseEvents );    setAttribute( Qt::WA_NoSystemBackground );    setFocusPolicy( Qt::NoFocus );    hide(); // 默认将其隐藏    setEnabled( true );}

继承自QWidget。默认情况下,将其隐藏。

2、使能/禁用

/*!  \brief En/disable the panner  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 QwtPanner::setEnabled( bool on ){    if ( d_data->isEnabled != on )    {        d_data->isEnabled = on;        QWidget *w = parentWidget();        if ( w )        {            if ( d_data->isEnabled )            {                w->installEventFilter( this ); // 安装事件过滤器            }            else            {                w->removeEventFilter( this );                hide();            }        }    }}
注意:QwtPanner定义的一对启用/禁用平移功能的接口:

    void setEnabled( bool );    bool isEnabled() const;
隐藏了其基类QWidget的槽函数接口:
    bool isEnabled() const;    bool isEnabledTo(QWidget*) const;    bool isEnabledToTLW() const;public Q_SLOTS:    void setEnabled(bool);    void setDisabled(bool);    void setWindowModified(bool);
不能不说是一个败笔!其实换个函数名字就能够避免,不知道作者是否有出于别的原因考虑?

3、事件过滤器:

/*!  \brief Event filter  When isEnabled() is true mouse events of the  observed widget are filtered.  \param object Object to be filtered  \param event Event  \return Always false, beside for paint events for the          parent widget.  \sa widgetMousePressEvent(), widgetMouseReleaseEvent(),      widgetMouseMoveEvent()*/bool QwtPanner::eventFilter( QObject *object, QEvent *event ){    if ( object == NULL || object != parentWidget() )        return false;    switch ( event->type() )    {        case QEvent::MouseButtonPress:        {            widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );            break;        }        case QEvent::MouseMove:        {            widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );            break;        }        case QEvent::MouseButtonRelease:        {            widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );            break;        }        case QEvent::KeyPress:        {            widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );            break;        }        case QEvent::KeyRelease:        {            widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );            break;        }        case QEvent::Paint:        {            if ( isVisible() )                return true;            break;        }        default:;    }    return false;}

4、返回QwtPanner操纵部件的mask(面具)的位图函数:

/*!  \brief Calculate a mask for the contents of the panned widget  Sometimes only parts of the contents of a widget should be  panned. F.e. for a widget with a styled background with rounded borders  only the area inside of the border should be panned.  \return An empty bitmap, indicating no mask*/QBitmap QwtPanner::contentsMask() const{    return QBitmap();}
它是一个虚函数,默认实现返回一个空的QBitmap,在QwtPlotPanner类中会被重新实现。

5、QwtPanner类实现抓取( grab)功能的函数:

/*!  Grab the widget into a pixmap.  \return Grabbed pixmap*/QPixmap QwtPanner::grab() const{#if QT_VERSION >= 0x050000    return parentWidget()->grab( parentWidget()->rect() ); // 抓取父窗口的矩形区域#else    return QPixmap::grabWidget( parentWidget() );#endif}

它是一个虚函数,在其子类中可根据需要重新实现。

二、QwtPlotPanner类:继承自QwtPanner类。
先看一看Qwt文档说明:

QwtPlotPanner provides panning of a plot canvas.

QwtPlotPanner is a panner for a QwtPlotCanvas, that adjusts the scales of the axes after dropping the canvas on its new position.

Together with QwtPlotZoomer and QwtPlotMagnifier powerful ways of navigating on a QwtPlot widget can be implemented easily.

Note:
The axes are not updated, while dragging the canvas
See also:
QwtPlotZoomer, QwtPlotMagnifier

1、构造函数

/*!  \brief A panner for the canvas of a QwtPlot  The panner is enabled for all axes  \param canvas Plot canvas to pan, also the parent object  \sa setAxisEnabled()*/QwtPlotPanner::QwtPlotPanner( QWidget *canvas ):    QwtPanner( canvas ){    d_data = new PrivateData();    connect( this, SIGNAL( panned( int, int ) ),        SLOT( moveCanvas( int, int ) ) );}
QwtPlotPanner的父窗口是画布(canvas),构造函数中将平移信号移动画布的槽连接
2、可以通过 setAxisEnabled( int axis, bool on ); 设置伴随平移更新标尺刻度的轴。默认是平移时所有的轴都会被更新刻度。

/*!   \brief En/Disable an axis   Axes that are enabled will be synchronized to the   result of panning. All other axes will remain unchanged.   \param axis Axis, see QwtPlot::Axis   \param on On/Off   \sa isAxisEnabled(), moveCanvas()*/void QwtPlotPanner::setAxisEnabled( int axis, bool on ){    if ( axis >= 0 && axis < QwtPlot::axisCnt )        d_data->isAxisEnabled[axis] = on;}
3、画布就是父窗口

//! Return observed plot canvasQWidget *QwtPlotPanner::canvas(){    return parentWidget();}//! Return Observed plot canvasconst QWidget *QwtPlotPanner::canvas() const{    return parentWidget();}

4、移动画布的函数

protected Q_SLOTS:    virtual void moveCanvas( int dx, int dy );

/*!   Adjust the enabled axes according to dx/dy   \param dx Pixel offset in x direction   \param dy Pixel offset in y direction   \sa QwtPanner::panned()*/void QwtPlotPanner::moveCanvas( int dx, int dy ){    if ( dx == 0 && dy == 0 )        return;    QwtPlot *plot = this->plot();    if ( plot == NULL )        return;    const bool doAutoReplot = plot->autoReplot();    plot->setAutoReplot( false );    for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )    {        if ( !d_data->isAxisEnabled[axis] )            continue;        const QwtScaleMap map = plot->canvasMap( axis );        const double p1 = map.transform( plot->axisScaleDiv( axis ).lowerBound() );        const double p2 = map.transform( plot->axisScaleDiv( axis ).upperBound() );        double d1, d2;        if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )        {            d1 = map.invTransform( p1 - dx );            d2 = map.invTransform( p2 - dx );        }        else        {            d1 = map.invTransform( p1 - dy );            d2 = map.invTransform( p2 - dy );        }        plot->setAxisScale( axis, d1, d2 );    }    plot->setAutoReplot( doAutoReplot );    plot->replot();}

该函数有待研究!!!目前还不懂

5、contentsMask() 函数的实现

/*!   Calculate a mask from the border path of the canvas   \return Mask as bitmap   \sa QwtPlotCanvas::borderPath()*/QBitmap QwtPlotPanner::contentsMask() const{    if ( canvas() )        return qwtBorderMask( canvas(), size() );    return QwtPanner::contentsMask();}

其中函数qwtBorderMask的实现如下:

static QBitmap qwtBorderMask( const QWidget *canvas, const QSize &size ){    const QRect r( 0, 0, size.width(), size.height() );    QPainterPath borderPath;    ( void )QMetaObject::invokeMethod(         const_cast< QWidget *>( canvas ), "borderPath", Qt::DirectConnection,        Q_RETURN_ARG( QPainterPath, borderPath ), Q_ARG( QRect, r ) );    if ( borderPath.isEmpty() )    {        if ( canvas->contentsRect() == canvas->rect() )            return QBitmap();        QBitmap mask( size );        mask.fill( Qt::color0 );        QPainter painter( &mask );        painter.fillRect( canvas->contentsRect(), Qt::color1 );        return mask;    }    QImage image( size, QImage::Format_ARGB32_Premultiplied );    image.fill( Qt::color0 );    QPainter painter( &image );    painter.setClipPath( borderPath );    painter.fillRect( r, Qt::color1 );    // now erase the frame    painter.setCompositionMode( QPainter::CompositionMode_DestinationOut );    if ( canvas->testAttribute(Qt::WA_StyledBackground ) )    {        QStyleOptionFrame opt;        opt.initFrom(canvas);        opt.rect = r;        canvas->style()->drawPrimitive( QStyle::PE_Frame, &opt, &painter, canvas );    }    else    {        const QVariant borderRadius = canvas->property( "borderRadius" );        const QVariant frameWidth = canvas->property( "frameWidth" );        if ( borderRadius.type() == QVariant::Double             && frameWidth.type() == QVariant::Int )        {            const double br = borderRadius.toDouble();            const int fw = frameWidth.toInt();                    if ( br > 0.0 && fw > 0 )            {                painter.setPen( QPen( Qt::color1, fw ) );                painter.setBrush( Qt::NoBrush );                painter.setRenderHint( QPainter::Antialiasing, true );                painter.drawPath( borderPath );            }        }    }    painter.end();    const QImage mask = image.createMaskFromColor(        QColor( Qt::color1 ).rgb(), Qt::MaskOutColor );    return QBitmap::fromImage( mask );}

6、QwtPlotPanner类实现抓取( grab)功能的函数:

/*!   \return Pixmap with the content of the canvas */QPixmap QwtPlotPanner::grab() const{       const QWidget *cv = canvas();    if ( cv && cv->inherits( "QGLWidget" ) )    {        // we can't grab from a QGLWidget        QPixmap pm( cv->size() );        QwtPainter::fillPixmap( cv, pm );        QPainter painter( &pm );        const_cast<QwtPlot *>( plot() )->drawCanvas( &painter );        return pm;    }    return QwtPanner::grab();}   

7、属性数据:

class QwtPlotPanner::PrivateData{public:    PrivateData()    {        for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )            isAxisEnabled[axis] = true;    }    bool isAxisEnabled[QwtPlot::axisCnt];};

用数组存储哪些坐标轴伴随平移而更新坐标刻度。

0 0
原创粉丝点击