微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有没有办法使用 VBA 以编程方式更改 Word 2010 中 CanvasShapes 的 Z 顺序位置?

如何解决有没有办法使用 VBA 以编程方式更改 Word 2010 中 CanvasShapes 的 Z 顺序位置?

我正在 Word 2010 中渲染 3D 形状,由于我的文档有多个动画图表,我决定将这些形状移动到绘图画布上,每个动画一个。为此,我修改代码支持 Shapes 和 CanvasShapes。我已经解决了大部分问题,除了一个:Z-Order 方法不会改变 CanvasShapes 的 Z-order 定位。

我一直在互联网上寻找原因,但找不到任何原因。仅使用两个搜索词“ZOrder”和“CanvasShape”并没有多大意义。我确实找到了 CanvasShape 的 MSDN 类描述,它没有将“Zorder”列为类成员,但是 Zorder 的使用信息将“CanvasShape”列为“支持的类”。如果该方法不改变 z 顺序位置,这意味着什么?

点击量很少让我相信我在做一些完全不合常规的事情,或者/并且我错过了一些非常基本的东西。

以下是我的测试例程:

Sub test()
    With ActiveDocument.Shapes.AddCanvas(72,72,144,144)
        .Name = "Test Canvas"
        .CanvasItems.AddShape(msoShapeRectangle,36,36).Name = "Shape 1"
        With .CanvasItems.AddShape(msoShapeRectangle,36)
            .Name = "Shape 2"
            Debug.Print .ZOrderPosition
            .ZOrder msoSendToBack
            Debug.Print .ZOrderPosition
        End With
    End With
End Sub

在 Word VBE 中执行时,一个绘图画布将添加到活动文档中,其中包含两个画布项目。该宏将尝试切换两者的 Z 顺序定位。在尝试切换之前和之后,第二个画布形状的 z 顺序位置将打印在即时/调试窗口中。如果 zorder 方法正常运行,之前和之后的值应该不同。在我的系统上,不是因为 zorderposition 没有改变。我还注意到我没有收到错误消息或任何类型的停止。这就是 MSDN 所说的“支持的类”吗?

作为一种解决方法,我考虑剪切 CanvasShapes,然后将它们以正确的 Z 顺序粘贴回画布上,不幸的是,这种方法会破坏我分配的时间片。通过 Word GUI“前进”和“后退”的手动过程仍然适用于这两个类,我将如何模仿?

解决方法

休息一个月后,我开始探索一些想法。我首先想到的是,由于“向前”和“向后发送”按钮仍然适用于绘图画布内的形状,我可以查看按钮的 OnAction 属性中的代码,或者只是简单地以某种方式调用适当的按钮。

我确实找到了三个 CommandBar,名为“Order”、“Ribbon”和“Selection and Visibility”,我希望它们应该有我需要的这些按钮。不幸的是, OnAction 属性是空的,我没有看到触发任何这些按钮的方法。沮丧的是,我不小心按下了激活功能区的 ALT 键,显示了可用于触发当前可见的各种功能区项目的键盘快捷键。我终于意识到我仍然可以使用按键来选择功能区项目,我认为这个功能随着功能区的引入而被删除。我想出了下面的这个原型:一种专门用于绘图画布中形状的方法,它也适用于绘图画布内部或外部的所有对象。

Sub Zorder(ByRef ShapeObject As Object,ByVal ZorderCmd As MsoZOrderCmd)
    'Add code here,if needed,to preserve last item selected
    ShapeObject.Select
    SendKeys "%",True: SendKeys "P",True
    SendKeys Array("AF","AE")(ZorderCmd Mod 2) & _
        Mid("RKFBTH",ZorderCmd + 1,1),True
    'Add code here,to restore last item selected
End Sub

使用功能区格式化对象需要选择对象,因此会触发 SelectionChange 或 LostFocus 事件,这在某些实现中可能是一个问题,但很容易解决。然而,我在使用 SendKeys 语句时遇到了问题,因为它们要求活动文档是活动的、最顶层的窗口,在我的场景中,这并不能保证。我最初虽然我可以用 SendMessage 或 PostMessage 替换 SendKeys。痛苦的是,我一直在追求这种方法,直到我读到一篇建议不要使用 SendMessage 或 PostMessage 向 word 应用程序发送消息的帖子。

我迷路了。现在怎么办?当我进行最终搜索时,我正准备在黑板上发布另一个问题。不知何故,我登陆了 GetVisibleMso 的使用页面,这是 CommmendBars 的一个成员函数。该页面讨论了 idMso,解释了功能区上的标准按钮与唯一的 idMso 相关联。它还暗示可以使用它们的 idMso 触发这些按钮。因此,我使用 VBE 中的对象浏览器仔细查看了 CommandBars 类,结果是: ExecuteMso 方法,idMSO 是其唯一参数;它会触发相应的按钮。

当我使用搜索词“执行功能区项目”时,我得到了比使用触发器或激活更好、更准确的命中率,这可能是我花了一段时间才想出合适的解决方案的原因。可以找到 Word 的标准 idMsos 列表here!

有了这个,我的原型的变化如下:

Application.CommandBars.ExecuteMso Array("ObjectBringToFront",_
    "ObjectSendToBack","ObjectBringForward","ObjectSendBackward",_
    "ObjectBringInFrontOfText","ObjectSendBehindText")(ZorderCmd)

我读到的建议之一是使用 Application.CommandBars。我还发现与被触发的功能区按钮关联的选项卡/面板不需要激活。该按钮只需要可用(换句话说,已启用)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。