【Qwt 7.0 系列】交互功能详解 ------ 平移、缩放、坐标轴交互与数据拾取
本文是 Qwt 7.0 系列介绍和教程,如果你正在寻找一个高性能、协议友好、同时支持 2D 和 3D 绘图的 Qt 数据可视化库,那么这篇文章就是为你准备的。
系列总述文章:Qwt 7.0 ------ 基于 Qt 的高性能 2D/3D 绘图库
概述 | 高性能曲线绘制 | 常用图表类型 | 高级科学图表 | 多坐标轴与布局 | 交互功能 | 3D 数据可视化 | 坐标轴与刻度 | 控件与辅助元素 | 总体架构解析 | matplotlib 风格绘图
引言
交互是数据可视化的关键环节。一张静态的图表只能展示数据的一个切面,而通过平移、缩放、拾取等交互操作,用户才能在数据海洋中自由探索,发现隐藏的规律。
原版 Qwt 6.2 已经提供了平移和缩放功能,但随着使用场景的复杂化,它暴露出一些明显的不足:平移过程基于位图缓存导致体验不够流畅,缩放器绑定坐标轴数量有限,坐标轴无法直接操作,数据拾取需要开发者自己实现等。
Qwt 7.0 对交互功能进行了全面重构和增强,带来了一系列令人瞩目的新特性:
- 实时平移 :
QwtPlotPanner基于QwtPicker状态机重构,平移过程中绘图实时刷新 - 整体画布缩放 :
QwtPlotCanvasZoomer无需指定坐标轴,自动处理全部四轴 - 坐标轴内置交互:鼠标直接拖动、滚轮缩放坐标轴(7.0.5+ 新增)
- 数据拾取 :
QwtPlotSeriesDataPicker提供 Y 值拾取和最近点拾取(7.0.6+ 新增)
本文将逐一详解这些功能。
一、平移工具
1.1 缓存平移的痛点
原版 Qwt 6 的 QwtPlotPanner 采用基于缓存的平移机制:平移过程中显示的是一张缓存的位图,而非实时更新的绘图内容。这带来两个问题:
- 平移时看到的不是真实数据,视觉上有"拖动残影"的感觉
- 无法在平移过程中看到数据的实时变化
虽然缓存机制减少了重绘开销,但对视觉体验很不友好。
1.2 实时平移:QwtPlotPanner(7.0 新增)
Qwt 7.0 对 QwtPlotPanner 进行了完全重构,新的实现基于 QwtPicker 状态机机制,实现了实时平移------平移过程中绘图内容实时更新:

新的 QwtPlotPanner 提供了完整的坐标轴支持:
- 线性坐标轴(Linear Scale)
- 对数坐标轴(Logarithmic Scale)
- 日期时间坐标轴(DateTime Scale)
- 多坐标轴
基本用法非常简单:
cpp
#include "qwt_plot_panner.h"
#include "qwt_plot.h"
#include "qwt_plot_curve.h"
// 创建绘图和曲线
QwtPlot* plot = new QwtPlot;
QwtPlotCurve* curve = new QwtPlotCurve("Sine Wave");
curve->attach(plot);
// 创建实时平移器
QwtPlotPanner* panner = new QwtPlotPanner(plot->canvas());
// 配置鼠标按钮(默认中键平移)
panner->setMouseButton(Qt::MiddleButton);
// 也可以用左键平移
// panner->setMouseButton(Qt::LeftButton);
// 启用平移器
panner->setEnabled(true);
你还可以限制平移方向,只允许水平或垂直方向移动:
cpp
// 默认:水平 + 垂直
panner->setOrientations(Qt::Horizontal | Qt::Vertical);
// 仅水平
// panner->setOrientations(Qt::Horizontal);
// 仅垂直
// panner->setOrientations(Qt::Vertical);
注意:
QwtPlotPanner不需要绑定坐标轴,因为它针对整个画布操作,移动画布时所有坐标轴都会同步移动。
1.3 缓存平移:QwtPlotCachePanner(原 QwtPlotPanner)
如果你仍然想使用原来的缓存式平移,Qwt 7.0 保留了它,只是换了名字。以下是重要的类名变更:
| 原名称(Qwt 6) | 新名称(Qwt 7.0) | 说明 |
|---|---|---|
QwtPanner |
QwtCachePanner |
基类更名 |
QwtPlotPanner(旧) |
QwtPlotCachePanner |
绘图缓存平移器更名 |
QwtPolarPanner |
QwtPolarCachePanner |
极坐标缓存平移器更名 |
QwtPlotPanner(新) |
--- | 全新重构,基于 QwtPicker |
简单来说:Qwt 6 的 QwtPlotPanner 在 Qwt 7.0 中变成了 QwtPlotCachePanner,而 QwtPlotPanner 这个名字被新的实时平移器"夺走"了。接口保持不变,原有代码基本无需修改即可使用 QwtPlotCachePanner。
二、缩放工具
2.1 缩放器的两个选择
在 Qwt 6 中,QwtPlotZoomer 需要指定两个坐标轴来进行缩放。如果你的绘图有四个坐标轴(上下左右都显示数据),就需要创建两个缩放器:
cpp
// Qwt 6 传统用法 - 需要两个缩放器来覆盖四个坐标轴
QwtPlotZoomer* zoomer1 = new QwtPlotZoomer(QwtAxis::XBottom, QwtAxis::YLeft, canvas);
QwtPlotZoomer* zoomer2 = new QwtPlotZoomer(QwtAxis::XTop, QwtAxis::YRight, canvas);
这既繁琐又容易遗漏。Qwt 7.0 提供了两个缩放器,分工明确:
| 特性 | QwtPlotAxisZoomer |
QwtPlotCanvasZoomer |
|---|---|---|
| 坐标轴绑定 | 需要指定 X 和 Y 轴 | 自动处理所有四个坐标轴 |
| 使用场景 | 特定坐标轴缩放 | 整体画布缩放 |
| 寄生绘图支持 | 需手动绑定 | 自动支持所有寄生绘图 |
2.2 QwtPlotAxisZoomer(原 QwtPlotZoomer)
QwtPlotAxisZoomer 就是原来的 QwtPlotZoomer,重命名以区分新的画布缩放器。它绑定两个特定的坐标轴:
cpp
#include "qwt_plot_axis_zoomer.h"
// 创建针对特定坐标轴的缩放器
QwtPlotAxisZoomer* axisZoomer = new QwtPlotAxisZoomer(
QwtAxis::XBottom, // X 轴
QwtAxis::YLeft, // Y 轴
plot->canvas(), // 画布
true // 自动重绘
);
// 或者使用默认坐标轴(XBottom + YLeft)
QwtPlotAxisZoomer* defaultZoomer = new QwtPlotAxisZoomer(plot->canvas());
2.3 QwtPlotCanvasZoomer(7.0 新增)
QwtPlotCanvasZoomer 是 Qwt 7.0 新增的缩放器,无需指定坐标轴,自动对整个画布进行缩放。这对多坐标轴和寄生绘图场景特别友好:
cpp
#include "qwt_plot_canvas_zoomer.h"
// 创建整体画布缩放器,自动处理所有坐标轴
QwtPlotCanvasZoomer* canvasZoomer = new QwtPlotCanvasZoomer(plot->canvas());
一行代码搞定,简洁明了。
2.4 默认按键绑定
两个缩放器的按键绑定完全一致:
鼠标操作:
| 操作 | 默认按钮 | 功能描述 |
|---|---|---|
| 缩放选择 | 左键拖拽 | 选择矩形区域进行缩放 |
| 回到基准 | 右键点击 | 缩放到基准视图(完全缩小) |
| 后退一级 | 中键点击 | 后退一级缩放 |
| 前进一级 | 中键+Shift 点击 | 前进一级缩放 |
键盘操作:
| 操作 | 默认按键 | 功能描述 |
|---|---|---|
| 前进一级 | + |
前进一级缩放 |
| 后退一级 | - |
后退一级缩放 |
| 回到基准 | Escape |
回到基准视图 |
2.5 自定义按键
如果默认按键不满足需求,可以自定义:
cpp
// 配置键盘快捷键
zoomer->setKeyPattern(QwtEventPattern::KeyRedo, Qt::Key_Plus, Qt::ShiftModifier); // 前进
zoomer->setKeyPattern(QwtEventPattern::KeyUndo, Qt::Key_Minus, Qt::ShiftModifier); // 后退
zoomer->setKeyPattern(QwtEventPattern::KeyHome, Qt::Key_Escape); // 重置
// 配置鼠标模式:中键重置,右键回退
zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::MiddleButton);
zoomer->setMousePattern(QwtEventPattern::MouseSelect3, Qt::RightButton);
三、坐标轴内置交互动作(7.0.5+ 新增)
3.1 直接操作坐标轴
这是一个非常实用的新特性。在 Qwt 6 及更早版本中,用户无法直接操作坐标轴------所有的平移和缩放都发生在画布上。从 Qwt 7.0.5 开始,你可以用鼠标直接拖动坐标轴来平移,用滚轮在坐标轴上缩放。
这个功能的设计灵感来源于 QCustomPlot 的交互机制。启用后,用户可以在任意坐标轴上:
- 左键单击选中坐标轴
- 左键拖动平移坐标轴范围,绘图区域实时更新
- 滚轮缩放,缩放中心位于鼠标当前位置
- 右键单击取消选中状态
坐标轴拖动效果:

