vba 有没有办法在打开文档时在 Word 中显示自定义 UI 选项卡?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15113874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 19:48:43  来源:igfitidea点击:

Is there a way of showing a customUI tab in Word when the document is opened?

vbams-wordribbon

提问by Boyplunder

I have a custom ribbon tab in Word, created with the CustomUI editor, with a host of buttons that all work fine. I am trying to find out if I can set the focus of this custom tab when the Word document is opened. [Or when a new document is created.]

我在 Word 中有一个自定义功能区选项卡,它是使用 CustomUI 编辑器创建的,其中包含许多可以正常工作的按钮。我想知道在打开 Word 文档时是否可以设置此自定义选项卡的焦点。[或者在创建新文档时。]

Currently, it just shows the Home tab by default. i have found ways of turning the custom tab on and off, but not to 'set focus' to it.

目前,它默认只显示主页选项卡。我找到了打开和关闭自定义选项卡的方法,但不是“设置焦点”。

Any ideas?

有任何想法吗?

采纳答案by Boyplunder

I couldn't get the Sendkeys solution to work reliably enough. The Active Accessibility solution seems to work, but needs a bit more time than I have. I'll certainly review this method later.

我无法让 Sendkeys 解决方案足够可靠地工作。Active Accessibility 解决方案似乎有效,但需要比我多一点的时间。稍后我肯定会回顾这种方法。

I did find that there is a way of displaying the custom tab if it is the first one in the tab list. I used these settings:

我确实发现有一种方法可以显示自定义选项卡,如果它是选项卡列表中的第一个选项卡。我使用了这些设置:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false"> 
<tabs>
<tab id="customTab" insertBeforeMso="TabHome" label="CustomTabName">

Thanks for the alternatives. Much appreciated.

感谢您的选择。非常感激。

回答by CuberChase

You can achieve this via the Microsoft Active Accessibility, I've include the code from the following webpage, but if you want more information then check if out. (sample is at the bottom of the page).

您可以通过 Microsoft Active Accessibility 实现这一点,我已经包含了以下网页中的代码,但如果您需要更多信息,请查看。(样本位于页面底部)。

http://www.wordarticles.com/Shorts/RibbonVBA/RibbonVBADemo.php

http://www.wordarticles.com/Shorts/RibbonVBA/RibbonVBADemo.php

In a new module you have the code to accept the accessibilty API:

