QWT框选缩放-仅水平或仅垂直缩放功能实现

    在文章之前,首先看看这篇文章要实现的效果:

对于某些绘图应用,如波形绘制,矩形框缩放并不能很好的满足波形查看要求,需要支持仅水平或仅垂直缩放,Qwt的原生控件并不支持仅水平或垂直框选缩放,因此,需要对Qwt缩放控件进行改造,以实现图中的效果。

Qwt提供了丰富的图形缩放功能,主要有两个类,分别是QwtMagnifierQwtPlotZoomer,其中,QwtMagnifier完成鼠标滚轮缩放功能,QwtPlotZoomer完成矩形框选缩放功能。这两个类的相关继承关系如下图所示。

QwtMagnifier类提供了缩放坐标轴使能函数,用于控制仅水平或仅垂直缩放功能。因此,通过鼠标滚轮利用原生的Qwt控件是支持仅水平缩放功能的。

    void setAxisEnabled( int axis, bool on );
    bool isAxisEnabled( int axis ) const;

但对于框选缩放类QwtPlotZoomer,并没有提供上述函数用于实现文章需要的水平框选缩放功能。因此,作者针对QwtPlotZoomer类进行了改造,以支持仅水平缩放功能。改造如下:

1、拷贝QwtPlotZoomer类

将QwtPlotZoomer类源代码拷贝出来,我们重命名为YPlotZoomer。保留QwtPlotZoomer类的所有内容。

2、改造头文件

在YPlotZoomer头文件中增加以下公共函数。

    // 增加坐标轴缩放使能函数
    void setAxisEnabled( int axis, bool on );
    bool isAxisEnabled( int axis ) const;
    // 重写Picker中橡皮筋绘制函数
    virtual void    drawRubberBand( QPainter *painter ) const;
    // 重写Picker中橡皮筋掩码区域函数
    virtual QRegion rubberBandMask() const;
    // 重写Picker中坐标跟踪标绘函数
    virtual QwtText trackerTextF( const QPointF &pos ) const;
    // end added

3、改造CPP文件

首先,在YPlotZoomer实现文件中增加坐标轴使能参数。

class YPlotZoomer::PrivateData
{
public:
    uint zoomRectIndex;
    QStack<QRectF> zoomStack;

    int maxStackDepth;

    // added by Yu.J 增加坐标轴缩放使能
    bool isAxisEnabled[QwtPlot::axisCnt];
    // end added
};

然后,修改rescale函数,在rescale函数中增加按坐标轴缩放实现代码。rescale函数是缩放末端实现函数,主要思想为通过判断坐标轴缩放使能,设置相应坐标轴的比例尺。

void AMCPlotZoomer::rescale()
{
    QwtPlot *plt = plot();
    if ( !plt )
        return;

    const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
    if ( rect != scaleRect() )
    {
        const bool doReplot = plt->autoReplot();
        plt->setAutoReplot( false );

        // modify by Yu.J 20200915 提供仅横坐标或仅纵坐标缩放的功能
        if ( d_data->isAxisEnabled[QwtPlot::xTop] && d_data->isAxisEnabled[QwtPlot::xBottom] )
        {
            double x1 = rect.left();
            double x2 = rect.right();
            if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() )
                qSwap( x1, x2 );

            plt->setAxisScale( xAxis(), x1, x2 );
        }

        if ( d_data->isAxisEnabled[QwtPlot::yLeft] && d_data->isAxisEnabled[QwtPlot::yRight] )
        {
            double y1 = rect.top();
            double y2 = rect.bottom();
            if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() )
                qSwap( y1, y2 );

            plt->setAxisScale( yAxis(), y1, y2 );
        }
        // end modify

        plt->setAutoReplot( doReplot );

        plt->replot();
    }
}

最后,重写橡皮筋相关函数。这里主要是框选的时候绘制的是矩形框,但我们设置了仅水平缩放,因此希望修改为按水平进行框选,并且显示文字要显示我们水平框选的范围。核心思想是通过重写QwtPicker类中的橡皮筋相关函数,修改绘制矩形框,修改显示文字。重写代码如下。

// added by Yu.J 定制RubberBand(橡皮筋)绘制
void YPlotZoomer::drawRubberBand( QPainter *painter ) const
{
    if ( !isActive() || rubberBand() == NoRubberBand ||
         rubberBandPen().style() == Qt::NoPen )
    {
        return;
    }

    const QPolygon pa = selection();

    if ( pa.count() < 2 )
        return;

    QRect rect = QRect( pa.first(), pa.last() ).normalized();
    // 横轴缩放,扩展绘制矩形选择框

    if ( d_data->isAxisEnabled[QwtPlot::yLeft]==false || d_data->isAxisEnabled[QwtPlot::yRight] == false )
    {
        rect.setTop(0);
        rect.setBottom(plot()->height());
    }
    else if ( d_data->isAxisEnabled[QwtPlot::xBottom]==false || d_data->isAxisEnabled[QwtPlot::xTop] == false )
    {
        rect.setLeft(0);
        rect.setRight(plot()->width());
    }
    else
    {
        ;
    }

    QwtPainter::drawRect( painter, rect );
}

// added by Yu.J 定制RubberBand(橡皮筋)绘制
static inline QRegion qwtMaskRegion( const QRect &r, int penWidth )
{
    const int pw = qMax( penWidth, 1 );
    const int pw2 = penWidth / 2;

    int x1 = r.left() - pw2;
    int x2 = r.right() + 1 + pw2 + ( pw % 2 );

    int y1 = r.top() - pw2;
    int y2 = r.bottom() + 1 + pw2 + ( pw % 2 );

    QRegion region;

    region += QRect( x1, y1, x2 - x1, pw );
    region += QRect( x1, y1, pw, y2 - y1 );
    region += QRect( x1, y2 - pw, x2 - x1, pw );
    region += QRect( x2 - pw, y1, pw, y2 - y1 );

    return region;
}

// added by Yu.J 定制RubberBand(橡皮筋)绘制
QRegion YPlotZoomer::rubberBandMask() const
{
    QRegion mask;

    if ( !isActive() || rubberBand() == NoRubberBand ||
        rubberBandPen().style() == Qt::NoPen )
    {
        return mask;
    }

    const QPolygon pa = selection(); 

    if ( pa.count() < 2 )
        return mask;

    const int pw = rubberBandPen().width();
    QRect rect = QRect( pa.first(), pa.last() );
    // 横轴缩放,扩展绘制矩形选择框
    if ( d_data->isAxisEnabled[QwtPlot::yLeft]==false || d_data->isAxisEnabled[QwtPlot::yRight] == false )
    {
        rect.setTop(0);
        rect.setBottom(plot()->height());
    }
    else if ( d_data->isAxisEnabled[QwtPlot::xBottom]==false || d_data->isAxisEnabled[QwtPlot::xTop] == false )
    {
        rect.setLeft(0);
        rect.setRight(plot()->width());
    }
    else
    {
        ;
    }

    mask = qwtMaskRegion( rect.normalized(), pw );
    return mask;
}

// added by Yu.J 定制坐标显示
QwtText YPlotZoomer::trackerTextF( const QPointF &pos ) const
{

    const QPolygon pa = selection();

    QString s;
    if ( pa.count() < 2 || m_bIsEnd )
    {
        s = "x=" + QString::number(pos.x() , 'f' , 2 ) + ",y=" + QString::number(pos.y(), 'f' , 2 );
    }
    else
    {
        QRect rect = QRect( pa.first(), pa.last() ).normalized();
       
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值