QCustomPlot滑动区域放大与恢复

QCustomPlot 原生支持滑动区域放大,核心是使用 QCPSelectionRect 配合 QCP::srmZoom 模式。你只需启用对应设置,无需手动编写复杂的鼠标事件逻辑。

实现步骤

  1. 启用缩放模式 :通过 setSelectionRectMode(QCP::srmZoom) 告诉 QCustomPlot,当用户拖拽出矩形选区时,执行缩放操作。

  2. 配置生效的轴 :如果需要同时缩放 X 和 Y 轴,需确保 setRangeZoomAxes 包含这两个轴(默认通常已包含)。如果只想缩放 X 轴,则仅将 X 轴传入即可。

代码示例1

以下代码展示了如何开启滑动区域放大,并自定义选区的外观:

复制代码
// 假设 customPlot 是你的 QCustomPlot 指针

// 1. 开启矩形缩放模式
customPlot->setSelectionRectMode(QCP::srmZoom);

// 2. 获取当前的选区对象,并自定义样式(可选)
QCPSelectionRect *rect = customPlot->selectionRect();
if (rect) {
    // 设置选区边框为蓝色虚线
    rect->setPen(QPen(Qt::blue, 1, Qt::DashLine));
    // 设置选区内部填充为半透明蓝色
    rect->setBrush(QBrush(QColor(0, 0, 255, 30)));
}

// 3. 如果只希望缩放 X 轴,取消勾选 Y 轴(通常用于时域图表)
// QList<QCPAxis*> zoomAxes;
// zoomAxes << customPlot->xAxis;
// customPlot->axisRect()->setRangeZoomAxes(zoomAxes);

       //不开启矩形缩放模式
       customPlot->setSelectionRectMode(QCP::srmNone);

QCP::SelectionRectMode 的枚举定义。

四种模式对照

模式 行为
srmNone 禁用选区矩形,鼠标事件直接透传给底层对象(如轴拖动)
srmZoom 拖拽出选区,松手后自动 按 setRangeZoomAxes 缩放
srmSelect 拖拽选区,松手后选中选区内的数据点
srmCustom 拖拽出选区,松手后发 accepted 信号,一切处理由程序员负责

代码示例2

将框选区域放大到充满整个 QCustomPlot 控件,同时能一键恢复原始视图。

步骤:

  1. 用户框选时,QCPSelectionRect 会记录选区在屏幕坐标系 下的矩形 QRect

  2. 通过 axisRect()->rect() 与轴范围的比例关系,把屏幕矩形转换成轴数据范围

  3. 调用 xAxis->setRange() / yAxis->setRange() 让该区域充满整个控件

  4. 恢复时,保存原始轴范围,一键还原

复制代码
MyPlot.h
复制代码
class MyPlot : public QCustomPlot {
    Q_OBJECT
public:
    explicit MyPlot(QWidget *parent = nullptr);

    void restoreView();          // 恢复到非全控件显示

private slots:
    void onSelectionAccepted(const QRect &rect, QMouseEvent *event);

private:
    bool m_hasSavedRange = false;
    QCPRange m_savedXRange;      // 保存原始 X 轴范围
    QCPRange m_savedYRange;      // 保存原始 Y 轴范围
};
复制代码
MyPlot.cpp
复制代码
MyPlot::MyPlot(QWidget *parent) : QCustomPlot(parent)
{
    //  使用自定义选区模式,方便自己处理
    setSelectionRectMode(QCP::srmCustom);

    // 自定义选区外观
    QCPSelectionRect *selRect = selectionRect();
    selRect->setPen(QPen(Qt::red, 1, Qt::DashLine));
    selRect->setBrush(QBrush(QColor(255, 0, 0, 30)));

    // 连接 accepted 信号:用户松开鼠标、确认选区后触发
    disconnect(selRect, &QCPSelectionRect::accepted, nullptr, nullptr);
    connect(selRect, &QCPSelectionRect::accepted,
            this, &MyPlot::onSelectionAccepted);
}