在一个新模块中,您拥有接受可访问性 API 的代码:

    ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
    ' Definitions and Procedures relating to Accessibility, used by the Ribbon VBA  '
    ' Demonstration UserForm. The constants have been lifted from oleacc.h, and are '
    ' just a subset of those available.                                             '
    '                                                                               '
    '                                                    Tony Jollans, August 2008. '
    ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '

    Option Explicit

    Public Const CHILDID_SELF                  As Long = &H0&
    Public Const STATE_SYSTEM_UNAVAILABLE      As Long = &H1&
    Public Const STATE_SYSTEM_INVISIBLE        As Long = &H8000&
    Public Const STATE_SYSTEM_SELECTED         As Long = &H2&

    Public Enum RoleNumber
        ROLE_SYSTEM_CLIENT = &HA&
        ROLE_SYSTEM_PANE = &H10&
        ROLE_SYSTEM_GROUPING = &H14&
        ROLE_SYSTEM_TOOLBAR = &H16&
        ROLE_SYSTEM_PAGETAB = &H25&
        ROLE_SYSTEM_PROPERTYPAGE = &H26&
        ROLE_SYSTEM_GRAPHIC = &H28&
        ROLE_SYSTEM_STATICTEXT = &H29&
        ROLE_SYSTEM_TEXT = &H2A&
        ROLE_SYSTEM_BUTTONDROPDOWNGRID = &H3A&
        ROLE_SYSTEM_PAGETABLIST = &H3C&
    End Enum

    Private Enum NavigationDirection
        NAVDIR_FIRSTCHILD = &H7&
    End Enum

    Private Declare Function AccessibleChildren Lib "oleacc.dll" _
                        (ByVal paccContainer As Object, ByVal iChildStart As Long, ByVal cChildren As Long, _
                               rgvarChildren As Variant, pcObtained As Long) _
                    As Long

    Public Function GetAccessible _
                        (Element As IAccessible, _
                         RoleWanted As RoleNumber, _
                         NameWanted As String, _
                         Optional GetClient As Boolean) _
                    As IAccessible

        ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
        ' This procedure recursively searches the accessibility hierarchy, starting '
        ' with the element given, for an object matching the given name and role.   '
        ' If requested, the Client object, assumed to be the first child, will be   '
        ' returned instead of its parent.                                           '
        '                                                                           '
        ' Called by: RibbonForm procedures to get parent objects as required        '
        '            Itself, recursively, to move down the hierarchy                '
        ' Calls: GetChildren to, well, get children.                                '
        '        Itself, recursively, to move down the hierarchy                    '
        ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '

        Dim ChildrenArray(), Child As IAccessible, ndxChild As Long, ReturnElement As IAccessible

        If Element.accRole(CHILDID_SELF) = RoleWanted And Element.accName(CHILDID_SELF) = NameWanted Then

            Set ReturnElement = Element

        Else ' not found yet
            ChildrenArray = GetChildren(Element)

            If (Not ChildrenArray) <> True Then
                For ndxChild = LBound(ChildrenArray) To UBound(ChildrenArray)
                    If TypeOf ChildrenArray(ndxChild) Is IAccessible Then

                        Set Child = ChildrenArray(ndxChild)
                        Set ReturnElement = GetAccessible(Child, RoleWanted, NameWanted)
                        If Not ReturnElement Is Nothing Then Exit For

                    End If                  ' Child is IAccessible
                Next ndxChild
            End If                          ' there are children
        End If                              ' still looking

        If GetClient Then
            Set ReturnElement = ReturnElement.accNavigate(NAVDIR_FIRSTCHILD, CHILDID_SELF)
        End If

        Set GetAccessible = ReturnElement

    End Function

    Private Function GetChildren(Element As IAccessible) As Variant()
        ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
        ' General purpose subroutine to get an array of children of an IAccessible  '
        ' object. The returned array is Variant because the elements may be either  '
        ' IAccessible objects or simple (Long) elements, and the caller must treat  '
        ' them appropriately.                                                       '
        '                                                                           '
        ' Called by: GetAccessible when searching for an Accessible element         '
        ' Calls: AccessibleChildren API                                             '
        ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
        Const FirstChild As Long = 0&
        Dim NumChildren As Long, NumReturned As Long, ChildrenArray()

        NumChildren = Element.accChildCount

        If NumChildren > 0 Then
            ReDim ChildrenArray(NumChildren - 1)
            AccessibleChildren Element, FirstChild, NumChildren, ChildrenArray(0), NumReturned
        End If

        GetChildren = ChildrenArray
    End Function

And then in your ThisTemplateor ThisDocumentmodule:

然后在您的ThisTemplateThisDocument模块中:

    Option Explicit

    Private Sub Document_New()
        SwitchTab "MyTab"
    End Sub

    Private Sub Document_Open()
            SwitchTab "MyTab"
    End Sub


    Private Sub SwitchTab(TabName As String)
        Dim RibbonTab   As IAccessible

        'Get the Ribbon as an accessiblity object and the
        Set RibbonTab = GetAccessible(CommandBars("Ribbon"), ROLE_SYSTEM_PAGETAB, TabName)

        'If we've found the ribbon then we can loop through the tabs
        If Not RibbonTab Is Nothing Then
            'If the tab state is valid (not unavailable or invisible)
            If ((RibbonTab.accState(CHILDID_SELF) And (STATE_SYSTEM_UNAVAILABLE Or _
                         STATE_SYSTEM_INVISIBLE)) = 0) Then
                'Then we can change to that tab
                RibbonTab.accDoDefaultAction CHILDID_SELF
            End If
        End If

    End Sub

回答by DanL

The answers presented are unnecessarily complex. The simplest solution is part of what Sam answered.

所提供的答案不必要地复杂。最简单的解决方案是 Sam 回答的一部分。

You add an "onLoad"-callback attribute referring to a method name in the custom UI root node of your custom XML. E.g.:

