| excelperfect 在本系列后面的示例程序中,你將會看到如何使用項目和帶圖像的庫控件通過getItemLabel和getItemImage回調(diào)屬性引用的VBA過程在運行時動態(tài)地填充下拉控件。另一個允許動態(tài)填充其內(nèi)容的控件是組合框控件。 動態(tài)菜單控件可以在運行時做更多的事,是唯一一個其內(nèi)容的結(jié)構(gòu)可以在運行時改變的控件,可以包含自定義控件和內(nèi)置控件——包括其他動態(tài)菜單。通過該控件的getContent屬性引用的VBA過程,在運行時為菜單內(nèi)容構(gòu)建XML代碼。 下面介紹一個簡單的使用動態(tài)菜單控件示例,在工作簿中為三個工作表(名為Data,Analysis,Reports)的每個顯示不同的菜單。 1. 創(chuàng)建一個新的工作簿,將其保存為啟用宏的工作簿。 2. 分別重命名工作表為Data、Analysis和Reports。 3. 關(guān)閉該工作簿,然后在Custom UIEditor中打開。 4. 在Custom UI Editor中,單擊Insert并選擇Office2007 Custom UI Part。 5. 復制并粘貼下面的XML代碼: group元素不僅能夠包含動態(tài)菜單,而且還可包含其他控件。 6. 單擊工具欄中的Validate按鈕檢查是否有錯誤。 7. 保存并關(guān)閉該文件。 8. 在Excel中打開該文件。對于彈出的錯誤消息,單擊“確定”。 9. 按Alt+F11激活VBE。 10. 插入標準的VBA模塊,復制并粘貼下面的VBA代碼: Public myRibbon As IRibbonUI 'Callback for customUI.onLoadSub Initialize(ribbon As IRibbonUI)    Set myRibbon = ribbonEnd Sub 'Callback for DynamicMenugetContentSub GetMenuContent(control As IRibbonControl, ByRef content)    Dim xml As String       xml = '<menu xmlns=' & _       '''http://schemas.microsoft.com/office/2006/01/customui''>'           Select Case ActiveSheet.Name        Case 'Data'            xml = xml & '<buttonid=''Btn1'' imageMso=''Cut'''& _                    ' label=''Reformat'''& _                    'onAction=''Reformat'' />'            xml = xml & '<checkBoxid=''checkBox1''' & _                    'label=''Include OEM''' & _                    'onAction=''Checkbox1_Change''/>'            xml = xml & '<menuid=''submenu1''label=''Optional''>'            xml = xml & ' <buttonid=''Btn2''' & _                    'imageMso=''PenComment''' & _                    'label=''TouchUp''' & _                    'onAction=''TouchUp''/>'            xml = xml & ' <buttonid=''Btn3''' & _                    'imageMso=''Breakpoint''' & _                    'label=''Polish''' & _                    'onAction=''Polish'' />'            xml = xml & '<menuSeparator id=''div2'' />'            xml = xml & ' <dynamicMenuid=''subMenu''' & _                    'label=''Submenu''' & _                    'getContent=''GetSubContent'' />'            xml = xml &'</menu>'            xml = xml & '<buttonidMso=''SortDialog'' />'                   Case 'Analysis'            xml = xml & '<buttonid=''Btn1'' imageMso=''_1''' &_                    'label=''Analysis 1''' & _                    'onAction=''Analysis1'' />'            xml = xml & '<buttonid=''Btn2'' imageMso=''_2''' &_                    ' label=''Analysis2''' & _                    'onAction=''Analysis2'' />'            xml = xml & '<buttonid=''Btn3'' imageMso=''_3''' &_                    'label=''Analysis 3''' & _                    'onAction=''Analysis3'' />'            xml = xml &'<menuSeparator id=''div2'' />'            xml = xml &'<dynamicMenu id=''subMenu''' & _                    'label=''Submenu''' & _                    'getContent=''GetSubContent'' />'                           Case 'Reports'            xml = xml & '<buttonid=''Btn1'' imageMso=''A''' &_                    'label=''Report A''' & _                    'onAction=''ReportA'' />'            xml = xml & '<buttonid=''Btn2'' imageMso=''B''' &_                    'label=''Report B''' & _                    'onAction=''ReportB'' />'            xml = xml & '<buttonid=''Btn3'' imageMso=''C''' &_                    'label=''Report C''' & _                    'onAction=''ReportC'' />'            xml = xml &'<menuSeparator id=''div2'' />'            xml = xml &'<dynamicMenu id=''subMenu''' & _                    'label=''Submenu''' & _                    'getContent=''GetSubContent'' />'               Case Else            'Empty dynamic menu               End Select       xml =xml & _        '</menu>'                       content = xml       'To view the XML code in the Immediatewindow    'Debug.Print xmlEnd Sub當首次打開工作簿或者使動態(tài)菜單控件無效時,執(zhí)行GetMenuContent回調(diào)過程。這個過程為動態(tài)菜單的內(nèi)容創(chuàng)建XML代碼。 注意,上面的VBA代碼以類似于CustomUI Editor中的一種方式縮進,通過使用Debug.Print語句發(fā)送構(gòu)建的XML代碼到立即窗口。復制并粘貼該代碼到記事本并在每個開標簽(例如<menu … >)和每個閉標簽(例如<button … />)之后按回車鍵。 'Callback for Sub Dynamic MenugetContentSub GetSubContent(control As IRibbonControl, ByRef SubContent) Dim xml As String xml = '<menu xmlns=' & _ '''http://schemas.microsoft.com/office/2006/01/customui''>' xml = xml & '<buttonid=''subBtn1'' label=''P''' &_ 'onAction=''MacroSubBtn1'' />' xml = xml & '<buttonid=''subBtn2'' label=''Q''' &_ ' onAction=''MacroSubBtn2''/>' xml = xml & '<buttonid=''subBtn3'' label=''R''' &_ 'onAction=''MacroSubBtn3'' />' xml = xml & _ '</menu>' SubContent = xmlEnd Sub 為簡單起見,所有這三個不同的菜單設(shè)置(對于3個不同的工作表)使用相同的子動態(tài)菜單。 'Callbacks for the controls inthe dynamic menu'when the Data sheet isactivatedSub Reformat(control As IRibbonControl)    MsgBox 'Reformat'End Sub  Sub Checkbox1_Change(control As IRibbonControl, pressed As Boolean)    MsgBox 'OEM check box is checked:' & pressedEnd Sub Sub TouchUp(control As IRibbonControl)    MsgBox 'TouchUp'End Sub Sub Polish(control As IRibbonControl)    MsgBox 'Polich'End Sub  'Callbacks for the controls inthe dynamic menu'when the Analysis sheet isactivatedSub Analysis1(control As IRibbonControl)    MsgBox 'Analysis 1'End Sub Sub Analysis2(control As IRibbonControl)    MsgBox 'Analysis 2'End Sub Sub Analysis3(control As IRibbonControl)    MsgBox 'Analysis 3'End Sub 'Callbacks for the controls inthe dynamic menu'when the Reports sheet isactivatedSub ReportA(control As IRibbonControl)    MsgBox 'Report A'End Sub Sub ReportB(control As IRibbonControl)    MsgBox 'Report B'End Sub Sub ReportC(control As IRibbonControl)    MsgBox 'Report C'End Sub 'Callbacks for the controls inthe sub dynamic menuSub MacroSubBtn1(control As IRibbonControl)    MsgBox 'P'End Sub Sub MacroSubBtn2(control As IRibbonControl)    MsgBox 'Q'End Sub  Sub MacroSubBtn3(control As IRibbonControl)    MsgBox 'R'End Sub  'Callback for CustomBtn1onActionSub MacroCustomButton(control As IRibbonControl)    MsgBox 'Custom Button'End Sub11. 在ThisWorkbook模塊中插入下面的VBA代碼: Private Sub Workbook_SheetActivate(ByVal Sh As Object) myRibbon.InvalidateControl 'DynamicMenu'End Sub 12. 保存,關(guān)閉,然后重新打開該工作簿。 下面展示了選擇不同的工作表時的菜單內(nèi)容: 保留自定義復選框的勾選條件 在上面的示例XML和VBA代碼中,當用戶在工作表Data中單擊動態(tài)菜單中的復選框后,復選框會相應地顯示勾選或者取消勾選。 然而,如果用戶在設(shè)置勾選該復選框后,通過單擊工作表標簽激活其他工作表,那么動態(tài)菜單被無效,與菜單相關(guān)的任何數(shù)據(jù)(包括復選框的勾選條件)將被銷毀。當重新激活工作表Data時,通過調(diào)用GetMenuContent過程會重新創(chuàng)建菜單,而復選框會重置為其默認值(即,取消勾選條件)。 如果要保留條件,可以在其被無效前存儲其狀態(tài),然后在重新創(chuàng)建菜單時恢復其狀態(tài)。這可以通過使用模塊級的變量和getPressed回調(diào)屬性來實現(xiàn)。下面,我們修改現(xiàn)有的VBA代碼來實現(xiàn)此目的(加黑的代碼是在上面代碼中增加的代碼): 1. 聲明模塊級的變量來存儲復選框的狀態(tài): Public myRibbon As IRibbonUIDim Checkbox1Pressed As Boolean2. 在GetMenuContent過程中加入為getPressed屬性的VBA代碼: Select Case ActiveSheet.Name Case 'Data' xml = xml & '<buttonid=''Btn1'' imageMso=''Cut'''& _ 'label=''Reformat''' & _ 'onAction=''Reformat'' />' xml = xml & '<checkBoxid=''checkBox1''' & _ 'label=''Include OEM''' & _ 'getPressed=''CheckBox1getPressed''' & _ 'onAction=''Checkbox1_Change''/>' 3. 在Checkbox1_Change過程中包含額外的代碼語句,由checkBox元素的onAction屬性引用: Sub Checkbox1_Change(control As IRibbonControl, pressed As Boolean)    MsgBox 'OEM check box is checked:' & pressed    Checkbox1Pressed = pressedEnd Sub當用戶單擊該復選框時,執(zhí)行Checkbox1_Change并在Checkbox1Pressed變量中存儲復選框的狀態(tài)。 4. 插入由getPressed屬性引用的CheckBox1getPressed過程: Sub CheckBox1getPressed(control As IRibbonControl, ByRef returnedVal) returnedVal = Checkbox1PressedEnd Sub 當用戶重新激活工作表Data并單擊動態(tài)菜單時,該菜單會重新創(chuàng)建并執(zhí)行CheckBox1getPressed過程。接著,通過在使復選框無效前存儲復選框狀態(tài)的Checkbox1Pressed變量重新賦值該復選框的狀態(tài)。 5. 保存,關(guān)閉,然后重新打開該工作簿。 現(xiàn)在,復選框能夠保留其在動態(tài)菜單被無效并重新構(gòu)建后的狀態(tài)。正如所看到的,Checkbox1Pressed模塊級變量在過程調(diào)用之間保留其值。 一般而言,即使工作簿中的代碼執(zhí)行完畢,工作簿中的公共級別變量、模塊級變量和過程級靜態(tài)變量仍然保留其值??梢允褂靡韵滤姆N方法清除這些變量存儲的值: 
 如果沒有未處理的錯誤,你可以只執(zhí)行前兩種方法,而用戶可以僅執(zhí)行最后一種方法。因此,只要該工作簿文件保持打開,Checkbox1Pressed變量就能夠合適地反映該復選框的狀態(tài)。 如果要在用戶關(guān)閉并重新打開該文件之后保留該復選框的狀態(tài),那么可能要在隱藏的工作表或者在Windows注冊表中存儲其狀態(tài)。 說明:本專題系列大部分內(nèi)容學習整理自《Dissectand Learn Excel VBA in 24 Hours:Changingworkbook appearance》,僅供學習研究。 注:如果你有興趣,你可以到知識星球App的完美Excel社群下載這本書的完整中文版電子書。 | 
|  | 
來自: hercules028 > 《VBA》