何时为Excel Addin设置MacroOptions

时间:2016-12-14 14:15:02

标签: excel vba excel-vba excel-addins

我正在制作一个Excel插件。它由以下模块中的一些函数组成:

Public Function MyFunctionOne(X As Range, Y As Double) As Double
    MyFunctionOne = 1 'Example
End Function
Public Function MyFunctionTwo(X As Range, Y As Double) As Double
    MyFunctionTwo =  2 'Example
End Function
Public Function MyFunctionThree(X As Range, Y As Double) As Double
    MyFunctionThree =  3 'Example
End Function

我已将整个内容保存为.xlam Excel Addin。因此,每当我开始新的电子表格时,这些功能都可用。

我最近了解到我可以将我的功能分配到一个类别,这非常有帮助。这使它们易于使用Excel功能向导。我使用以下代码来分配类别:

Public Sub MyRegister()
    Application.MacroOptions Macro:="MyFunctionOne", Description:="Returns 1", Category:="My New Category"
    Application.MacroOptions Macro:="MyFunctionTwo", Description:="Returns 2", Category:="My New Category"
    Application.MacroOptions Macro:="MyFunctionThree", Description:="Returns 3", Category:="My New Category"
End Sub

现在,如果我手动运行宏MyRegister,那么这些函数都会获得新类别,并且效果非常好。但我不想每次开始新的电子表格时都手动运行宏。我的问题是,addin如何自动为每个新电子表格执行此操作?

我尝试将它放在插件的Workbook_Open中,如下所示:

Private Sub Workbook_Open()
    Call MyRegister
End Sub

问题在于它不起作用。每当Excel启动时,我都会收到错误消息:“Cannot edit a macro on a hidden workbook.”因此,Workbook_Open事件似乎是错误的地方。

所以我的问题是,如何在适当的时候运行MyRegister宏来将我的插件功能分配给类别?

顺便说一下,我真的不想制作模板。我真的要保持这个并且加上。

谢谢!

3 个答案:

答案 0 :(得分:2)

您可以执行以下操作,而不是使用Workbook_Open

Private WithEvents App As Application

Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
    MyRegister
End Sub

Private Sub Workbook_Open()
    Set App = Application
End Sub

这样,它会在工作簿处于活动状态时运行,并且您将避免出现错误。

答案 1 :(得分:1)

几乎就在那里。只需将加载项转换为普通工作簿,设置选项并重置为加载项。有关详细信息,请参阅代码注释。

Public Sub MyRegister()
    Application.ScreenUpdating = False '/ Turn it off to avoid flicker.
    ThisWorkbook.IsAddin = False '/ Make the add-in workbook as normal, hence unhiding sheets
    Application.MacroOptions Macro:="MyFunctionOne", Description:="Returns 1", Category:="My New Category"
    Application.MacroOptions Macro:="MyFunctionTwo", Description:="Returns 2", Category:="My New Category"
    Application.MacroOptions Macro:="MyFunctionThree", Description:="Returns 3", Category:="My New Category"
    ThisWorkbook.IsAddin = True '/ Set back as add-in, hides everything.
    Application.ScreenUpdating = True '/ Turn on screen updating
End Sub

答案 2 :(得分:0)

在我写这篇文章的时候,这个问题已经很老了(持续了 5 年),但这个问题为我提供了完全解决这个问题所需的信息。我能够接受@jerryact 提供的答案并对其进行扩展以解决我的问题。

首先,与原始海报类似,我在 Workbook_Open 事件中注册了我的 UDF,当它作为加载项加载时,会导致打开时显示 Run-time error '1004': Cannot edit a macro on a hidden workbook. Unhide the workbook using the Unhide command. 错误消息excel。

使用@jerryact 以上答案中的信息,我将代码更改为如下所示:

Option Explicit

Private WithEvents App As Application

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    modUDFs.UnregisterUDF "DMS_2_DD"
    modUDFs.UnregisterUDF "DD_2_DMS"
    modUDFs.UnregisterUDF "ElapsedTime"
End Sub

Private Sub Workbook_Open()
    Set App = Application
