eduwin 画布绘图教程

eduwin 的画布(Canvas)组件提供完整的 2D 绘图能力,基于 GDI+ 实现,支持线、矩形、椭圆、多边形、扇形、贝塞尔曲线、路径、文本、图像等绘制,还内置双缓冲离屏渲染,天然无闪烁。


1. 创建画布

#include "eduwin.h"

HWND win = create_window(L"画布演示", 640, 480);
HWND canvas = create_canvas(win, 0, 0, 640, 480);

create_canvas 在窗口中创建一个画布控件,参数依次为父窗口、x、y、宽度、高度。

注意:所有绘图操作必须在 show_window 之后调用!show_window 触发 WM_SIZE 消息,画布会重新创建离屏位图,之前绘制的内容会被清空。


2. 基本绘图流程

show_window(win);

// 1. 清空画布背景
canvas_clear(canvas, 240, 240, 240, 255);  // 灰色不透明背景

// 2. 设置画笔(轮廓)
canvas_set_pen(canvas, 0, 0, 255, 255, 3);  // 蓝色 3px 不透明

// 3. 设置画刷(填充)
canvas_set_brush(canvas, 255, 200, 200, 255); // 粉色不透明

// 4. 绘图
canvas_draw_rect(canvas, 20, 20, 100, 80);    // 矩形边框
canvas_fill_ellipse(canvas, 140, 20, 100, 80); // 填充椭圆
canvas_draw_line(canvas, 20, 120, 300, 120);   // 直线
canvas_draw_text(canvas, L"Hello 画布", 20, 140, 0, 0, 0, 255, 20); // 文字

3. 绘图状态

void canvas_clear(HWND canvas, int r, int g, int b, int a);
void canvas_set_pen(HWND canvas, int r, int g, int b, int a, int width);
void canvas_set_brush(HWND canvas, int r, int g, int b, int a);
void canvas_set_font(HWND canvas, const WCHAR *family, int size);
  • canvas_clear 用指定颜色填充整个画布(清除原有内容),参数为 RGBA,范围 0–255
  • canvas_set_pen 设置轮廓画笔的颜色、透明度和线宽(默认黑色 1px 不透明)
  • canvas_set_brush 设置填充画刷的颜色和透明度(默认白色不透明)
  • canvas_set_font 设置文本字体和字号(默认 Microsoft YaHei 14)

绘图状态是全局的——设置后影响后续所有绘制,直到再次修改。

canvas_set_pen(canvas, 255, 0, 0, 255, 5);   // 红色 5px 画笔
canvas_draw_rect(canvas, 10, 10, 100, 100);  // 红色5px边框

canvas_set_pen(canvas, 0, 128, 0, 200, 1);   // 绿色半透明 1px 画笔
canvas_draw_rect(canvas, 130, 10, 100, 100); // 绿色1px边框

4. 基本几何图形

void canvas_draw_line(HWND canvas, int x1, int y1, int x2, int y2);
void canvas_draw_rect(HWND canvas, int x, int y, int w, int h);
void canvas_fill_rect(HWND canvas, int x, int y, int w, int h);
void canvas_draw_ellipse(HWND canvas, int x, int y, int w, int h);
void canvas_fill_ellipse(HWND canvas, int x, int y, int w, int h);
void canvas_fill_polygon(HWND canvas, const PointF *pts, int count);
void canvas_fill_pie(HWND canvas, int x, int y, int w, int h, float start_angle, float sweep_angle);
  • draw_line / draw_rect / draw_ellipse 用当前画笔绘制轮廓
  • fill_rect / fill_ellipse / fill_polygon / fill_pie 用当前画刷填充

填充多边形示例:

/* 绘制一个蓝色三角形 */
PointF pts[3] = {
    {200, 50},  /* 顶点 */
    {150, 150}, /* 左下 */
    {250, 150}  /* 右下 */
};
canvas_set_brush(canvas, 50, 100, 200, 200);  // 半透明蓝色
canvas_fill_polygon(canvas, pts, 3);

填充扇形示例:

/* 绘制一个从 0° 到 90° 的扇形 */
canvas_set_brush(canvas, 200, 100, 50, 220);
canvas_fill_pie(canvas, 300, 50, 120, 120, 0, 90);

5. 弧形与贝塞尔曲线