您在自定义 XML 的自定义 UI 根节点中添加引用方法名称的“onLoad”回调属性。例如:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
<ribbon startFromScratch="false">
    <tabs>
        <tab id="customTab" label="Custom Tab">
        </tab>
    </tabs>
</ribbon>
</customUI>

You then add a callback method with the correct signature to a module in the document. In this method, you'll have access to an IRibbonUI object, which can be used to activate tabs - be they custom or built-in. The following example activates a custom tab with an id equal to "customTab":

然后将具有正确签名的回调方法添加到文档中的模块。在此方法中,您将可以访问 IRibbonUI 对象,该对象可用于激活选项卡 - 无论是自定义的还是内置的。以下示例激活一个 id 等于“customTab”的自定义选项卡:

Sub Ribbon_Load(ribbon As IRibbonUI)
    ribbon.ActivateTab "customTab"
End Sub

回答by Robin Kramer

I wanted to make an addition to CuberChase's excellent answer, which worked for me on a 32-bit instance, by simply copying all the code into a module of the document you work in.

我想通过简单地将所有代码复制到您工作的文档的模块中来对 CuberChase 的优秀答案进行补充,该答案在 32 位实例上对我有用。

However, when you work on a 64-bit instance, it is necessary to change a bit of code.

但是,当您在 64 位实例上工作时,有必要更改一些代码。

Instead of Private Declare Function ... As Long:

而不是私有声明函数......只要

Private Declare Function AccessibleChildren Lib "oleacc.dll" _
                    (ByVal paccContainer As Object, ByVal iChildStart As Long, ByVal cChildren As Long, _
                           rgvarChildren As Variant, pcObtained As Long) _
                As Long

You require to declare Private Declare PtrSafe Function ... As LongPtr. The function thus changes to:

您需要声明Private Declare PtrSafe Function ... As LongPtr。函数因此更改为:

Private Declare PtrSafe Function AccessibleChildren Lib "oleacc.dll" _
                    (ByVal paccContainer As Object, ByVal iChildStart As Long, ByVal cChildren As Long, _
                           rgvarChildren As Variant, pcObtained As Long) _
                As LongPtr

See also this websitefor some more explanation.

另请参阅此网站以获取更多解释。

Note, I used this code to get SolverStudio in Excel 2016, to work. I was referred to this page by http://solverstudio.org/using-studio/

请注意,我使用此代码使Excel 2016 中的 SolverStudio工作。我被http://solverstudio.org/using-studio/提到了这个页面

回答by StoriKnow

After your custom ribbon tab gets drawn to the Ribbon, you can send a key to the model like so:

在您的自定义功能区选项卡被绘制到功能区后,您可以像这样向模型发送一个键:

Application.SendKeys "%keytosend%"

Application.SendKeys "%keytosend%"

To find out what key needs to be sent, open the workbook and press Alt. You will notice key icons display over the tabs.

要找出需要发送的密钥,请打开工作簿并按Alt。您会注意到选项卡上显示的键图标。

enter image description here

在此处输入图片说明

For example, to load the Page Layouttab, you would send the key like so:

例如,要加载Page Layout选项卡,您可以像这样发送密钥:

Application.SendKeys "%P%"

Application.SendKeys "%P%"

NOTE:You may have to tell the custom ribbon code what macro to call onLoad. This can be done in the XML using the Custom UI Editor. Load the workbook that contains the custom ribbon code, then add the onLoadattribute to the <customUI></customUI>tag, like so:

注意:您可能需要告诉自定义功能区代码调用什么宏onLoad。这可以在 XML 中使用Custom UI Editor. 加载包含自定义功能区代码的工作簿,然后将onLoad属性添加到<customUI></customUI>标签,如下所示:

enter image description here

在此处输入图片说明

Once added, you then have to create a VBA function that matches the onLoadfunction you defined (in this case, ribbonLoad). In that function is where you can then send the appropriate key:

添加后,您必须创建一个与onLoad您定义的函数(在本例中为ribbonLoad)相匹配的VBA 函数。在该函数中,您可以发送适当的密钥:

Sub ribbonLoad(ctl As IRibbonUI)
    Application.SendKeys "%Y1%"
End Sub