<ribbon startFromScratch="true">
在處理QAT時(shí),你會(huì)注意到有兩類(lèi)圖標(biāo),一種在其周?chē)羞吙蚨硪环N則沒(méi)有,這種區(qū)別表明哪種控件是共享控件,哪種控件是文檔控件。
QAT文檔控件的XML代碼如下:
<qat><documentControls><control/></documentControls></qat>
QAT共享控件的XML代碼如下:
<qat><sharedControls><control/></sharedControls></qat>
在QAT中添加自定義和內(nèi)置命令
快速訪問(wèn)工具欄共享或文檔控件的子元素如下表。
表:QAT的子元素
對(duì)象 用來(lái)做什么 control 引用可以表現(xiàn)其它對(duì)象例如按鈕、拆分按鈕、組等的普通控件對(duì)象 button 引用按鈕控件 separator 引用分隔條控件
如下圖所示,在QAT中添加內(nèi)置控件和自定義按鈕。
XML代碼如下:
<qat><documentControls><control idMso="Bold" screentip="Make it Bold" supertip="Click here to make the selected text bold."/><button id="rxbtnOpen" imageMso="FileOpen" screentip="This is Happy" supertip="Click here for a happy message" onAction="rxbtnOpen_click"/></documentControls></qat>
可以使用control對(duì)象引用內(nèi)置的按鈕(本例中為加粗按鈕),接著使用按鈕創(chuàng)建自已的定制按鈕(可以使用control對(duì)象引用其它控件例如按鈕或拆分按鈕)。
下面的示例創(chuàng)建一個(gè)splitButton控件,然后將其添加到QAT。因?yàn)镼AT沒(méi)有splitButton子元素,我們必須在QAT之外創(chuàng)建splitButton,然后將其引用到QAT??梢酝ㄟ^(guò)以普通的方式添加splitButton來(lái)實(shí)現(xiàn)——也就是說(shuō),通過(guò)將其添加到組中開(kāi)始:
<group id="rxgrp" label="My Custom Group"><splitButton id="rxsbtn" size="large"><button id="rxbtn2" imageMso="HappyFace" label="My Happy Split"/><menu id="rxmnu"><button id="rxbtn3" label="My Happy Menu" imageMso="HappyFace" onAction="rxbtn3_click"/></menu></splitButton></group>
上面已經(jīng)有splitButton并帶有一個(gè)菜單,菜單中包含一個(gè)按鈕。由于QAT使用現(xiàn)有的控件,因此現(xiàn)在可以在QAT中引用已存在的拆分按鈕了,XML代碼如下:
<qat><documentControls><control id="rxsbtn" imageMso="HappyFace" screentip="This is Happy" supertip="Click here for a happy message"/></documentControls></qat>
結(jié)果如下圖所示。
在QAT中添加自定義和內(nèi)置組
必須首先創(chuàng)建組,然后從QAT中引用指定該組的id??梢蕴砑咏M到選項(xiàng)卡中并使其在選項(xiàng)卡中不可見(jiàn)而在QAT中可見(jiàn)。
如上圖所示,My QAT Custom Group屬于自定義的“Home”選項(xiàng)卡,然而我們將其可見(jiàn)屬性設(shè)置為False,使其在選項(xiàng)卡上隱藏而在QAT中可見(jiàn)。XML代碼如下:
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"><ribbon startFromScratch="true"><tabs><tab id="rxtabHome" label="Home"><group idMso="GroupClipboard"/><group idMso="GroupFont"/><group idMso="GroupAlignmentExcel"/><group idMso="GroupNumber"/><group idMso="GroupStyles"/><group idMso="GroupCells"/><group idMso="GroupEditingExcel"/><group id="rxgrp" label="My QAT Custom Group" getVisible="rxshared_getVisible"> <button id="rxbtnHappy" label="Mr. Happy Face" imageMso="HappyFace" size="large" onAction="rxshared_click" /><button id="rxbtnHappy2" label="Mr. Happy Face 2" imageMso="HappyFace" size="large" onAction="rxshared_click" /></group> </tab></tabs> <qat><documentControls><control idMso="GroupInsertChartsExcel"/><control idMso="GroupFunctionLibrary"/><control id="rxgrp" imageMso="FormatCellsDialog"/></documentControls></qat> </ribbon></customUI>
這里,因?yàn)橐幚鞶AT,所以我們從頭開(kāi)始定制用戶界面,然后以常規(guī)方式設(shè)置自定義選項(xiàng)卡和組并在自定義組中添加了兩個(gè)按鈕,將自定義組的getVisible屬性設(shè)置為False,使其不會(huì)在選項(xiàng)卡中顯示。最后,在QAT標(biāo)簽中,添加了兩個(gè)自定義組,然后使用通用的control對(duì)象來(lái)引用想在QAT中顯示的自定義組,同時(shí)為組賦予了內(nèi)置的圖像。
注意,有時(shí)雖然我們?cè)赒AT中定制了組,但打開(kāi)Excel時(shí)不會(huì)出現(xiàn),這是QAT中的一個(gè)“小問(wèn)題”,后文將給出解決方法。
重利用QAT控件
當(dāng)重利用QAT中的控件時(shí),實(shí)際上重利用與之相關(guān)的命令,然后作為控件在QAT中添加相同的命令。
重利用的一個(gè)主要優(yōu)勢(shì)是會(huì)對(duì)該控件產(chǎn)生全局影響。
下面的XML代碼重利用Excel中的兩個(gè)控件——打開(kāi)和保存:
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="rxIRibbonUI_onLoad"><commands><command idMso="FileSave" onAction="rxFileSave_repurpose"/><command idMso="FileOpen" onAction="rxFileOpen_repurpose"/></commands> <ribbon startFromScratch="true"><qat><documentControls><control idMso="FileSave" screentip="Repurposed Save" supertip="This is a repurposed command"/> <control idMso="FileOpen" screentip="Repurposed File Open" supertip="This is a repurposed command"/></documentControls></qat></ribbon> </customUI>
首先,聲明希望重利用的命令并賦宏給每個(gè)控件,接著在ribbon標(biāo)記里定義希望在QAT中出現(xiàn)的命令。
注意,這將產(chǎn)生全局影響,也就是說(shuō),如果在該命令出現(xiàn)的任一位置單擊該命令或者使用指向該命令的快捷鍵(這里是Ctrl+o和Ctrl+s),該命令將指向賦值給onAction屬性的回調(diào)。
在Excel中還可以使用不同的方式。Excel有一個(gè)名為OnKey的便捷的方法,當(dāng)按下指定的鍵或鍵組合時(shí)觸發(fā)。這是一個(gè)應(yīng)用程序級(jí)的方法,因此一旦在某工作簿中禁用了某命令,所有在相同會(huì)話中打開(kāi)的其它工作簿都將禁用該命令。
因此,在Excel中,如果僅僅需要取消包含UI的工作簿中的快捷鍵,那么在移動(dòng)到另一個(gè)工作簿中時(shí)或者當(dāng)打開(kāi)工作簿時(shí)需要撤銷(xiāo)該快捷鍵的取消。因?yàn)檫@是一個(gè)應(yīng)用程序級(jí)的事件,所以需要使用類(lèi)模塊來(lái)監(jiān)控并響應(yīng)在工作簿間的轉(zhuǎn)換。
在Excel項(xiàng)目中添加一個(gè)類(lèi)模塊并命名,本例中命名為clsAppExcelEvents,輸入下面的代碼:
Public WithEvents appXL As Excel.Application Private Sub ShortcutsEnabled(ByVal blnEnabled As Boolean)Select Case blnEnabledCase Is = TrueApplication.OnKey "^o"Application.OnKey "^s"Case Is = FalseApplication.OnKey "^o", "commandDisabled"Application.OnKey "^s", "commandDisabled"End SelectEnd Sub Private Sub setEnabled(ByVal Wb As Workbook)Select Case Wb.NameCase Is = ThisWorkbook.NameShortcutsEnabled FalseCase ElseShortcutsEnabled TrueEnd SelectEnd Sub
注意,在類(lèi)模塊的聲明部分聲明Excel應(yīng)用程序。有兩個(gè)程序來(lái)實(shí)現(xiàn)這項(xiàng)任務(wù):一個(gè)程序檢查哪個(gè)工作簿是活動(dòng)工作簿,另一個(gè)程序指定OnKey方法。OnKey方法的鍵組合字符之后,是程序名commandDisabled,該程序必須放置在標(biāo)準(zhǔn)模塊中。
在類(lèi)模塊中,可以指定監(jiān)控的事件。例如,可以監(jiān)控某工作簿的激活或失活,決定是否取消快捷鍵:
Private Sub appXL_WorkbookActivate(ByVal Wb As Workbook)setEnabled WbEnd Sub Private Sub appXL_WorkbookDeactivate(ByVal Wb As Workbook)setEnabled WbEnd Sub
最后,需要在工程打開(kāi)時(shí)設(shè)置類(lèi),這由包含該工程的工作簿的Open事件來(lái)實(shí)現(xiàn):
Dim XL As New clsAppExcelEventsPrivate Sub Workbook_Open()Set XL.appXL = ApplicationEnd Sub
使用表驅(qū)動(dòng)(Table-Driven)方式定制QAT
下圖是一個(gè)自定義QAT的示例,使用表裝載詳細(xì)信息到QAT中。
首先,編寫(xiě)包含UI和QAT菜單按鈕的XML代碼,這里創(chuàng)建的是文檔控件按鈕:
<documentControls><control id="rxgrp" imageMso="AdvancedFileProperties"/><button id="rxbtnShowPopup" image="rob" screentip="This is Robert's QAT" supertip="You can only customize the QAT by starting from scratch. If you do not do that you will not be able to make any changes..." onAction="rxbtnShowPopup_Click" /></documentControls>
上述XML代碼將產(chǎn)生上圖所示的兩個(gè)QAT按鈕,這里的關(guān)鍵是賦給onAction屬性的回調(diào),單擊該按鈕后將顯示菜單。
接著,創(chuàng)建包含菜單信息的表,如下圖所示。
上圖所示的表只是一個(gè)建議,因?yàn)槟梢栽谄渲刑砑痈嗟倪x項(xiàng)?,F(xiàn)在,使用VBA閱讀該表并創(chuàng)建菜單:
Public Const POPNAME As String = "MY POPUP" Sub loadPopup()Dim mnuWs As WorksheetDim cmdbar As CommandBarDim cmdbarPopup As CommandBarPopupDim cmdbarBtn As CommandBarButtonDim nRowCount As Long Call unloadPopupSet mnuWs = ThisWorkbook.Sheets("MenuItems")Set cmdbar = Application.CommandBars.Add(POPNAME, msoBarPopup) nRowCount = 2With mnuWsDo Until IsEmpty(.Cells(nRowCount, 1)) Select Case UCase(.Cells(nRowCount, 1))Case "POPUP"Set cmdbarPopup = cmdbar.Controls.Add(msoControlPopup)cmdbarPopup.Caption = .Cells(nRowCount, 2)If .Cells(nRowCount, 3) <> "" ThencmdbarPopup.BeginGroup = TrueEnd If Case "BUTTON"Set cmdbarBtn = cmdbarPopup.Controls.Add(msoControlButton)cmdbarBtn.Caption = .Cells(nRowCount, 2)If .Cells(nRowCount, 3) <> "" ThencmdbarBtn.BeginGroup = TrueEnd IfcmdbarBtn.FaceId = .Cells(nRowCount, 4)cmdbarBtn.OnAction = .Cells(nRowCount, 5) Case "BUTTON_STANDALONE"Set cmdbarBtn = cmdbar.Controls.Add(msoControlButton)cmdbarBtn.Caption = .Cells(nRowCount, 2)If .Cells(nRowCount, 3) <> "" ThencmdbarBtn.BeginGroup = TrueEnd IfcmdbarBtn.FaceId = .Cells(nRowCount, 4)cmdbarBtn.OnAction = .Cells(nRowCount, 5) End SelectnRowCount = nRowCount + 1LoopEnd With End Sub Sub unloadPopup()On Error Resume NextApplication.CommandBars(POPNAME).DeleteEnd Sub Sub showAbout()MsgBox "This is a sample on how to customize the QAT on the fly!!", vbInformationEnd Sub Sub showHelp()On Error GoTo Err_HandlerThisWorkbook.FollowHyperlink "http://www.msofficegurus.com", , True, TrueExit Sub Err_Handler:MsgBox Err.Description, vbCritical, Err.Number End Sub
最后,需要編寫(xiě)回調(diào)的代碼。使用onLoad事件調(diào)用loadPopup過(guò)程,以便創(chuàng)建彈出菜單,并準(zhǔn)備當(dāng)在QAT中單擊該按鈕時(shí)使用,也包含當(dāng)發(fā)生單擊時(shí)顯示彈出菜單的單擊事件代碼:
Dim grxIRibbonUI As IRibbonUI Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)On Error Resume NextSet grxIRibbonUI = ribbon Application.Workbooks.AddIf ActiveWorkbook.Name <> ThisWorkbook.Name ThenWith ActiveWorkbook.Saved = True.CloseEnd WithEnd If ' 可以在這個(gè)事件或者ThisWorkbook的Open事件中裝載彈出菜單 Call loadPopupEnd Sub Sub rxbtnShowPopup_Click(control As IRibbonControl)On Error Resume NextApplication.CommandBars(POPNAME).ShowPopupEnd Sub Sub rxbtnHappy_Click(control As IRibbonControl)MsgBox "This is Mr. Happy Face... hurray!!", vbExclamationEnd Sub
定制QAT時(shí)的一些注意事項(xiàng)
雖然在QAT中可以方便地實(shí)現(xiàn)自定義,但也有一些缺陷。
(1)無(wú)法裝載控件
上文中曾經(jīng)談到,在定制好后,例如按鈕和組,打開(kāi)工作簿時(shí),卻發(fā)現(xiàn)定制的控件沒(méi)有出現(xiàn)。這種情況在使用sharedControls時(shí)非常普遍。
一種解決方法是先最小化工作簿,然后再最大化,通過(guò)刷新來(lái)使定制的控件出現(xiàn);或者再打開(kāi)一個(gè)工作簿后,將其關(guān)閉,看看定制的控件是否出現(xiàn)。
(2)無(wú)法為控件裝載自定義圖像
共享控件的表現(xiàn)通常無(wú)法預(yù)料,并且不能提供可信賴(lài)且一致的界面,因此建議在共享控件中盡量不要使用自定義圖像。
至于文檔控件,可以使用下面的過(guò)程刷新包含UI的窗口來(lái)解決此類(lèi)問(wèn)題:
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)Set grxIRibbonUI = ribbonOn Error Resume NextApplication.Workbooks.AddIf ActiveWorkbook.Name <> ThisWorkbook.Name ThenWith ActiveWorkbook.Saved = True.CloseEnd WithEnd IfEnd Sub
上述技巧也能用于無(wú)法裝載自定義控件中。
(3)復(fù)制控件
在QAT中控件的復(fù)制通常發(fā)生在工作簿或文檔之間切換時(shí)。假設(shè)有一個(gè)包含定制的QAT的工作簿,當(dāng)按Alt+Tab移動(dòng)到另一個(gè)文檔,然后返回定制的工作簿時(shí),在QAT中的控件被復(fù)制、三次復(fù)制、四次復(fù)制……這種復(fù)制能夠被傳播到?jīng)]有包含任何XML定制的其它工作簿和文檔。
此時(shí),需要關(guān)閉后重新打開(kāi)文檔才能消除這種不應(yīng)有的復(fù)制。