Qwt寄生绘图使用指南¶
寄生绘图(Parasite Axes)是 QwtPlot 中在同一个绘图区域内创建多个具有不同刻度和标签的坐标轴。寄生绘图与宿主绘图持有共同的绘图区域(寄生绘图的绘图区域是透明颜色),但可以拥有独立的坐标系统,这在需要展示不同量级或单位的数据时特别有用。
寄生绘图的工作原理¶
寄生绘图是通过 QwtPlot::createParasiteAxes 或 QwtFigure::createParasiteAxes (QwtFigure::createParasiteAxes内部实际也是调用QwtPlot::createParasiteAxes)方法创建的,它属于宿主绘图的子窗口。
寄生绘图具有以下特点:
- 绘图区域尺寸一致:寄生绘图与宿主绘图的绘图区域保持一致
- 独立坐标系统:寄生绘图可以有自己的刻度范围和标签
- 透明背景:寄生绘图具有透明背景,只显示坐标轴本身和绘制的曲线
- 自动同步:可以选择性地与宿主绘图共享 X 轴或 Y 轴的刻度
创建寄生绘图¶
寄生绘图通过 QwtPlot::createParasiteAxes 方法创建,该方法定义如下:
1 | |
enableAxis为寄生绘图显示的坐标轴,此时寄生绘图只会显示此坐标轴,其他坐标轴隐藏
该方法创建的寄生绘图对象,与宿主绘图的绘图区域是保持一致的,但它可以拥有独立的坐标系统,此时宿主绘图内部会记录绑定的寄生绘图对象,当宿主绘图被销毁时,寄生绘图也会被销毁。
宿主绘图的尺寸改变时会同时调整寄生绘图的尺寸,宿主绘图会让所有的寄生绘图尺寸和其保持一致
下面是创建寄生绘图的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
上面代码运行效果如下:

要创建寄生绘图,首先需要创建宿主绘图,寄生绘图是在宿主绘图基础上通过QwtPlot::createParasitePlot函数创建,此函数返回寄生绘图的指针;寄生绘图的对象也是QwtPlot,通过函数QwtPlot::isHostPlot和QwtPlot::isParasitePlot可以区分这个绘图是寄生绘图还是宿主绘图。如果当前是寄生绘图,可以通过QwtPlot::hostPlot获取宿主绘图指针,如果当前是宿主绘图,可以通过QwtPlot::parasitePlots获取所有寄生绘图指针
注意
一个绘图不会既是寄生绘图也是宿主绘图的情况,也就是说,如果绘图是寄生绘图,那么他自身不允许再创建寄生绘图,在寄生绘图上调用createParasitePlot将返回nullptr
寄生绘图创建后,可以按照正常绘图那样设置它的属性
通过QwtPlot::setParasiteShareAxis可以设置寄生绘图和宿主绘图共享的坐标轴。例如寄生绘图设置x轴和宿主绘图共享,那么在寄生绘图上应调用setParasiteShareAxis(QwtAxis::XBottom)
Qwt允许创建多个寄生绘图,实现任意多的坐标轴叠加,只要在宿主绘图上继续调用createParasitePlot即可再创建一个寄生绘图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
上面代码运行效果如下:

寄生绘图的层级关系¶
寄生绘图有层级关系,寄生绘图的层级关系主要决定了寄生轴的布局顺序,首先添加的寄生绘图位于最低层级,最后添加的寄生绘图处于最高层级
布局过程中宿主绘图布局完成后,开始布局寄生绘图,优先布局低层级的寄生绘图,也就是层级越低的寄生绘图的轴越接近宿主绘图,层级越高的寄生绘图的坐标轴越远离宿主绘图
寄生绘图的布局¶
寄生绘图的布局由寄生绘图布局管理器和宿主绘图共同完成,寄生绘图布局管理器由QwtParasitePlotLayout类实现,它继承QwtPlotLayout
classDiagram
class QwtPlotLayout {
-QwtPlot* m_plot
+activate(QWidget*, QRectF&, int[])
+invalidate()
}
class QwtPlotParasiteLayout {
+activate(QWidget*, QRectF&, int[])
+parasiteScaleRect(QwtAxisId): QRectF
}
QwtPlotLayout <|-- QwtPlotParasiteLayout
QwtParasitePlotLayout类的activate函数会计算寄生轴的各个轴的窗口大小,通过parasiteScaleRect可以获取到这个尺寸,这个尺寸的作用是给宿主绘图布局寄生绘图的轴坐标使用,这里不要使用QwtParasitePlotLayout::scaleRect函数获取寄生绘图的轴尺寸,这个函数获取的尺寸是和宿主绘图一样的
宿主绘图通过QwtPlot::updateAxisEdgeMargin函数来布局各个寄生绘图的轴坐标
每个轴通过QwtScaleWidget::margin和QwtScaleWidget::edgeMargin两个参数,控制轴到绘图区域和轴到绘图边界的距离
例如,下面代码的效果如下图所示
1 2 3 4 | |