End Sub

Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
    modUDFs.RegisterUDF "Converts Decimal Degrees to Degrees, Minutes, Seconds" & vbLf & "rbcDD_2_DMS(<Decimal Degrees>)", "DD_2_DMS", 3
    modUDFs.RegisterUDF "Converts Degrees, Minutes, Seconds to Decimal Degrees" & vbLf & "rbcDMS_2_DD(<Degrees Minutes Seconds>)", "DMS_2_DD", 3
    modUDFs.RegisterUDF "Calculates the Time between two time stamps" & vbLf & _
                        "rbcElapsedTime(<end time>,<start time>,<output code>)" & vbLf & _
                        "0 = <Seconds>,  1 = <Minutes:Seconds>" & vbLf & _
                        "2 = <Hours:Minutes:Seconds>,  3 = <Days Hours:Minutes:Seconds>", "ElapsedTime", 2
End Sub

这很好用,似乎解决了我的问题(并且在 99.9% 的情况下都解决了)。但是,了解我的加载项可以随时由用户卸载,我想确保在卸载我的加载项时,它提供和注册的 UDF 未注册。这意味着@jerryact 提供的解决方案会导致与以前相同的错误消息,但仅在用户打开 Excel 但在实际打开工作簿或创建空白工作簿之前关闭应用程序的特定情况下。这让我找到了我的最终解决方案,如下所示:

Option Explicit

Private WithEvents App As Application

Private Sub App_WindowDeactivate(ByVal Wb As Workbook, ByVal Wn As Window)
    modUDFs.UnregisterUDF "DMS_2_DD"
    modUDFs.UnregisterUDF "DD_2_DMS"
    modUDFs.UnregisterUDF "ElapsedTime"
End Sub

Private Sub Workbook_Open()
    Set App = Application
End Sub

Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
    modUDFs.RegisterUDF "Converts Decimal Degrees to Degrees, Minutes, Seconds" & vbLf & "rbcDD_2_DMS(<Decimal Degrees>)", "DD_2_DMS", 3
    modUDFs.RegisterUDF "Converts Degrees, Minutes, Seconds to Decimal Degrees" & vbLf & "rbcDMS_2_DD(<Degrees Minutes Seconds>)", "DMS_2_DD", 3
    modUDFs.RegisterUDF "Calculates the Time between two time stamps" & vbLf & _
                        "rbcElapsedTime(<end time>,<start time>,<output code>)" & vbLf & _
                        "0 = <Seconds>,  1 = <Minutes:Seconds>" & vbLf & _
                        "2 = <Hours:Minutes:Seconds>,  3 = <Days Hours:Minutes:Seconds>", "ElapsedTime", 2
End Sub

请注意,Workbook_BeforeClose 事件已消失,我已将取消注册调用移至 App_WindowDeactivate 事件。这解决了这两个问题,并为我提供了一个可以注册和取消注册我的 UDF 的插件。上面的所有代码都放在 ThisWorkbook 中,下面处理 UDF 注册和取消注册的代码放在我的 modUDFs 代码模块中

Sub RegisterUDF(ByVal fDescription As String, ByVal fUDFName As String, ByVal fCategory As Variant)
    'Integer Category
    '1   Financial
    '2   Date & Time
    '3   Math & Trig
    '4   Statistical
    '5   Lookup & Reference
    '6   Database
    '7   Text
    '8   Logical
    '9   Information
    '10  Commands
    '11  Customizing
    '12  Macro control
    '13  DDE/External
    '14  User Defined
    '15  First custom category
    '16  Second custom category
    '17  Third custom category
    '18  Fourth custom category
    '19  Fifth custom category
    '20  Sixth custom category
    '21  Seventh custom category
    '22  Eighth custom category
    '23  Ninth custom category
    '24  Tenth custom category
    '25  Eleventh custom category
    '26  Twelfth custom category
    '27  Thirteenth custom category
    '28  Fourteenth custom category
    '29  Fifteenth custom category
    '30  Sixteenth custom category
    '31  Seventeenth custom category
    '32  Eighteenth custom category
    
    If IsNull(fCategory) Then fCategory = 9
    If fCategory = "" Then fCategory = 9
    Application.MacroOptions Macro:=fUDFName, Description:=fDescription, Category:=fCategory
End Sub

Sub UnregisterUDF(ByVal fUDFName As String)
    Application.MacroOptions Macro:=fUDFName, Description:=Empty, Category:=Empty
End Sub