坐标轴滚轮缩放效果:

3.2 启用与配置
坐标轴交互功能通过 QwtPlotScaleEventDispatcher 类实现事件分发,但用户通常无需直接接触这个类,只需调用 QwtPlot::setEnableScaleBuildinActions 即可:
cpp
// Qwt 7 默认启用坐标轴交互
// 如需手动控制:
plot->setEnableScaleBuildinActions(true); // 启用
// plot->setEnableScaleBuildinActions(false); // 禁用
3.3 单轴自定义
你可以针对特定坐标轴配置不同的交互行为。QwtScaleWidget 使用 BuiltinActions 枚举来定义内置动作:
cpp
// 仅让 XBottom 轴支持拖动,不支持滚轮缩放
plot->axisWidget(QwtAxis::XBottom)->setBuildinActions(
QwtScaleWidget::ActionClickPan);
// 查询当前配置
auto flags = plot->axisWidget(QwtAxis::XBottom)->buildinActions();
// 检查某个动作是否激活
bool canPan = plot->axisWidget(QwtAxis::XBottom)->testBuildinActions(
QwtScaleWidget::ActionClickPan);
3.4 选中效果自定义
坐标轴被选中时,默认文字和轴线颜色变为蓝色。你可以自定义这个选中颜色,以及选中后轴线粗细的变化:
cpp
// 设置选中颜色(默认蓝色)
plot->axisWidget(QwtAxis::XBottom)->setSelectionColor(QColor(255, 100, 0));
// 设置选中后画笔宽度偏移(默认 1,即选中后线条加粗 1 像素)
plot->axisWidget(QwtAxis::XBottom)->setSelectedPenWidthOffset(2);
效果如下图所示,选中坐标轴后轴线变粗、颜色变化:

四、数据拾取:QwtPlotSeriesDataPicker(7.0.6+ 新增)
4.1 为什么需要数据拾取
数据拾取是绘图控件的常见需求:用户移动鼠标时,实时显示当前位置对应的数据值。在 Qwt 6 中,这个功能需要开发者自己实现,涉及坐标转换、数据查找、文本绘制等繁琐工作。
从 Qwt 7.0.6 开始,Qwt 新增了 QwtPlotSeriesDataPicker 类,开箱即用,支持两种拾取模式、线性插值、多曲线、高性能优化等特性:

核心特性一览:
- 双模式拾取:Y 值拾取 + 最近点拾取
- 智能插值:线性插值计算,数据点之间也能精确取值
- 高性能优化:二分查找 + 窗口搜索算法,支持大数据集
- 多曲线支持:同时拾取多条曲线的数据
- 自定义显示:文本样式、特征点绘制、背景均可定制
- 寄生绘图支持:支持宿主绘图和寄生绘图的数据获取
4.2 基本用法
cpp
#include "qwt_plot_series_data_picker.h"
// 创建绘图对象
QwtPlot* plot = new QwtPlot(this);
// 创建数据拾取器,传入 canvas 即可
QwtPlotSeriesDataPicker* picker = new QwtPlotSeriesDataPicker(plot->canvas());
// 设置拾取模式
picker->setPickMode(QwtPlotSeriesDataPicker::PickYValue);
// 启用线性插值
picker->setInterpolationMode(QwtPlotSeriesDataPicker::LinearInterpolation);
// 设置文本显示位置(自动选择)
picker->setTextArea(QwtPlotSeriesDataPicker::TextPlaceAuto);
4.3 Y 值拾取模式
Y 值拾取模式显示当前 X 位置对应所有曲线的 Y 值。当鼠标在画布上移动时,拾取器会画一条垂直辅助线,并在每条曲线上标记对应 Y 值的位置:

cpp
// Y 值拾取模式(默认)
picker->setPickMode(QwtPlotSeriesDataPicker::PickYValue);
插值是该模式的亮点。当数据点比较稀疏时,拾取器会通过线性插值计算出当前 X 轴位置对应的 Y 值,而非简单取最近点。插值默认开启,也可以关闭:
cpp
// 关闭插值,使用最近的数据点
picker->setInterpolationMode(QwtPlotSeriesDataPicker::NoInterpolation);
4.4 最近点拾取模式
最近点拾取模式计算距离鼠标最接近的数据点并显示。这个模式特别适合频谱图等需要拾取峰值的场景:

cpp
// 最近点拾取模式
picker->setPickMode(QwtPlotSeriesDataPicker::PickNearestPoint);
4.5 性能优化:窗口搜索算法
最近点拾取需要计算曲线每个点到鼠标的距离,全曲线遍历会非常耗时。为此,Qwt 7.0 提供了窗口搜索算法:
cpp
// 设置搜索窗口大小
void setNearestSearchWindowSize(int windowSize);
int nearestSearchWindowSize() const;
窗口大小支持三种设置方式:
| 设置值 | 含义 |
|---|---|
0 |
不使用窗口,搜索整个曲线 |
| 正数 | 固定窗口大小(数据点数量) |
| 负数 | 自适应窗口,取绝对值百分比(如 -5 表示曲线点数的 5%) |
默认值为 -5,即曲线点数的 5%。需要注意的是,窗口优化算法默认在曲线点数超过 1000 时才生效,点数较少时直接全量搜索。
此外,窗口优化算法要求曲线数据按 X 坐标升序排列。使用自定义数据源时请确保数据已排序。
4.6 自定义显示文本
通过继承 QwtPlotSeriesDataPicker 并重写 valueString 方法,可以自定义数据点的显示格式:
cpp
class CustomDataPicker : public QwtPlotSeriesDataPicker {
public:
explicit CustomDataPicker(QWidget* canvas) : QwtPlotSeriesDataPicker(canvas) {}
protected:
QString valueString(const QPointF& value, QwtPlotItem* item,
size_t seriesIndex, int order) const override {
Q_UNUSED(seriesIndex);
if (pickMode() == PickYValue) {
QString text;
if (order != 0) {
text += "\n"; // 非第一个点需要换行
}
text += QString("%1: %2 (X=%3)")
.arg(item->title().text())
.arg(value.y(), 0, 'f', 3)
.arg(value.x(), 0, 'f', 3);
return text;
}
return QString("坐标: (%1, %2)").arg(value.x()).arg(value.y());
}
};
valueString 的 order 参数表示当前是第几个特征点,多条曲线时递增,可根据它是否为 0 决定是否换行。
4.7 特征点与文本样式
拾取到的数据点称为"特征点",会在曲线上标记出来:
cpp
// 启用特征点标记
picker->setEnableDrawFeaturePoint(true);
// 设置特征点大小(像素)
picker->setDrawFeaturePointSize(6);
// 自定义文本背景
picker->setTextBackgroundBrush(QBrush(QColor(255, 255, 255, 180)));
// 设置文本对齐方式
picker->setTextAlignment(Qt::AlignLeft | Qt::AlignTop);
4.8 点击信号与数据获取
QwtPlotSeriesDataPicker 提供了点击信号,方便响应用户操作:
cpp
// 单击信号
void clicked(QwtPlotSeriesDataPicker* picker, const QPoint& pos);
// 双击信号
void doubleClicked(QwtPlotSeriesDataPicker* picker, const QPoint& pos);
点击信号仅响应鼠标左键。双击时会先触发
clicked()再触发doubleClicked(),这是 Qt 的标准行为。
通过 featurePoints() 方法可以获取当前拾取到的数据点信息:
cpp
struct FeaturePoint {
QwtPlotItem* item { nullptr }; // 对应的曲线项
QPointF feature { 0, 0 }; // 特征点坐标
size_t index { 0 }; // 在曲线数据中的索引
};
// 获取当前拾取到的特征点列表
QList<FeaturePoint> featurePoints() const;
使用示例:
cpp
connect(picker, &QwtPlotSeriesDataPicker::clicked,
[](QwtPlotSeriesDataPicker* p, const QPoint& pos) {
Q_UNUSED(pos);
QList<QwtPlotSeriesDataPicker::FeaturePoint> fps = p->featurePoints();
for (const auto& fp : fps) {
if (fp.item) {
qDebug() << "曲线:" << fp.item->title().text()
<< "X:" << fp.feature.x()
<< "Y:" << fp.feature.y()
<< "索引:" << fp.index;
}
}
});
4.9 多子图联动:QwtPlotSeriesDataPickerGroup
在多子图布局中,QwtPlotSeriesDataPickerGroup 可以实现跨图数据联动。当用户点击某个子图时,组内其他 picker 会自动同步到相同的 X 轴比例位置:
cpp
#include "qwt_plot_series_data_picker_group.h"
// 创建 Group 并添加多个 picker
QwtPlotSeriesDataPickerGroup* pickerGroup = new QwtPlotSeriesDataPickerGroup(this);
pickerGroup->addPicker(picker1);
pickerGroup->addPicker(picker2);
pickerGroup->addPicker(picker3);
// 连接 Group 的点击信号
connect(pickerGroup, &QwtPlotSeriesDataPickerGroup::clicked,
this, [this](QwtPlotSeriesDataPicker* picker, const QPoint& pos) {
Q_UNUSED(pos);
// 此时所有 picker 已同步,可获取所有子图的数据
for (auto* p : { picker1, picker2, picker3 }) {
auto fps = p->featurePoints();
if (!fps.isEmpty()) {
qDebug() << "Y value:" << fps.first().feature.y();
}
}
});
Group 在发出点击信号之前会先同步所有 picker 的位置,这意味着信号触发时所有 picker 的 featurePoints() 都已更新,非常适合多子图联动检视。
五、Picker 状态机简介
前面多次提到 QwtPlotPanner 基于 QwtPicker 状态机实现,这里简要介绍一下状态机的概念,帮助理解 Qwt 7.0 交互功能的底层机制。
5.1 为什么需要状态机
图形交互中,用户的操作往往是一个有序的事件序列,而非单一动作。比如拖拽操作 = 按下鼠标 → 移动鼠标 → 释放鼠标。如果没有状态机管理,我们需要在事件处理函数中写大量 if-else 分支和状态变量,代码会变得难以维护。
Qwt 的 QwtPicker 使用状态机来管理交互过程,将事件序列的识别 与具体业务操作分离:
- 状态机负责识别完整的事件序列(按下→移动→释放)
QwtPicker负责执行具体的绘制、选择等操作
5.2 工作原理
QwtPicker 的事件处理流程如下:
事件流: QEvent → QwtPicker → QwtPickerMachine → Commands → QwtPicker方法
状态机将具体的绘图动作抽象为五种命令:
| 命令 | 描述 |
|---|---|
Begin() |
开始选择 |
Append() |
添加点 |
Move() |
移动点 |
Remove() |
删除点 |
End() |
结束选择 |
状态机分析事件后返回命令序列,QwtPicker 依次执行这些命令。以拖拽点选择为例,核心逻辑如下:
cpp
QList<QwtPickerMachine::Command> QwtPickerDragPointMachine::transition(
const QwtEventPattern& eventPattern, const QEvent* event)
{
QList<QwtPickerMachine::Command> cmdList;
switch (event->type()) {
case QEvent::MouseButtonPress:
if (state() == 0) { // 初始状态
cmdList += Begin; // 开始选择
cmdList += Append; // 添加第一个点
setState(1); // 进入拖拽状态
}
break;
case QEvent::MouseMove:
if (state() != 0) // 在拖拽状态中
cmdList += Move; // 持续移动
break;
case QEvent::MouseButtonRelease:
if (state() != 0) {
cmdList += End; // 结束选择
setState(0); // 回到初始状态
}
break;
}
return cmdList;
}
状态转换非常清晰:状态 0(初始)→ 按下 → 状态 1(拖拽)→ 释放 → 状态 0。
5.3 常用内置状态机
Qwt 提供了多种预定义状态机,满足不同的交互需求:
| 状态机 | 用途 | 典型场景 |
|---|---|---|
QwtPickerTrackerMachine |
实时追踪鼠标位置 | 坐标显示、悬停提示 |
QwtPickerClickPointMachine |
单次点击选择一个点 | 点选数据点、快速定位 |
QwtPickerDragPointMachine |
拖拽选择点 | 精确位置选择、实时平移 |
QwtPickerClickRectMachine |
两次点击确定矩形 | 精确矩形选择 |
QwtPickerDragRectMachine |
拖拽选择矩形 | 快速缩放、区域选择 |
QwtPickerDragLineMachine |
拖拽选择线段 | 距离测量、角度测量 |
QwtPickerPolygonMachine |
多次点击创建多边形 | 复杂区域选择、多边形绘制 |
理解状态机的工作原理,不仅有助于正确使用 Qwt 的交互组件,还能在需要自定义交互模式时,通过继承 QwtPickerMachine 快速实现。
六、与旧版本的区别总结
下表汇总了 Qwt 7.0 交互功能与 Qwt 6 的核心区别:
| 功能 | Qwt 6 | Qwt 7.0 |
|---|---|---|
| 平移 | QwtPlotPanner(缓存平移) |
QwtPlotPanner(实时平移,重构)+ QwtPlotCachePanner(缓存平移) |
| 缩放 | QwtPlotZoomer(绑定 2 轴) |
QwtPlotAxisZoomer(绑定 2 轴)+ QwtPlotCanvasZoomer(整体画布缩放) |
| 坐标轴交互 | 不支持 | 7.0.5+ 支持鼠标拖动和滚轮缩放 |
| 数据拾取 | 需自行实现 | 7.0.6+ 内置 QwtPlotSeriesDataPicker |
| 多子图联动 | 无 | QwtPlotSeriesDataPickerGroup 支持同步 |
类名变更速查(重要):
| 旧名(Qwt 6) | 新名(Qwt 7.0) | 说明 |
|---|---|---|
QwtPanner |
QwtCachePanner |
缓存平移基类更名 |
QwtPlotPanner |
QwtPlotCachePanner |
缓存平移器更名 |
QwtPolarPanner |
QwtPolarCachePanner |
极坐标缓存平移器更名 |
QwtPlotZoomer |
QwtPlotAxisZoomer |
轴缩放器更名 |
迁移提示:如果你从 Qwt 6 迁移到 7.0,只需将旧的
QwtPlotPanner替换为QwtPlotCachePanner,将QwtPlotZoomer替换为QwtPlotAxisZoomer,接口保持不变。或者直接使用新的实时平移QwtPlotPanner和整体画布缩放QwtPlotCanvasZoomer,体验更佳。
总结
Qwt 7.0 的交互功能相比 Qwt 6 有了质的提升:
- 实时平移让数据探索更流畅,告别缓存残影
- 整体画布缩放简化了多坐标轴场景的配置
- 坐标轴内置交互让用户可以直接操作坐标轴,交互更直观
- 数据拾取器开箱即用,支持双模式、插值、多子图联动,大幅减少开发工作量
- 底层的 Picker 状态机机制让自定义交互也变得清晰可控
类名变更是迁移时最需要注意的地方,但接口保持不变,迁移成本很低。如果你是新项目,直接使用 7.0 的新组件即可获得最佳体验。
系列文章
- 第 1 篇:快速入门与核心新特性概览
- 第 2 篇:曲线绘图详解 ------ 从基础到百万级数据性能优化
- 第 3 篇:常用图表类型实战 ------ 柱状图、散点图、箱线图与直方图
- 第 4 篇:高级科学图表 ------ 光谱图、向量场、K线图与极坐标绘图
- 第 5 篇:多坐标轴与多绘图布局 ------ 寄生绘图与 QwtFigure 容器
- 第 6 篇:交互功能详解 ------ 平移、缩放、坐标轴交互与数据拾取
- 第 7 篇:3D 数据可视化 ------ OpenGL 高性能三维绘图
- 第 8 篇:坐标轴与刻度系统 ------ 刻度引擎、网格、图例与刻度朝内
- 第 9 篇:控件与辅助元素 ------ 滑块旋钮、标记与装饰
- 第 10 篇:总体架构解析 ------ 从单体到三库模块化的演进
- 第 11 篇:matplotlib 风格绘图 ------ QwtPyPlot 接口详解
相关链接