Skip to content

.NET 操作 PowerPoint COM 组件:从零到精通的幻灯片制作实战

形状组合与自定义绘图

问题

文字和图片之外,PPT 还需要流程图、标注框、箭头指示等图形元素。PowerPoint 提供的自选图形库有 150+ 种预设形状,加上连接线和自由曲线,几乎可以画出任何图形。

MudTools 在 IPowerPointShapes 上暴露了 AddShapeAddLineAddConnector 等 20+ 个创建方法,返回的 IPowerPointShape 可以进一步控制填充、线条、大小和层级关系。

绘制基本形状

AddShape 是创建自选图形的主入口,通过 MsoAutoShapeType 枚举选择形状类型:

csharp
using var app = PowerPointFactory.BlankDocument();
var pres = app.ActivePresentation;
var slide = pres.AddSlide(PpSlideLayout.ppLayoutBlank);

// 矩形
var rect = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeRectangle,
    50, 50, 200, 120);

// 圆形(椭圆)
var circle = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeOval,
    300, 50, 120, 120);

// 圆角矩形
var rounded = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeRoundedRectangle,
    470, 50, 200, 120);

// 箭头
var arrow = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeRightArrow,
    50, 220, 150, 60);

// 菱形
var diamond = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeDiamond,
    250, 220, 120, 120);

// 五角星
var star = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShape5pointStar,
    420, 220, 120, 120);

常用 MsoAutoShapeType 枚举:

枚举形状
msoShapeRectangle矩形
msoShapeOval椭圆/圆
msoShapeRoundedRectangle圆角矩形
msoShapeRightArrow右箭头
msoShapeLeftArrow左箭头
msoShapeDiamond菱形
msoShapePentagon五边形
msoShapeChevronV 形
msoShapeParallelogram平行四边形
msoShapeFlowchartProcess流程图-过程
msoShapeFlowchartDecision流程图-判断
msoShape5pointStar五角星

形状的填充、线条、阴影和 3D 效果通过各自的 Format 接口控制:

csharp
// 填充颜色
rect.Fill.ForeColor.RGB = 0x3498DB;
rect.Fill.Visible = true;

// 线条边框
rect.Line.ForeColor.RGB = 0x2C3E50;
rect.Line.Weight = 1.5f;
rect.Line.DashStyle = MsoLineDashStyle.msoLineSolid;

// 阴影
rect.Shadow.Type = MsoShadowType.msoShadow1;
rect.Shadow.OffsetX = 3;
rect.Shadow.OffsetY = 3;

// 3D 效果
rect.ThreeD.Depth = 10;
rect.ThreeD.ExtrusionColor.RGB = 0x1A5276;

直线与连接符

csharp
// 画一条直线(从 (50, 400) 到 (250, 400))
var line = slide.Shapes.AddLine(50, 400, 250, 400);
line.Line.Weight = 2;
line.Line.ForeColor.RGB = 0xE74C3C;

// 添加连接符
var connector = slide.Shapes.AddConnector(
    MsoConnectorType.msoConnectorStraight,
    300, 400, 500, 400);
connector.Line.Weight = 1.5f;

连接符与普通线条的区别:连接符的两端可以附着在形状上,移动形状时连接符会自动跟随并重新路由。

csharp
// 连接两个形状
var shapeA = slide.Shapes.AddShape(MsoAutoShapeType.msoShapeRectangle, 50, 450, 100, 50);
var shapeB = slide.Shapes.AddShape(MsoAutoShapeType.msoShapeRectangle, 300, 450, 100, 50);

var conn = slide.Shapes.AddConnector(
    MsoConnectorType.msoConnectorElbow,
    150, 475, 300, 475);

// 连接端点
conn.ConnectorFormat.BeginConnect(shapeA, 1);  // 连接到 shapeA 的连接点 1
conn.ConnectorFormat.EndConnect(shapeB, 1);     // 连接到 shapeB 的连接点 1
conn.RerouteConnections();  // 让 PPT 自动选择最佳路由

