QT实现曲线图缩放、拖拽以及框选放大

发布于:2025-05-09 ⋅ 阅读:(15) ⋅ 点赞:(0)

.h文件

protected:    
    void saveAxisRange();
    void wheelEvent(QWheelEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    QPoint m_lastPoint;
    bool m_isPress = false;  //这里我把平移的判定初始化成了false,解决鼠标一移进QchartView就跟随移动的情况
    bool m_ctrlPress;
    bool m_alreadySaveRange;
    double m_xMin, m_xMax, m_yMin, m_yMax;
    QGraphicsSimpleTextItem* m_coordItem;

    // 框选
    bool m_isSelecting = false;        // 是否正在框选
    QPoint m_selectionStart;           // 框选起点
    QGraphicsRectItem* m_selectionRect = nullptr; // 选框图形项

.cpp文件

void saveAxisRange()
{
    QValueAxis *axisX = dynamic_cast<QValueAxis*>(this->chart()->axisX());
    m_xMin = axisX->min();
    m_xMax = axisX->max();
    QValueAxis *axisY = dynamic_cast<QValueAxis*>(this->chart()->axisY());
    m_yMin = axisY->min();
    m_yMax = axisY->max();
}

void wheelEvent(QWheelEvent *event)
{
     获取当前轴的缩放因子(0.9为缩小,1.1为放大)
    //const double zoomFactor = 0.9;
    //const double minRange = 0.01; // 防止缩放到负数或过小

     获取当前轴范围
    //QValueAxis* axisX = qobject_cast<QValueAxis*>(chart()->axes(Qt::Horizontal).first());
    //QValueAxis* axisY = qobject_cast<QValueAxis*>(chart()->axes(Qt::Vertical).first());
    //if(!axisX || !axisY)
    //{
    //    return;
    //}

     计算缩放方向(向上滚为缩小,向下滚为放大)
    //double delta = event->angleDelta().y() > 0 ? zoomFactor : 1.0 / zoomFactor;

     根据修饰键选择缩放轴
    //if(event->modifiers() & Qt::ControlModifier)
    //{
    //    // 缩放Y轴
    //    double newMinY = axisY->min() * delta;
    //    double newMaxY = axisY->max() * delta;
    //    if(newMaxY - newMinY > minRange)
    //    {
    //        axisY->setRange(newMinY, newMaxY);
    //    }
    //}
    //else
    //{
    //    // 缩放X轴
    //    double newMinX = axisX->min() * delta;
    //    double newMaxX = axisX->max() * delta;
    //    if(newMaxX - newMinX > minRange)
    //    {
    //        axisX->setRange(newMinX, newMaxX);
    //    }
    //}

    //event->accept();

    const QPoint curPos = event->pos();
    QPointF curVal = this->chart()->mapToValue(QPointF(curPos));

    if(!m_alreadySaveRange)
    {
        this->saveAxisRange();
        m_alreadySaveRange = true;
    }
    const double factor = 1.5;//缩放比例
    if(event->modifiers() & Qt::ControlModifier)
    {
        //Y轴
        QValueAxis *axisY = dynamic_cast<QValueAxis*>(this->chart()->axisY());
        const double yMin = axisY->min();
        const double yMax = axisY->max();
        const double yCentral = curVal.y();

        double bottomOffset;
        double topOffset;
        if(event->delta() > 0)
        {
            //放大
            bottomOffset = 1.0 / factor * (yCentral - yMin);
            topOffset = 1.0 / factor * (yMax - yCentral);
        }
        else
        {
            //缩小
            bottomOffset = 1.0 * factor * (yCentral - yMin);
            topOffset = 1.0 * factor * (yMax - yCentral);
        }

        this->chart()->axisY()->setRange(yCentral - bottomOffset, yCentral + topOffset);
    }
    else
    {
        //X轴
        QValueAxis *axisX = dynamic_cast<QValueAxis*>(this->chart()->axisX());
        const double xMin = axisX->min();
        const double xMax = axisX->max();
        const double xCentral = curVal.x();

        double leftOffset;
        double rightOffset;
        if(event->delta() > 0)
        {
            //放大
            leftOffset = 1.0 / factor * (xCentral - xMin);
            rightOffset = 1.0 / factor * (xMax - xCentral);
        }
        else
        {
            //缩小
            leftOffset = 1.0 * factor * (xCentral - xMin);
            rightOffset = 1.0 * factor * (xMax - xCentral);
        }
        this->chart()->axisX()->setRange(xCentral - leftOffset, xCentral + rightOffset);
    }
}

void mousePressEvent(QMouseEvent *event)
{
    //if(event->button() == Qt::LeftButton)
    //{
    //    m_lastPoint = event->pos();
    //    m_isPress = true;
    //}
    if(event->button() == Qt::LeftButton)
    {
        // 检测 Ctrl 键是否按下
        if(QApplication::keyboardModifiers() & Qt::ControlModifier)
        {
            // 开始框选
            m_isSelecting = true;
            m_selectionStart = event->pos();

            // 创建选框图形项
            if(!m_selectionRect)
            {
                m_selectionRect = new QGraphicsRectItem();
                m_selectionRect->setPen(QPen(Qt::blue, 1, Qt::DashLine));
                m_selectionRect->setBrush(QColor(100, 100, 255, 50));
                chart()->scene()->addItem(m_selectionRect);
            }
        }
        else
        {
            // 正常平移模式
            m_lastPoint = event->pos();
            m_isPress = true;
        }
    }
}

void mouseMoveEvent(QMouseEvent *event)
{
    /*if(!m_coordItem)
    {
        m_coordItem = new QGraphicsSimpleTextItem(this->chart());
        m_coordItem->setZValue(5);
        m_coordItem->setPos(100, 60);
        m_coordItem->show();
    }
    const QPoint curPos = event->pos();

    if(m_isPress)
    {
        QPoint offset = curPos - m_lastPoint;
        m_lastPoint = curPos;
        if(!m_alreadySaveRange)
        {
            this->saveAxisRange();
            m_alreadySaveRange = true;
        }
        this->chart()->scroll(-offset.x(), offset.y());
    }*/

    // 更新坐标显示(原功能保留)
    if(!m_coordItem)
    {
        m_coordItem = new QGraphicsSimpleTextItem(chart());
        m_coordItem->setZValue(5);
        m_coordItem->setPos(100, 60);
    }

    // 处理框选逻辑
    if(m_isSelecting)
    {
        // 更新选框图形
        QRectF rect(m_selectionStart, event->pos());
        m_selectionRect->setRect(rect.normalized());
    }
    // 处理平移逻辑
    else if(m_isPress)
    {
        QPoint offset = event->pos() - m_lastPoint;
        m_lastPoint = event->pos();
        if(!m_alreadySaveRange)
        {
            saveAxisRange();
            m_alreadySaveRange = true;
        }
        chart()->scroll(-offset.x(), offset.y());
    }
}

void mouseReleaseEvent(QMouseEvent *event)
{
    //m_isPress = false;
    //if(event->button() == Qt::RightButton)
    //{
    //    if(m_alreadySaveRange)
    //    {
    //        this->chart()->axisX()->setRange(m_xMin, m_xMax);
    //        this->chart()->axisY()->setRange(m_yMin, m_yMax);
    //    }
    //}

    if(event->button() == Qt::LeftButton)
    {
        if(m_isSelecting)
        {
            // 应用框选缩放
            QRectF rect = m_selectionRect->rect();
            QPointF topLeft = chart()->mapToValue(rect.topLeft());
            QPointF bottomRight = chart()->mapToValue(rect.bottomRight());

            chart()->axisX()->setRange(topLeft.x(), bottomRight.x());
            chart()->axisY()->setRange(bottomRight.y(), topLeft.y()); // Y轴方向反转

            // 清理选框
            chart()->scene()->removeItem(m_selectionRect);
            delete m_selectionRect;
            m_selectionRect = nullptr;
            m_isSelecting = false;
        }
        else
        {
            m_isPress = false;
        }
    }
    // 原右键恢复功能保留
    else if(event->button() == Qt::RightButton)
    {
        if(m_alreadySaveRange)
        {
            chart()->axisX()->setRange(m_xMin, m_xMax);
            chart()->axisY()->setRange(m_yMin, m_yMax);
        }
    }
}

构造函数中添加代码:

    grabGesture(Qt::PinchGesture);                              //这里只grabGesture了PinchGesture