void canvas_draw_arc(HWND canvas, int x, int y, int w, int h, float start_angle, float sweep_angle);
void canvas_draw_bezier(HWND canvas, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
  • draw_arc 绘制椭圆弧线段,start_angle 为起始角度(度),sweep_angle 为扫过的角度(逆时针为正)
  • draw_bezier 绘制三次贝塞尔曲线,4 个点依次为起点、控制点 1、控制点 2、终点
/* 弧线:从 0° 到 180° */
canvas_set_pen(canvas, 200, 50, 50, 255, 3);
canvas_draw_arc(canvas, 50, 200, 100, 80, 0, 180);

/* 贝塞尔曲线 */
canvas_draw_bezier(canvas, 200, 200, 250, 100, 350, 300, 400, 200);

6. 路径系统

路径(Path)允许你将多条线段、弧线、椭圆、矩形组合成一个图形,然后统一绘制或填充。

void *canvas_create_path(void);
void canvas_add_path_line(void *path, float x1, float y1, float x2, float y2);
void canvas_add_path_arc(void *path, float x, float y, float w, float h, float start_angle, float sweep_angle);
void canvas_add_path_ellipse(void *path, float x, float y, float w, float h);
void canvas_add_path_rect(void *path, float x, float y, float w, float h);
void canvas_close_path(void *path);
void canvas_draw_path(HWND canvas, void *path);
void canvas_fill_path(HWND canvas, void *path);
void canvas_delete_path(void *path);

使用模式:创建路径 → 添加图形 → 绘制/填充 → 销毁路径。

/* 创建一个心形路径 */
void *path = canvas_create_path();
canvas_add_path_ellipse(path, 0, 0, 80, 80);    // 左圆
canvas_add_path_ellipse(path, 60, 0, 80, 80);   // 右圆
canvas_add_path_line(path, 0, 50, 70, 140);      // 左侧边
canvas_add_path_line(path, 70, 140, 140, 50);     // 右侧边
canvas_close_path(path);

canvas_set_brush(canvas, 220, 60, 80, 255);
canvas_fill_path(canvas, path);

canvas_set_pen(canvas, 180, 30, 50, 255, 2);
canvas_draw_path(canvas, path);

canvas_delete_path(path);

7. 绘制文本

void canvas_set_font(HWND canvas, const WCHAR *family, int size);
void canvas_draw_text(HWND canvas, const WCHAR *text, int x, int y, int r, int g, int b, int a, int size);
  • canvas_set_font 设置全局字体和字号(size 为 0 时不影响后续单次绘制)
  • canvas_draw_textr g b a 为文字颜色和透明度,size 传 0 使用 canvas_set_font 设定的字号
/* 设置全局字体 */
canvas_set_font(canvas, L"SimSun", 24);     // 宋体 24 号
canvas_draw_text(canvas, L"你好,eduwin", 50, 300, 50, 50, 50, 255, 0);  // 用全局设置

/* 单次绘制指定字号 */
canvas_draw_text(canvas, L"大标题", 50, 340, 200, 50, 50, 255, 36);
canvas_draw_text(canvas, L"小标注", 50, 390, 128, 128, 128, 255, 12);

8. 绘制图像

void *load_image_from_file(const WCHAR *filepath, UINT *width, UINT *height);
void canvas_draw_image(HWND canvas, void *image, int x, int y, int w, int h);
UINT iw, ih;
void *img = load_image_from_file(L"photo.png", &iw, &ih);
if (img)
{
    canvas_draw_image(canvas, img, 10, 10, (int)iw, (int)ih);
}

9. 局部清除与文件输出

void canvas_clear_rect(HWND canvas, int x, int y, int w, int h, int r, int g, int b, int a);
void canvas_save_image(HWND canvas, const WCHAR *filepath);

canvas_clear_rect 用颜色填充指定矩形区域(局部清除),a 为透明度。canvas_save_image 将画布当前内容保存为图像文件(根据扩展名自动选择编码器,支持 png/jpg/bmp)。

/* 在灰色区域中挖一个矩形 */
canvas_set_brush(canvas, 180, 180, 180, 255);
canvas_fill_rect(canvas, 10, 10, 200, 100);

/* 局部清除并填充绿色 */
canvas_clear_rect(canvas, 50, 30, 100, 40, 100, 200, 50, 255);

/* 保存为文件 */
canvas_save_image(canvas, L"output.png");

10. 画布尺寸

int canvas_get_width(HWND canvas);
int canvas_get_height(HWND canvas);

获取画布的实际像素尺寸,通常配合 show_window 之后使用:

int cw = canvas_get_width(canvas);
int ch = canvas_get_height(canvas);
canvas_draw_text(canvas, L"居中文字", cw / 2 - 60, ch / 2, 0, 0, 0, 255, 20);

完整示例

#include "eduwin.h"

int main(void)
{
    init_app();

    HWND win = create_window(L"画布绘图教程", 400, 400);
    HWND canvas = create_canvas(win, 0, 0, 400, 400);

    show_window(win);

    /* 白色背景 */
    canvas_clear(canvas, 255, 255, 255, 255);

    /* 红色矩形边框 */
    canvas_set_pen(canvas, 220, 50, 50, 255, 3);
    canvas_draw_rect(canvas, 20, 20, 160, 100);

    /* 蓝色填充椭圆 */
    canvas_set_brush(canvas, 60, 120, 200, 200);
    canvas_fill_ellipse(canvas, 220, 20, 160, 100);

    /* 绿色直线 */
    canvas_set_pen(canvas, 60, 160, 60, 255, 2);
    canvas_draw_line(canvas, 20, 180, 380, 180);

    /* 半透明填充三角形 */
    canvas_set_brush(canvas, 200, 160, 60, 180);
    PointF pts[3] = {{200, 220}, {100, 350}, {300, 350}};
    canvas_fill_polygon(canvas, pts, 3);

    /* 灰色文字 */
    canvas_draw_text(canvas, L"eduwin 画布", 140, 370, 80, 80, 80, 255, 16);

    run_app();
    return 0;
}

编译命令:

cl canvas_demo.c /Feoutput.exe /I include /link eduwin.lib lib\*.lib