形状分组与层级

当一个复杂图形由多个形状构成,把它们组合成一个 Group 可以方便整体移动和缩放:

csharp
// 创建分组
var groupShapes = slide.Shapes.Range(new object[] { rect.Name, circle.Name, arrow.Name });
var group = groupShapes.Group();

// 解组
var ungrouped = group.Ungroup();

层级控制通过 ZOrder 方法管理:

csharp
// 把形状移到最顶层
rect.ZOrder(MsoZOrderCmd.msoBringToFront);

// 把形状移到最底层
circle.ZOrder(MsoZOrderCmd.msoSendToBack);

// 上移一层
arrow.ZOrder(MsoZOrderCmd.msoBringForward);

// 下移一层
diamond.ZOrder(MsoZOrderCmd.msoSendBackward);

ZOrderPosition 属性可以查询当前层级序号(1 = 最底层)。

mermaid
flowchart TD
    A["AddShape(type, left, top, width, height)"] --> B["配置 Fill 填充"]
    A --> C["配置 Line 边框"]
    A --> D["配置 Shadow 阴影"]
    A --> E["配置 ThreeD 3D 效果"]
    B --> F{需要组合?}
    C --> F
    D --> F
    E --> F
    F -->|"是"| G["Range(names).Group()"]
    F -->|"否"| H["ZOrder 调整层级"]
    G --> H

SmartArt

Shapes.AddSmartArt 可以从代码创建 SmartArt 图形:

csharp
// 创建 SmartArt(需要 IOfficeSmartArtLayout 参数)
// 目前通过底层 COM 对象获取布局
var nativeSlide = (MsPowerPoint.Slide)slide;  // 注意:此处需要从 IPowerPointSlide 获取

AddSmartArt 接受 IOfficeSmartArtLayout 参数,后者需要通过 Office 的 SmartArt 布局库获取。在 MudTools 的框架下,可以通过 SmartArtLayouts 集合遍历找到目标布局。

自由曲线与多边形

通过 BuildFreeform 方法可以绘制任意多边形:

csharp
// 构建自由形状
var freeform = slide.Shapes.BuildFreeform(
    MsoEditingType.msoEditingCorner,  // 折线节点
    100, 500                          // 起点 x, y
);

// 添加节点
freeform.AddNodes(
    MsoSegmentType.msoSegmentLine,        // 直线段
    MsoEditingType.msoEditingAuto,        // 自动编辑
    200, 550,                             // 中间控制点(line 不需要,传相同坐标)
    200, 550                              // 终点
);

freeform.AddNodes(
    MsoSegmentType.msoSegmentLine,
    MsoEditingType.msoEditingAuto,
    300, 500,
    300, 500
);

// 闭合路径并创建形状
var poly = freeform.ConvertToShape();
poly.Fill.ForeColor.RGB = 0x9B59B6;
poly.Fill.Visible = true;

添加文本到任意形状

所有形状都有 HasTextFrame 属性和 TextFrame,这意味着矩形、圆形、箭头都可以直接写字:

csharp
var box = slide.Shapes.AddShape(
    MsoAutoShapeType.msoShapeRectangle,
    50, 550, 200, 60);

box.TextFrame.TextRange.Text = "点击此处输入";
box.TextFrame.TextRange.Font.Size = 14;
box.TextFrame.TextRange.ParagraphFormat.Alignment =
    PpParagraphAlignment.ppAlignCenter;
box.TextFrame.VerticalAnchor = MsoVerticalAnchor.msoAnchorMiddle;

艺术字通过 AddTextEffect 创建:

csharp
var wordArt = slide.Shapes.AddTextEffect(
    MsoPresetTextEffect.msoTextEffect1,
    "欢迎",                // 文字
    "Arial Black",         // 字体
    36,                    // 字号
    true,                  // 加粗
    false,                 // 斜体
    150, 200               // 位置
);

完整示例:流程图