void MyPlot::onSelectionAccepted(const QRect &rect, QMouseEvent *event)
{
    Q_UNUSED(event);

    // rect 是屏幕坐标系下的选区矩形(相对于 axisRect)
    if (rect.width() < 2 || rect.height() < 2)
        return;  // 选区太小,忽略

    // 首次缩放前保存原始范围,方便恢复
    if (!m_hasSavedRange) {
        m_savedXRange = xAxis->range();
        m_savedYRange = yAxis->range();
        m_hasSavedRange = true;
    }

    QCPAxisRect *ar = axisRect();

    // ---------- 计算 X 轴新范围 ----------
    // 把屏幕 x 坐标 映射到 轴数据坐标
    double x1 = xAxis->pixelToCoord(rect.left());
    double x2 = xAxis->pixelToCoord(rect.right());
    // 选区可能反向拖拽,保证下界 < 上界
    if (x1 > x2) std::swap(x1, x2);

    // ---------- 计算 Y 轴新范围 ----------
    double y1 = yAxis->pixelToCoord(rect.bottom());
    double y2 = yAxis->pixelToCoord(rect.top());
    if (y1 > y2) std::swap(y1, y2);

    // 设置新范围(该区域将充满整个控件)
    xAxis->setRange(x1, x2);
    yAxis->setRange(y1, y2);

    replot();
}

void MyPlot::restoreView()
{
    if (!m_hasSavedRange)
        return;  // 没有保存过,无需恢复

    xAxis->setRange(m_savedXRange);
    yAxis->setRange(m_savedYRange);
    m_hasSavedRange = false;  // 可选:下次缩放重新保存

    //取消可能的残留选择框
    QCPSelectionRect *selRect = ui->widgetWave2->selectionRect();
    if(selRect != nullptr){
       selRect->cancel();
    }

    replot();
}

关键点说明:

1、只缩放 X 轴 / 只缩放 Y 轴

如果你只想横向放大(时域图常见):

复制代码
xAxis->setRange(x1, x2);
// yAxis 保持原样,不调用 setRange

2、支持多次连续缩放

上面代码里用 m_hasSavedRange 标记,只在第一次 缩放前保存原始范围。这样即使用户连续框选放大多次,恢复时也能回到最初的完整视图。若你希望每次缩放都可回退一步,可以把范围存进 QList<QPair<QCPRange, QCPRange>> 做成栈。

3、按钮触发恢复

在 UI 上加一个按钮或右键菜单,调用 restoreView() 即可。

复制代码
connect(ui->btnReset, &QPushButton::clicked, myPlot, &MyPlot::restoreView);

4、 srmCustom 的正确姿势

复制代码
setSelectionRectMode(QCP::srmCustom);

connect(selectionRect(), &QCPSelectionRect::accepted,
        this, &MyPlot::onSelectionAccepted);

在 onSelectionAccepted 里你完全掌控

复制代码
void MyPlot::onSelectionAccepted(const QRect &rect, QMouseEvent *event)
{
    // 1. 保存原始范围(首次)
    // 2. 用 pixelToCoord 把屏幕矩形换算成数据范围
    // 3. 手动 setRange
    // 4. 想怎么处理都行------限制最小范围、只缩 X、记录栈......
}
相关推荐
尘中远3 个月前
【Qwt 7.0 系列】坐标轴与刻度系统 —— 刻度引擎、网格、图例与刻度朝内
qt·数据可视化·qcustomplot·qwt·工业软件·科学绘图
尘中远3 个月前
【Qwt 7.0 系列】交互功能详解 —— 平移、缩放、坐标轴交互与数据拾取
qt·数据可视化·绘图·qcustomplot·qwt·科学绘图
尘中远3 个月前
【Qwt 7.0 系列】3D 数据可视化 —— OpenGL 高性能三维绘图
qt·3d·qcustomplot·qwt·科学绘图·高性能绘图
春蕾夏荷_7282977251 年前
qcustomplot 显示坐标轴
qt·qcustomplot·坐标轴
OldField-Tian1 年前
QCustomPlot 性能优化与问题排查
qcustomplot
十秒耿直拆包选手1 年前
Qt:QCustomPlot类介绍
c++·qt·qcustomplot
byxdaz1 年前
金融图QCPFinancial
qcustomplot
人还是要有梦想的2 年前
Qt画实时曲线图
qt·qcustomplot·实时折线图
hellokandy3 年前
Qt QCustomPlot 鼠标悬浮提示
qt·qcustomplot·qcptooltip