Qt技巧笔记(十二):QCustomPlot绘图库结构分析
Qt技巧笔记(十二):QCustomPlot绘图库结构分析
学习一个陌生的库,我们首先要明确它有什么用,可以结合库官方examples,学习怎么简单的用。但是如果要对该库有一个全面的认识,还是需要了解它的开发思路和库结构。
QCustomPlot的架构设计分析且模块化,主要围绕图层、图元和布局三大核心概念构建。理解三者的关系,是掌握这个绘图库的关键。我们可以把QCustomPlot 想像成一个智能的空白画布,它是所有绘图活动的核心管理者。他不能仅负责与Qt的事件系统交互,更关键的是,它内部组织和协调几个关键部分:
- 图层列表:按顺序管理着所有用于绘制不同内容的图层。
- 布局系统:一个顶级的网格布局(
plotLayout),负责所有可见元素(如坐标矩形、图例)的自动定位和尺寸调整。 - 各种图元:包括用于展示数据的
plottable(如曲线、柱状体)和用于标识、装饰的items(如文本、箭头)。
下面的表格为你梳理了构成QCustomPlot的核心类以及各自得作用:
| 核心积木 | 基类 | 主要用途 | 常见子类举例 |
|---|---|---|---|
| 图层 (Layer) | QCPLayer |
控制不同元素的绘制顺序,实现分层渲染 | 背景层、网格层、主图层、坐标轴层等 |
可绘制对象 (Layerable) |
QCPLayerable |
所有可绘制元素的总基类,必须属于某个图层 | 几乎所有下面的类都派生自它 |
数据图元 (Plottable) |
QCPAbstractPlottable |
用于绘制和展示具体的数据系列 | QCPGraph (折线图)、QCPBars (柱状图) |
标识图元 (Item) |
QCPAbstractItem |
用于添加辅助性的图形或文字标记,通常不与数据强绑定 | QCPItemLine (线段)、QCPItemText (文本) |
布局元素 (Layout Element) |
QCPLayoutElement |
可被布局系统管理的元素,用于界面结构组织 | QCPAxisRect (坐标轴矩形)、QCPLegend (图例) |
其官方架构图(类关系图):
classDiagram
class QCustomPlot
class QCPLayer
class QCPLayerable
class QCPAbstractItem
class QCPItemAnchor
class QCPItemPosition
class QCPAxis
class QCPRange
class QCPGrid
class QCPAbstractPlottable
class QCPLayoutElement
class QCPLayoutGrid
class QCPLayoutInset
class QCPLegend
class QCPAbstractLegendItem
class QCPPlottableLegendItem
QCustomPlot --> QCPLayer : has one/multiple
QCPLayer --> QCPLayerable : contains and defines order
QCPLayerable <|-- QCPAbstractItem : inherits
QCPLayerable <|-- QCPAxis : inherits
QCPLayerable <|-- QCPAbstractPlottable : inherits
QCPLayerable <|-- QCPLayoutElement : inherits
QCPAbstractItem --> QCPItemAnchor : has one/multiple
QCPItemAnchor <|-- QCPItemPosition : is a
QCPAxis --> QCPRange : has one
QCPAxis --> QCPGrid : has one
QCPLayoutElement <|-- QCPLayoutGrid : is itself a
QCPLayoutGrid --> QCPLayoutInset : has one as insetLayout()
QCPLayoutGrid --> QCPLegend : usually has one
QCPLegend --> QCPAbstractLegendItem : has multiple
QCPAbstractLegendItem <|-- QCPPlottableLegendItem : is a
其中:
QCustomPlot是一个图表:包含一个或多个图层、一个或多个item(例如文本、线段等)、一个或多个可以绘制的元素、一个布局;QCPLayer是一个图层:包含基本的元素(QCPLayerable);QCPAbstractItem是标识图元虚基类;QCPAbstractPlottable是数据展示图元虚基类;QCPLayoutGrid是一个网格布局,可以插入QCPLayoutElement元素(文本元素QCPTextElement、坐标轴矩形QCPAxisRect);
classDiagram
direction LR // 核心修改:从左到右布局(Left to Right)
class QCPLayerable
class QCPAbstractPlottable
class QCPAbstractItem
class QCPLayoutElement
class QCPGrid
class QCPAxis
class QCPGraph
class QCPCurve
class QCPBars
class QCPStatisticalBox
class QCPColorMap
class QCPFinancial
class QCPItemStraightLine
class QCPItemLine
class QCPItemCurve
class QCPItemRect
class QCPItemEllipse
class QCPItemText
class QCPItemBracket
class QCPItemTracer
class QCPItemPixmap
class QCPAbstractLegendItem
class QCPLayout
class QCPAxisRect
class QCPTextElement
class QCPColorScale
class QCPPlottableLegendItem
class QCPLayoutGrid
class QCPLayoutInset
class QCPLegend
QCPLayerable <|-- QCPAbstractPlottable
QCPLayerable <|-- QCPAbstractItem
QCPLayerable <|-- QCPLayoutElement
QCPLayerable <|-- QCPGrid
QCPLayerable <|-- QCPAxis
QCPAbstractPlottable <|-- QCPGraph
QCPAbstractPlottable <|-- QCPCurve
QCPAbstractPlottable <|-- QCPBars
QCPAbstractPlottable <|-- QCPStatisticalBox
QCPAbstractPlottable <|-- QCPColorMap
QCPAbstractPlottable <|-- QCPFinancial
QCPAbstractItem <|-- QCPItemStraightLine
QCPAbstractItem <|-- QCPItemLine
QCPAbstractItem <|-- QCPItemCurve
QCPAbstractItem <|-- QCPItemRect
QCPAbstractItem <|-- QCPItemEllipse
QCPAbstractItem <|-- QCPItemText
QCPAbstractItem <|-- QCPItemBracket
QCPAbstractItem <|-- QCPItemTracer
QCPAbstractItem <|-- QCPItemPixmap
QCPLayoutElement <|-- QCPAbstractLegendItem
QCPLayoutElement <|-- QCPLayout
QCPLayoutElement <|-- QCPAxisRect
QCPLayoutElement <|-- QCPTextElement
QCPLayoutElement <|-- QCPColorScale
QCPAbstractLegendItem <|-- QCPPlottableLegendItem
QCPLayout <|-- QCPLayoutGrid
QCPLayout <|-- QCPLayoutInset
QCPLayoutGrid <|-- QCPLegend
在一个QCustomPlot类图中,最重要且用的最多的是QCPLayerable元素,几乎除了QCPLayer以外的元素都是继承自该类;
QCPAbstractPlottable:数据展示图元,包含:QCPGraph(折线图)、QCPCurve(曲线图)、QCPBars(柱状图)、QCPStatiBox(盒子图)、QCPColorMap(色谱图)、QCPFinancial(金融图);QCPAbstractItem:标识图元,包含:直线(QCPItemStraightLine)、线段(QCPItemLine)、曲线(QCPItemCurve)、矩形(QCPItemRect)、椭圆(QCPItemEllipse)、文本(QCPItemText)、小圆球(QCPItemTracer)、图片(QCPItemPixmap)、括弧(QCPItemBracket);QCPLayoutElement:布局项;QCPGrid:网格线,每一个坐标轴对应一个网格线;QCPAxis:坐标轴,一个坐标轴矩形包含四个坐标轴,上下左右四个坐标轴;
由此可以看出QCustomPlot的几个设计原则:
1.核心继承关系:一切始于 QCPLayerable
当你深入查看类继承图时,会发现几乎所有能在画布上显示出来的东西,都有一个共同的祖先——QCPLayerable(可分层对象)。这种设计的精妙之处在于,它将绘制内容与绘制层次这两个概念解耦了。任何QCPLayerable的派生类,都可以被分配到一个QCPLayer上,从而控制它在最终图像中的上下位置。
从这个基类出发,主要衍生出三大功能分支:
QCPAbstractPlottable(数据图元):这是所有数据系列的抽象基类。你通过它来展示数据,比如用QCPGraph画一条股价走势线,或用QCPBars画一个销售统计柱状图。QCPAbstractItem(标识图元):这是一个用于添加装饰和说明的抽象基类。它不像plottable那样必须绑定在数据坐标系上,位置可以更灵活。你可以用它在图表上画一条直线 (QCPItemLine)、添加一个文本框 (QCPItemText) 或一个箭头标记 (QCPItemTracer)。QCPLayoutElement(布局元素):这个分支让QCustomPlot具备了像Qt布局一样的能力。所有需要参与自动布局的对象,如承载坐标轴的矩形框 (QCPAxisRect)、图例 (QCPLegend),都继承于此。
2.图层系统:控制渲染的先后顺序
QCustomPlot的一大特色就是它的图层系统。你可以把它想象成Photoshop的图层:
QCustomPlot维护着一个有序的图层列表。在绘制时,它会从列表的最底层开始,由下往上依次绘制每个图层上的所有对象。- 新创建的QCustomPlot默认有六个图层,顺序如下(下层在上层之前绘制):
background:背景层,通常用于放置坐标轴矩形的背景。grid:网格层,绘制坐标轴的网格线。main:主绘图层,默认情况下,新创建的plottable(如曲线)和item都会被添加到此层。axes:坐标轴层,绘制坐标轴的轴线、刻度和标签。legend:图例层,绘制图例。overlay:覆盖层,最顶层,通常用于绘制鼠标选择框等临时元素。
- 你可以通过
QCPLayerable::setLayer()将任意一个layerable对象移动到任意图层,也可以通过QCustomPlot::moveLayer()来调整图层本身的顺序,从而实现复杂的显示效果。
3.布局系统:自动化管理元素位置
除了通过图层控制绘制顺序,QCustomPlot还通过一套布局系统来控制各个元素(如坐标轴矩形、图例、图表标题)的位置和尺寸。
- 顶层布局:每个
QCustomPlot对象都有一个顶级的QCPLayoutGrid,即plotLayout。它是一个网格布局,默认只有一个单元格,里面放着你最常用的QCPAxisRect(坐标轴矩形)。 - 灵活的扩展:你可以通过操作这个顶层布局,来构建更复杂的界面。例如,你可以在第0行插入一个单元格,放置一个
QCPTextElement作为图表标题;也可以添加一个新的轴矩形,将多个图表并排显示。图例 (QCPLegend) 本身也是一个布局元素,可以被移动到主布局中,实现图例在图表外部显示的效果。

浙公网安备 33010602011771号