csharp
using MudTools.OfficeInterop;
using MudTools.OfficeInterop.PowerPoint;
using MsCore = Microsoft.Office.Core;

using var app = PowerPointFactory.BlankDocument();
var pres = app.ActivePresentation;
var slide = pres.AddSlide(PpSlideLayout.ppLayoutBlank);

// 流程节点
var start = slide.Shapes.AddShape(
    MsCore.MsoAutoShapeType.msoShapeRoundedRectangle,
    280, 30, 160, 50);
start.TextFrame.TextRange.Text = "开始";
start.TextFrame.VerticalAnchor = MsCore.MsoVerticalAnchor.msoAnchorMiddle;
start.TextFrame.TextRange.ParagraphFormat.Alignment =
    PpParagraphAlignment.ppAlignCenter;
start.Fill.ForeColor.RGB = 0x2ECC71;
start.Fill.Visible = true;

var process1 = slide.Shapes.AddShape(
    MsCore.MsoAutoShapeType.msoShapeRectangle,
    280, 120, 160, 50);
process1.TextFrame.TextRange.Text = "处理数据";
process1.TextFrame.VerticalAnchor = MsCore.MsoVerticalAnchor.msoAnchorMiddle;
process1.TextFrame.TextRange.ParagraphFormat.Alignment =
    PpParagraphAlignment.ppAlignCenter;
process1.Fill.ForeColor.RGB = 0x3498DB;
process1.Fill.Visible = true;

var decision = slide.Shapes.AddShape(
    MsCore.MsoAutoShapeType.msoShapeDiamond,
    280, 220, 160, 120);
decision.TextFrame.TextRange.Text = "验证通过?";
decision.TextFrame.VerticalAnchor = MsCore.MsoVerticalAnchor.msoAnchorMiddle;
decision.TextFrame.TextRange.ParagraphFormat.Alignment =
    PpParagraphAlignment.ppAlignCenter;
decision.Fill.ForeColor.RGB = 0xF39C12;
decision.Fill.Visible = true;

var process2 = slide.Shapes.AddShape(
    MsCore.MsoAutoShapeType.msoShapeRectangle,
    280, 380, 160, 50);
process2.TextFrame.TextRange.Text = "输出结果";
process2.TextFrame.VerticalAnchor = MsCore.MsoVerticalAnchor.msoAnchorMiddle;
process2.TextFrame.TextRange.ParagraphFormat.Alignment =
    PpParagraphAlignment.ppAlignCenter;
process2.Fill.ForeColor.RGB = 0x3498DB;
process2.Fill.Visible = true;

// 箭头连接
void AddArrow(float x1, float y1, float x2, float y2, int color)
{
    var line = slide.Shapes.AddLine(x1, y1, x2, y2);
    line.Line.ForeColor.RGB = color;
    line.Line.Weight = 2;
}

AddArrow(360, 80, 360, 120, 0x333333);   // start → process1
AddArrow(360, 170, 360, 220, 0x333333);  // process1 → decision
AddArrow(360, 340, 360, 380, 0x333333);  // decision → process2

// 决策的"No"分支
var noLine = slide.Shapes.AddLine(280, 280, 150, 280);
noLine.Line.ForeColor.RGB = 0xE74C3C;
noLine.Line.Weight = 1.5f;

var noLabel = slide.Shapes.AddTextbox(
    MsCore.MsoTextOrientation.msoTextOrientationHorizontal,
    110, 260, 40, 20);
noLabel.TextFrame.TextRange.Text = "否";

Console.WriteLine("流程图已生成,按回车退出...");
Console.ReadLine();

小结

AddShape + MsoAutoShapeType 覆盖了 150+ 种预设形状。连接符的自动路由能力对流程图场景至关重要,ZOrder 管理了三层以上图形的视觉遮挡关系。Group 分组在需要整体移动一组形状时非常实用。

下一篇文章进入动画和切换效果——如何让幻灯片里的元素动起来,以及触发方式的控制。