- margin:决定了坐标轴靠近绘图区域边界到绘图区域的距离,默认为0紧贴绘图区域
- edgeMargin:决定了坐标轴靠近绘图边界区域到绘图边界的距离,默认为0紧贴绘图边框
上面这两个参数即可实现一个寄生绘图的坐标轴的正常显示
QwtPlot::updateAxisEdgeMargin/QwtPlot::updateAllAxisEdgeMargin函数用于自动计算寄生绘图和宿主绘图的margin和edgeMargin,避免轴层之间重叠
大致计算过程如下:
- 收集宿主及所有可见寄生轴的“净”矩形(已剔除旧的 edgeMargin 与 margin)
- 对每i层:
- margin = 0 ~ i-1 层净矩形尺寸之和
- edgeMargin = i+1 ~ 末层净矩形尺寸之和
- 将新值设置给对应轴的 QwtScaleWidget
- 宿主的 margin 予以保留(不覆盖用户可能手工设置的值)。
注意
QwtPlot::updateAxisEdgeMargin/QwtPlot::updateAllAxisEdgeMargin不会改变宿主绘图的margin属性
在添加寄生轴后,绘图显示前,你应该手动调用updateAllAxisEdgeMargin来更新寄生绘图坐标轴的布局
寄生绘图的相关操作¶
寄生绘图的相关操作¶
获取所有绘图项¶
对于 QwtPlotItem 的遍历,不能仅处理宿主绘图,还需要考虑所有寄生绘图。
通常事件处理会绑定到宿主绘图,您可以获取宿主绘图的指针,通过 QwtPlot::plotList 函数获取该绘图的所有图层。此函数默认按升序返回所有绘图,宿主绘图自身位于列表的第一个元素。
然后通过 itemList 获取各自图层的 QwtPlotItem 列表进行处理,示例代码如下:
1 2 3 4 5 6 7 | |
注意
任意绘图调用 QwtPlot::plotList 函数都能返回所有绘图列表,无论在寄生绘图还是宿主绘图中调用,结果相同。
处理坐标变换¶
Qwt6 提供了多种坐标转换函数辅助绘图时的坐标转换。由于 Qwt6 在设计时未充分考虑寄生绘图,部分坐标转换函数的实现可能存在兼容性问题,例如:
1 2 3 4 | |
上述函数都是针对固定 X 轴和 Y 轴的坐标变换,在存在寄生绘图的情况下无法正确工作。
对于存在寄生绘图的坐标变换,应避免使用固定轴的变换方法,而是通过 QwtPlotItem 获取对应的坐标变换对象进行处理。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 | |
上述代码将坐标点 valuePoint 转换到各自绘图项对应坐标轴的屏幕坐标,是提前知道当前的绘图窗口情况下,如果未知绘图窗口,仅仅只有QwtPlotItem,你可以这样处理。
1 2 3 4 5 6 7 8 9 10 11 12 | |
坐标转换示例
可参考 QwtPlotSeriesDataPicker 类中 pickYValue 和 pickNearestPoint 的实现,该类用于拾取曲线点,已考虑寄生绘图的情况。
注意事项¶
1. 生命周期管理¶
- 寄生绘图的生命周期与宿主绘图绑定
- 当宿主绘图被移除或销毁时,寄生绘图也会自动被清理
- 不需要手动删除寄生绘图对象
2. 布局限制¶
- 寄生绘图不能作为
QwtFigure当前激活的坐标轴 - 寄生绘图不参与
QwtFigureLayout的布局计算 - 寄生绘图会设置
Qt::WA_TransparentForMouseEvents属性,也就是它不会接受任何鼠标事件,鼠标事件都会被宿主绘图处理 - 寄生绘图的位置由宿主绘图控制
寄生绘图示例
完整的示例代码可参阅examples/parasitePlot