自定义绘图

Charmy 的 图形层 提供了直接绘制线条、形状和文字的能力。 你可以直接使用 graphics 模块中的 DrawnLineDrawnShapeDrawnText 在窗口上绘制内容,无需通过控件。

基本概念

图形层位于后端层和控件层之间,三个核心类:

用途

示例

DrawnLine

绘制线条

直线、折线、圆弧、贝塞尔曲线

DrawnShape

绘制填充形状

矩形、圆角矩形、多边形、SVG 路径

DrawnText

绘制文字

带样式的文字

所有 Drawn* 对象创建后需要调用 .draw() 才会实际加入渲染队列。

绘制线条

直线:

import charmy as cm

window = cm.Window(size=(400, 300))

# 直线 (Line)
line = cm.graphics.DrawnLine(
    window,
    cm.styles.shape.Line([(50, 50), (200, 100)]),  # 起点→终点
    (255, 0, 0),       # 红色纹理(RGB)
    width=3            # 线宽
).draw()

折线:

# 折线 (PolyLine)
polyline = cm.graphics.DrawnLine(
    window,
    cm.styles.shape.PolyLine([(50, 150), (150, 50), (250, 150), (350, 50)]),
    (0, 100, 255),     # 蓝色
    width=2
).draw()

圆弧:

# 圆弧 (CircleArc)
#    参数: center, radius, start_orient, end_orient
#    orient 0°=正上方, 顺时针递增
arc = cm.graphics.DrawnLine(
    window,
    cm.styles.shape.CircleArc((200, 200), 80, 0, 270),  # 0°→270° 顺时针
    (0, 200, 0),       # 绿色
    width=4
).draw()

贝塞尔曲线:

# 三次贝塞尔曲线 (CubicBezier)
#    参数: [起点, 控制点1, 控制点2, 终点]
bezier = cm.graphics.DrawnLine(
    window,
    cm.styles.shape.CubicBezier([(50, 250), (100, 50), (250, 50), (300, 250)]),
    (200, 0, 200),     # 紫色
    width=3
).draw()

备注

DrawnLinewidth 参数控制线宽,单位为像素。 纹理参数可以是 (R, G, B)(R, G, B, A) 元组。

绘制形状

矩形:

# 填充矩形
rect = cm.graphics.DrawnShape(
    window,
    cm.styles.shape.Rect((50, 50), (150, 100)),  # (左上角), (宽, 高)
    (255, 200, 0),      # 填充色
    border_width=3,     # 边框宽度 (0=无边框)
    border_texture=(100, 100, 100)  # 边框色
).draw()

圆角矩形:

# 圆角矩形,圆角半径 20px
round_rect = cm.graphics.DrawnShape(
    window,
    cm.styles.shape.RoundRect((50, 50), (150, 100), 20),
    (200, 200, 255, 150),   # 半透明蓝色填充
    offset=(50, 100)        # 位置偏移
).draw()

多边形(任意形状):

# 任意多边形通过 AnyShape 定义
polygon = cm.graphics.DrawnShape(
    window,
    cm.styles.shape.AnyShape([
        cm.styles.shape.PolyLine([
            (100, 100), (150, 80), (180, 120),
            (140, 160), (80, 140), (100, 100)
        ])
    ]),
    (150, 150, 150),     # 灰色填充
    border_width=4,
    border_texture=(255, 0, 0)  # 红色边框
).draw()

小技巧

DrawnShapeborder_width 参数: 正值表示向外扩展边框,负值表示向内收缩。 0 表示不绘制边框。

然而这一特性并未在Genesis中实现,也并未被设计为强制性需要被后端实现的功能。

绘制文字

text = cm.graphics.DrawnText(
    window,
    "Hello, Charmy!",                         # 文字内容
    cm.styles.text_style.TextStyle(            # 文字样式
        font="Consolas",                       # 字体名
        size=24,                               # 字号
        weight=cm.styles.text_style.WEIGHT.BOLD, # 字重
        underlined=True,                       # 下划线
        italic=False                           # 斜体
    ),
    (0, 0, 0),         # 文字颜色
    offset=(50, 200)   # 位置
).draw()

备注

Charmy 使用 Cairo 进行文字渲染,字体名需要是系统中已安装的字体。 如果指定字体不存在,Cairo 会回退到默认字体。

透明度与纹理

纹理(Texture)是 Charmy 中控制颜色的统一方式:

from charmy.styles.texture import Color, Transparent

# 纯色 (R, G, B, A)
texture = Color((255, 0, 0, 200))     # 半透明红色

# 透明(不绘制)
transparent = Transparent()

# 快捷方式:直接使用元组
line = DrawnLine(window, shape, (255, 0, 0))         # RGB
line = DrawnLine(window, shape, (255, 0, 0, 128))     # RGBA
shape = DrawnShape(window, rect, (0, 255, 0, 100))    # 半透明绿色填充

偏移与锚点

DrawnLineDrawnShape 支持 offsetanchor 参数:

  • offset: 整体位置的偏移量(相对于原始坐标)

  • anchor: 锚点位置,即原始坐标中作为基准的点

# offset 将整个图形向右下偏移 (50, 50)
shape = cm.graphics.DrawnShape(
    window,
    cm.styles.shape.Rect((0, 0), (100, 100)),
    (255, 0, 0),
    offset=(50, 50)       # 相当于将图形从 (0,0) 移到 (50,50)
).draw()

offsetanchor 设置为 "auto" 时, 会自动使用图形边界框的左上角作为默认值。

SVG 路径绘制

Charmy 内置了完整的 SVG 路径解析器,可以直接从 SVG 路径字符串创建形状:

from charmy.utils.svg import shapes_from_svg_path

# SVG 路径字符串 → Charmy 形状
path = "M 10 10 L 100 10 L 100 100 Z"  # 一个正方形
shape = shapes_from_svg_path(path)

# 绘制
drawn = cm.graphics.DrawnShape(window, shape, (100, 200, 255)).draw()

支持的 SVG 命令: M (移动到)、 L (直线)、 V (垂直线)、 H (水平线)、 C (三次贝塞尔曲线)、 S (平滑贝塞尔)、 Z (闭合路径)。

警告

SVG 解析器目前不支持二次贝塞尔曲线( Q/T )和椭圆弧( A )。

参见

更多图形绘制 API 请参考 graphics 模块shape 模块texture 模块