Gianni Giaccaglini

Tricks & mini applics on WPF
posts - 46, comments - 0, trackbacks - 0

martedì 1 aprile 2014

Ribbon personale per Office rivisitato

 

Personalizzazione del Ribbon, rivisitata

Gianni Giaccaglini

La barra multifunzione di Office, alias Ribbon, introdotta fin dalla versione 2007 è oggi più che familiare agli utenti. Nel frattempo si è persa di vista la possibilità di personalizzarla,specie in particolari documenti o modelli più o meno chiusi per l’utente finale. Confesso che ciò vale in particolare per chi scrive, a causa della macchinosità delle operazioni che, per giunta, non si possono automatizzare con codice macro, essendo il Ribbon un oggetto XML. In un precedente post su questo blog ho illustrato la possibilità di celare l’invadente Ribbon in Excel coi comandi che qui ripeto:

'Il Ribbon sparisce:

Application.ExecuteExcel4Macro "SHOW.TOOLBAR(""Ribbon"",False)"

'Il Ribbon riappare:

Application.ExecuteExcel4Macro "SHOW.TOOLBAR(""Ribbon"",False)"

 

Una misura così estremistica ha suscitato qualche critica, così ho deciso di pubblicare nuovamente informazioni piuttosto dettagliate sull’argomento, visto che oltretutto il trucco precedente non si applica a Word o PowerPoint.

La trattazione (quasi) completa

Office 2007 ha sostituito le molte precedenti barre strumenti (Commandbar) con un’unica barra multifunzione, in inglese Ribbon User Interface, abbreviato Ribbon UI. Le sole commandbar personali restano in vita, rese però obsolete da una tecnologia RibbonX (sta per Ribbon Extensibility), che descrive in linguaggio XML le caratteristiche di un ribbon personalizzato in un file customUI.xml, componente incorporato – almeno con Word, Excel e PowerPoint - in uno dato documento macro-enabled (xlsm, in Excel, docm in Word) o in un add-in (xlam in Excel) o un template Word dotm, secondo la famosa struttura open xml adottata da Microsoft con Office 2007. RibbonX consente multiformi, camaleontiche metamorfosi della nuova interfaccia utente (gli Autori Microsoft parlano di “fluent ribbon interface”) la cui natura XML fa sì che per tali personalizzazioni può bastare il Blocco Note. Occorre però apprendere la sintassi dei tag descrittori dei componenti del Ribbon, strutturati gerarchicamente: si va dalle tab (schede) ai group  (gruppi in cui si articolano le schede) fino ai control (controlli: pulsanti, caselle ecc.) cui si possono associare le cosiddette callback routine.

Si può così stravolgere sia il volto che le funzionalità, aggiunte o ridefinite, del ribbon. Le routine callback si possono scrivere in VBA (Visual Basic for application, le macro tradizionali) o C# (in ambito VSTO, Visual StudioTools per Office) e in questa sede di VBA ci occuperemo, per il suo più immediato utilizzo e perché identica è la natura e struttura di un archivio customUI.xml.

In medias res con un semplicissimo esempio

Proponiamoci l’aggiunta, in una cartella Excel macro enabled, di una tab (scheda) personale che si affianchi alle altre del ribbon, composta da un solo group (gruppo) comprendente due button (pulsanti di comando), ciascuno scatenante una determinata macro da noi creata.

Anticipazione importante. Prima di descrivere le operazioni da compiere, mi preme svelare che il passo 1 si può evitare compiendo direttamente la digitazione di cui al passo 2 nella finestra del Custom UI Editor, evitando anche altre noie relative ai passi da 4 in poi. Ne parlerò più avanti, comunque chi ha fretta può scaricare tale utile utility da questo sito, ove ne vengono descritte le peculiarità:

http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2006/05/26/customuieditor.aspx

Chi ha fretta può farlo direttamente da qui (NB: prima di communityserver c’è l’underscore _ ):

http://openxmldeveloper.org/cfs-file.ashx/_communityserver-components-postattachments/00-00-72-93/officecustomUIEditorSetup.zip

 

Procediamo con la prassi normale, che ha il pregio di chiarire bene quel che accade.

  1. Creare un file customUI.xml, con un editor di testo XML o anche il semplice Notepad.
  2. digitandovi questo codice XML:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">

  <ribbon>

    <tabs>

      <tab id="PersonTab" label="Mia Tab"  insertAfterMso="TabHome">

         <group id="PersonGruppo" label="Mio Gruppo">

            <button id="Puls1" size="large" tag="OraAttuale" label="Segnala l’ora" onAction="SegnalaOra" />

            <button id="Puls2" size="large" tag="LanciaUserForm" label="Lancia UserForm" onAction="LanciaUserForm" />

         </group>

      </tab>

    </tabs>

  </ribbon>

</customUI>

 

 

NOTA. La direttiva iniziale potrebbe recare Office/2009/07 in luogo di Office/2006/01 supportando così speciali novità di Office 2010/2013. Ma è una sottigliezza per espertissimi.

  1. Creare una cartella Excel PrimaProva.xlsm, e nell’Editor VBA inserire le macro seguenti, più una UserForm1 a piacere.

Sub SegnalaOra(ByVal controllo As IRibbonControl)

  msg = "Ore " & Hour(Time) & " e " & Minute(Time) & " minuti"

  'Indica l’orario e il nome del pulsante

  MsgBox msg, vbInformation, controllo.Tag

End Sub

 

Sub LanciaUserForm(ByVal controllo As IRibbonControl)

  'Richiama la UserForm...

  Load UserForm1

  UserForm1.Show

End Sub

 

Sono le Sub associate ai controlli Button1 e Button2 descritti nel customUI.xlm, il cui compito è ovvio, ma senza dimenticare l’argomento controllo, di ben preciso tipo IRibbonControl altrimenti la macro fallisce.

  1. Chiudere PrimaProva.xlsm e modificarne l’estensione .xlsm in .zip, poi con manovre date per note, aggiungervi il predetto customUI.xml.
  2. Aprire la cartella _rels  e aggiungere le righe seguenti prima della tag finale delle Relationships, una direttiva che indica il “target” che descrive il ribbon personale:

<relationship Id="someID" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml" />

NOTA. Si può pensare di sostituire customUI.xml con un nome diverso, ma è da sconsigliare specie se si usa l’editor ad hoc (v. più avanti).

  1. Chiudere il file .zip e ripristinarne l’estensione originaria .xlsm.

Alla riapertura di PrimaProva.xlsm si noterà la neonata Mia Tab, col gruppo etichettato "Mio Gruppo" che mostra due grossi pulsanti, corredati dalle label previste. Cliccando sull’uno o sull’altro otterremo quel che promettono.

Ciascuno potrà progettare una Userform1 di suo gusto oppure modificare le macro senza toccare il customUI.xlm. E una volta creato e incorporato quest’ultimo, le routine associate si possono modificare, in particolare per le eventuali UserForm richiamate.

Tab personali con pochi pulsanti soddisfano i casi normali della vita, per cui si può pensare di predisporre una serie di file customUI.xml tipici da adattare a varie esigenze per inserirli in questo o quel documento. Qui conviene poi anticipare la possibilità di salvare un file macro enabled che incorpora un customUI.xml d’uso generale in forma di add-in (.xlam), poi richiamabile in un qualsiasi file .xlsm (o .docm) che così assume quella particolare interfaccia utente senza avere in pancia un (proprio) customUI.xml.

La figura 1 illustra, senza commenti, una situazione più complessa conseguente all’aggiunta di un secondo gruppo della "Mia Tab", comprendente controlli di altro tipo, come una editBox e una comboBox, un pot pourri che però evidenzia la versatilità di questa tecnica e la sua perfetta consistenza col Ribbon.

http://www.giannigiaccaglini.it/download/FigRibbon-01.jpg

Figura 1

Altri particolari d’anteprima

I diversi componenti RibbonX godono di numerosi attributi. Oltre ai label o size già viste citiamo insertAfterMso=”TabData” o insertBeforeMso=”TabHome” e visible=”false” o enabled=”false”. I primi due collocano la tab personale accanto alla tab standard Home anziché in fondo alle tab.

Interessante l’opzione di apertura startFromScratch del tag ribbon:

<ribbon startFromScratch="true">

startFromScratch per default ="false" col valore "true" occulta tutte le tab standard, mantenendo solo i comandi Nuovo, Apri e Salva del menu Office. Tale direttiva, come si comprende è particolarmente utile per i modelli molto chiusi per l’utente finale.

Prima di procedere con una trattazione passabilmente sistematica riteniamo utile fornire subito una precisazione e qualche indicazione di documenti sul tema reperibili sul web.

RibbonX con Access e Outlook. L’esempietto preliminare e quelli che andremo a proporre prevedono l’incorporazione di un customUI.xlm nel documento XML (di regola in un’omonima cartella). Come tutti comprendono, se non ci hanno già pensato, ciò non ha senso con Access né tantomeno con Outlook, che non prevede documenti separati, tuttavia l’implementazione di ribbon personali è possibile anche in questi mondi, tramite add-in e… complicanze che esulano dagli scopi di questo articolo, interamente focalizzato su Excel, anche nella convinzione che i concetti base che esamineremo accomunano tutti i membri della famiglia Office 2007.

Link essenziali

Ripeto a beneficio di pigri & smemorati il link da cui scaricare Il Custom UI Editor:

http://openxmldeveloper.org/cfs-file.ashx/_communityserver-components-postattachments/00-00-72-93/officecustomUIEditorSetup.zip

(o con una ricerca via Google; tale link potrebbe variare nel tempo...)

Una volta installata tale utility la si può lanciare e subito compare una semplicissima dialog box con una commanbar che presenta un paio di opzioni. L’operazione inizia col comando Open seguito dall’indicazione del nostro file .xlsm o .docm, che sarà stato creato, perlomeno nei suoi termini essenziali. Subito dopo si scriverà nella finestra centrale del codice XML come quelle descritto sopra. Al termine occorre e basta salvare il lavoro.

La figura 2 illustra la creazione (o la successiva revisione) di un customUI.xml relativo al file .xlsm aperto. Rispetto all’elementare esempio precedente si hanno tra l’altro due gruppi, un combo box e una routine OnChange di quest’ultimo, legato alla scelta dell’elemento (item). Ne parleremo più diffusamente in seguito.

 

http://www.giannigiaccaglini.it/download/FigRibbon-02.jpg

Figura 2

Questa utility inserisce automaticamente le relationship di cui sopra, risparmiandoci una bella noia.

Un semplice esercizio

A beneficio dei principianti, rivisitiamo l’XML relativo al file PrimaProva.xlsm descritto all’inizio con qualche piccola variante:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">

  <ribbon startFromScratch="true">

    <tabs>

      <tab id="PersonTab" label="Mia Tab"  insertAfterMso="TabHome">

         <group id="PersonGruppo" label="Mio Gruppo">

            <button id="Puls1" size="large" tag="OraAttuale"

              label="Segnala l’ora" image="OROLOG" onAction="SegnalaOra" />

            <button id="Puls2" size="large" tag="LanciaUserForm" label="Lancia UserForm" image="ASINO" onAction="LanciaUserForm" />

         </group>

      </tab>

    </tabs>

  </ribbon>

</customUI>

 

Le novità, evidenziate in grassetto sono questi argomenti:

 startFromScratch="true" attributo aggiunto alla tag <Ribbon>;

image="OROLOG"aggiunto al <Button id=”Puls 1 ... >

image="ASINO"aggiunto al <Button id=”Puls 2 ... >

Le operazioni da compiere sono qui sotto elencate.

  1. Nello spreadsheet PrimaProva.xlsm preparare le macro SegnalaOra e LanciaUserForm viste in apertura.
  2. Creare una banale UserForm1 dotata di una TextBox1 e un CommandButton1 e, per dare un senso pratico al suo apparire, aggiungere una macro (normale) dell’evento Click del secondo:

Private Sub CommandButton1_Click()

  ' Contenuto della TextBox1 in A1

  Range("A1") = TextBox1.Text

End Sub

  1. Lanciare il Custom UI Editor avendo cura di salvare e chiudere PrimaProva.xlsm (altrimenti il passo seguente non avrebbe senso).
  2. Aprire PrimaProva.xlsm col comando File > Open.
  3. Dare un clic sull’icona Insert Icons e nella susseguente finestra attingere al file .jpg o .png che ci piace (suggeriamo di copiarlo preliminarmente nella stessa cartella ove risiede PrimaProva.xlsm). L’importante è che il nome da indicare nell’attributo Image sia privo di estensione (per es. image=”OROLOG” se il file è un certo OROLOG.jpg).

La Figura 3 esibisce una fase in cui il nostro Editor dell’ultima edizione 2010, presenta nel riquadro di destra le figurine man mano prelevate.

http://www.giannigiaccaglini.it/download/FigRibbon-03.jpg

Figura 3

  1. Salvare il risultato, ripetere l’operazione precedente per la seconda icona, salvare ancora e chiudere L’Editor.

La Figura 4 mostra il risultato, che pensiamo non meriti commenti.

http://www.giannigiaccaglini.it/download/FigRibbon-04.jpg

Figura 4

Un ampio repertorio di immagini appositamente studiate per il Ribbon e suddivise per categorie si trova all’URL seguente:

http://soltechs.net/customUi/imageMso01.asp

La pagina si presenta in sostanza così:

  • Click the Gallery link (Gal 1 through Gal 9) to see the images and the imageMso name you need all in one place.
  • Click in the Text Box with the imageMso information. It will select the text and you can copy and paste it into your project...
  • The galleries have between 245 and 321 individual .JPG images in them, so they take a while to load. The "All (overview)" page contains all 2,577 images in a static display.

E

Gal 1 (Large)

Gal 2 (Large)

Gal 3 (Large)

Gal 4 (Small)

Gal 5 (Small)

Gal 6 (Small)

Gal 7 (Small)

Gal 8 (Small)

Gal 9 (Small)

All (overview)

 

I vari Gal1, Gal2 ecc. danno adito alle varie “gallerie” di tipi, ciascuno corredato di una precisa stringa (cpme la “HappyFace” di cui fra poco, affiancata dalla figura risultante.

Importante. Nelle tag XML si deve usare l’attributo imageMso in luogo dello Image relativo a figure locali.

Vediamo subito un semplice esempio. Nella precedente tag,relativa al secondo pulsante basta sostituire a Image=”ASINO” con:

<button id="Puls2"imageMso="HappyFace"... />

Per vedere una nota faccina gialla ridente al posto dell’asinello.

NOTA. Il bello della faccenda è che non occorre, come con image, attingere a un nostro file locale. Basta copiare fedelmente la stringa indicata in quella tal galleria.

Altre immagini standard: “FilePrint”, “FilePrintPreview”, “FileSave, “Filter” ecc., molte relative a comandi già presenti nel Ribbon normale, con rischio di confusione qualora se ne associ macro troppo personali... Interessanti piuttosto cose come “BlogHomePage” o "StartAfterPrevious" che raffigurano, l’uno una casetta, l’altro un orologio.

Immagini per controlli normali della vita. Sono quelle che visualizzano i familiari controlli ActiveX, CommandButton, ListBox ecosì via. Sono reperibili nella Gal 4 (Small), di nome auto-eloquente:

“ActiveXButton”

“ActiveXComboBox”

imageMso="ActiveXListBox"

eccetera.

Creazione di add-in

In questo esempio ci proponiamo di creare un add-in di pura interfaccia che semplicemente ridisponga alcuni componenti standard (built-in, in inglese) raggruppandoli in modo più consono a un certo modus operandi. A tale scopo si cominci col creare un file Revisioni.xlsm e, dopo averlo salvato e chiuso mediante il Custom UI Editor inserirvi il file customUI.xml seguente:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">

  <ribbon>

    <tabs>

      <tab id="Audit" label="Revisioni" >

        <group idMso="GroupFormulaAuditing" />

        <group idMso="GroupFont" />

        <group idMso="GroupNumber" />

        <group id="Varie" label="Operazioni varie">

          <box id="SortBox">

            <control idMso="SortAscendingExcel" showLabel="false"/>

            <control idMso="SortDescendingExcel" showLabel="false"/>

            <control idMso="SortDialog" showLabel="false"/>

          </box>

          <control idMso="Copy" />

          <control idMso="PasteMenu" />

          <separator id="Separatore1" />

          <control idMso="NameManager" />

          <control idMso="ViewFreezePanesGallery" />

          <control idMso="WindowSwitchWindowsMenuExcel" />

        </group>

      </tab>

    </tabs>

  </ribbon>

</customUI>

Aprendo di nuovo Revisioni.xlsm noteremo in fondo al Ribbon la nuova tab Revisioni di figura 5.

http://www.giannigiaccaglini.it/download/FigRibbon-05.jpg

Figura 5

Revisioni.xlsm potrà servire per modifiche successive dell’add-in di cui stiamo per indicare le operazioni necessarie.

Per creare un add-in occorre eseguire le mosse qui sotto indicate.

 

1.       Aprire un file come il nostro Revisioni.xlam.

2.       Salvarlo con Salva con nome... scegliendo Tipo File: Componente Aggiuntivo di Excel (*.xlsm)

Si otterrà così la registrazione sistematica nella sottocartella Addins di Excel. Da quel momento esso si può utilizzare scegliendo Revisioni.xlsm nell’elenco dei Componenti aggiuntivi, che aggiunge la tab Revisioni a qualunque file Excel aperto. In verità in nostre prove nelle versioni dalla 2007 alla 2013 confessiamo di essere incappati a fallimenti, a volte ovviati con un provvidenziale pulsante Sfoglia... Auguri!

NOTA. In ogni caso ci sentiamo di sconsigliare di creare add-in partendo da file .xlsm o .docm dotate, come nel caso PrimaProva.xlsm, di macro dotate di argomento ByVal controllo As IRibbonControl legate a un modello particolare: darebbero errore su file qualsiasi! Di regola esse dovrebbero comprendere esclusivamente codice di tipo generale (trattamento di celle, righe, formati ecc.). Ma ne vale la pena?

Nella giungla delle tab, dei gruppi e dei controlli

Ai più esperti suggeriamo anzitutto di cercare articoli sul Ribbon nell’(affollato) blog di Frank Rice:

http://blogs.msdn.com/b/frice/

Il nostro fluent ribbon presenta una miriade di componenti. Con un po’ di pazienza sul sito Microsoft si possono reperire e scaricare diversi file Excel, contenenti l’elenco completo dei controlli e dei relativi tab o gruppi dei vari membri di Office 2007/2011/2013.

Per chi non ha grandi ambizioni ne forniamo qui sotto uno scampolo relativo a Excel, limitato alle tab TabHome e TabInsert, depurato di talune intestazioni e di molte voci:

Control Name

Control Type

Tab Name

Group Name

TabHome

Tab

 

 

GroupClipboard

Group

TabHome

 

Paste

Button

TabHome

GroupClipboard

PasteSpecialDialog

Button

TabHome

GroupClipboard

Cut

Button

TabHome

GroupClipboard

Copy

Button

TabHome

GroupClipboard

Bold

toggleButton

TabHome

GroupFont

Italic

toggleButton

TabHome

GroupFont

Underline

toggleButton

TabHome

GroupFont

GroupNumber

Group

TabHome

 

NumberFormatGallery

comboBox

TabHome

GroupNumber

GroupCells

Group

TabHome

 

InsertCellstMenu

splitButton

TabHome

GroupCells

AutoSum

Button

TabHome

GroupEditingExcel

TabInsert

Tab

 

 

PivotTableInsertMenu

splitButton

TabInsert

GroupInsertTablesExcel

PivotTableInsert

Button

TabInsert

GroupInsertTablesExcel

PivotChartInsert

Button

TabInsert

GroupInsertTablesExcel

Cerchiamo di fissare i punti salienti. Tutti i componenti del Ribbon sono in inglese e validi pure nelle edizioni localizzate. I nomi di ciascuno sono definite mediante tre distinti identificatori (univoci):

-      idMso per i componenti standard (es. <group idMso="GroupFont" />);

-      id per quelli customizzati (es. <box id="SortBox">);

-      idQ, identificatori "qualificati", relativi a specifici namespace e dei quali diamo solo cenno.

Tali parole chiave non vanno confuse tra loro, rispettandone i ruoli!, inoltre sottolineiamo la necessità di rispettare rigorosamente maiuscole e minuscole, come ben sa chi si è accostato all’XML, pena fastidiosi rigetti. Un esempio per tutti è onAction, che i primi tempi è facile scrivere OnAction, un termine VBA consimile (relativo a pulsanti delle Commandbar tradizionali).

Le tab built-in principali sono TabHome, TabInsert, TabPageLayoutExcel, TabFormulas, TabData, TabReview, TabView, TabDeveloper (se l’utente l’ha attivata) cui va aggiunto un OfficeMenu. Ognuno di questi "padri" ha come figli dei Gruppi. I gruppi sia built-in che personali possono comprendere controlli di vario tipo. I puntini alludono ai diversi possibili attributi dei vari componenti. Indichiamo i principali, avvertendo che lo spazio non ci consente di trattarli tutti né tantomeno a fondo:

  • <button...>, pulsante di commando;
  • <toggleButton...>, pulsante premuto/non premuto; più toggleButton corrisponde a una serie di pulsanti di opzione, mutuamente esclusivi;
  • <checkBox...>, casella di selezione;
  • <editBox...>, casella di testo;
  • <gallery...>, griglia tipica del Ribbon;
  • <item...>, elemento di un controllo comboBox o dropDown;
  • <dialogBoxLauncher...>, "lanciatore" di una dialog box;
  • <separator ...> ¸linea verticale di separazione di controlli.

Prima di proseguire con (alcuni) controlli "contenitori", invitiamo a rivedere i due esempi finora forniti, in particolare per quel che riguarda il separatore, e liquidiamo il dialogBoxLauncher illustrandolo con una variante del primo esempio:

   <dialogBoxLauncher>

      <button id="Lanciatore" screentip="Lancia una UserForm..."

      onAction="LanciaUserForm" />

   </dialogBoxLauncher>

</group>

Il dialogBoxLauncher deve incastonare un button, auspicabilmente dotato di attributo screentip (suggeritore che ne indica lo scopo quando il mouse lo sfiora) fa apparire la tipica freccina in basso a destra di certi gruppi, che per l’appunto lancia una finestra di dialogo (o una qualsiasi macro). Nel nostro caso onAction attiva la medesima macro del Puls2.

Ma ecco solo alcuni controlli destinati a contenere altri controlli:

  • <comboBox...>, contiene più item;
  • <dropDown...>, contiene più item e/ button;
  • <box...>, riquadro che raggruppa ogni tipo di controllo;
  • <menu...> menu pop-up con ogni tipo di voce, controllo o sotto menu.

Il box è stato usato nel caso Revisioni. Quanto al combo Box si riveda la figura 1 e si esamini il seguente brano, senza commenti perché la sintassi XML ci pare eloquente.

  <comboBox id="MioCombo" tag="ScegliEl" label="Scegli il mese"

   onChange="ScegliMese">

     <item id="Elem1" label="Gennaio" />

     <item id="Elem2" label="Febbraio" />

     <item id="Elem3" label="Marzo" />

  </comboBox>

I limiti della nostra trattazione e la convinzione che i componenti base di RibbonX bastano e avanzano per la maggioranza dei casi pratici ci spingono a citare soltanto lo splitButton e il buttonGroup, complessi contenitori che permettono di imitare ogni aspetto della nuova interfaccia.

Gli attributi

Tanto per cambiare, sono numerosi, e il guaio è che non esiste allo stato nessuno strumento suggeritore (l’intellisense? è un sogno). Si può comunque avere un’indicazione di errori ex post. Tale funzionalità va attivata in ciascun applicativo Office (altrimenti il nostro sudato ribbon, se contiene il minimo errore non appare proprio!).

Le operazioni da compiere in Excel sono le seguenti: clic sul pulsante Office, poi scegliere le Opzioni di Excel; clic sulle Impostazioni avanzate, e spostarsi in basso fino alla sezione Generale; attivare infine la casellina "Mostra errori dell'interfaccia utente dei componenti aggiuntivi".

Gli attributi comuni a tutti i controlli, oltre ai predetti identificatori sono, per limitarsi ai principali: image (controlli nostrani) e imageMso (controlli standard), label, tag, screentip e supertip, enabled, visible, size e showLabel. I primi due corredano il controllo di un’immagine. Ripetiamo l’esempietto tipico già visto sopra:

<button id="Puls1" size="large" tag="OraAttuale"

       label="Segnala l’ora" image="OROLOG" onAction="SegnalaOra" />

 

Il capitolo immagini è divertente quanto... ridondante. Si possono usare immagini predefinite, tra cui quelle dei controlli built-in (i cui nomi si possono scaricare dal sito msdn), immagini (jpg o png, possibilmente) presenti sul proprio PC, aiutati in tal caso dal customUI Editor con il comando Insert icons di facile sperimentazione. Su possibilità più avanzate è giocoforza sorvolare.

Tornando a tag e label, la seconda è un’etichetta esplicativa del controllo mentre la prima è un attributo richiamabile in una procedura callback:

Sub MiaCallback(Ctrl As IRibbonControl)

   Msgbox "Sono il controllo " & Ctrl.Tag

End Sub

Va qui precisato che un oggetto IribbonControl gode anche della proprietà Id, l’identificatore del controllo, e null’altro (non esiste alcuna proprietà riconducibile alla label).

L’attributo size ha due soli valori: "large" e "normal" e, in realtà, non è supportato da tutti i controlli. In particolare, la larghezza di una ComboBox o di una casella editBox si regola con sizeString cui assegnare una stringa arbitraria della lunghezza voluta (12 caratteri, nell’esempio seguente):

<editBox id="MiaCas" sizeString="zzzzzzzzzzzz"... />

Le procedure callback

Sono routine associate ai vari controlli  e/o a loro attributi. Con qualche arbitrio ne distinguiamo due tipi:

  • onAction e onChange, la prima scatenata dal clic su un button, toggleButton, checkBox, dropDown o gallery, la seconda dal mutamento di un’editBox o un Combobox;
  • le routine con prefisso get, come getLabel, getPressed, getText e numerose altre.

La nostra distinzione mira a evitare equivoci circa il funzionamento a run-time. La più "tranquilla" al riguardo è onAction, ma già con onChange si presenta il problema delle firme (signature) della callback associata, che nel secondo come in altri casi è duplice.

Esempio, relativo a una comboBox supposta formata dalle voci (item): "Gennaio", "Febbraio" e "Marzo".

Sub OnChangeCallback(Ctrl As IRibbonControl, Testo As String)

   Select Case Testo

     Case "Gennaio"

      ...

     Case "Febbraio"

      ...

     Case "Marzo"

      ...

  End Select

End Sub

Il secondo argomento alias firma, contiene il testo dell’item scelto (il testo digitato dall’utente nel caso editBox). Volendone conservare traccia, si danno due modi: una variabile definita a livello modulo:

Dim ItemScelto As String

 

Sub OnChangeCallback(Ctrl As IRibbonControl, Testo As String)

  ItemScelto = Testo

End Sub

In Excel c’è l’alternativa della registrazione in una cella, diciamo Range("ItemScelto") = Testo. Nell’uno o nell’altro caso il dato della variabile a livello modulo può essere usato da altre, normali Sub.

 Venendo a routine come getLabel, getImage e altre, esse espongono una seconda firma RetVal di tipo Variant (anziché String, badare bene).

NOTA. Nelle callback come pure in quelle di evento (es. Change) si può assegnare agli argomenti qualsiasi nome, a patto di rispettarne ordine e tipo. L’abbiamo fatto con Controllo, Testo e RetVal al posto dei canonici Control, Text e ReturnValue. Si provi con Bersaglio in luogo del Target suggerito in Change: il risultato è lo stesso.

Ora la situazione è più limitante, in quanto tali Sub servono all’acquisizione dinamica di un’etichetta, un’immagine ecc., che però avviene solo all’avvio del documento.

Premesso che l’attributo getLabel è goduto anche dai gruppi, ecco un caso tipico. Si abbia un add-in, o anche solo un modello, il cui customUI comprende un gruppo "Azienda" da etichettare col nome della ditta, supposta scritta nella cella A1. Ed ecco una riga XML seguita dalla sua brava callback:

<group id="Azienda" getLabel="PrendiNomeAz">

Sub PrendiNomeAz(Ctrl As IRibbonControl, RetVal As Variant)

  RetVal = Range("A1").Value

End Sub

Una variante banale potrebbe poi essere l’istruzione RetVal = InputBox (“Nome della ditta").

NOTA. Una curiosità. Una sub come la precedente potrebbe surrogare l’evento Open? Certo, basta inserirvi qualsiasi istruzione anche non pertinente il Ribbon. E non c’è conflitto con Open, perché questa parte comunque per prima. Comunque meglio evitare, per la chiarezza dei vari ruoli.

Dimenticavamo una segnalazione di firme (l’ultima), relativa alla procedura onAction dei controlli checkBox e  toggleButton, che presenta il booleano Pressed come secondo argomento, di cui tutti dovrebbero capire l’uso.

Uno schema generale

Il RibbonX si compone di varie parti, che si susseguono secondo lo schema seguente.

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">

  <commands>

    <command ... />

  </commands>

  <ribbon ... >

    <officeMenu>

      controlli del menu Office

    </officeMenu>

    <qat>

      <sharedControls>

        controlli condivisi

      </sharedControls>

      <documentControls>

         Controolli di documento

       </documentControls>

    </qat> <!—Quick access toolbar-->

    <tabs>

      <tab ... >

        <group ... >

           Controlli vari

        </group> </tab>

    </tabs>

    <contextualTabs>

      <tabSet idMso=”TabSetChartTools”>

        <tab ... >

          <group ... >

             controlli vari

          </group>

        </tab>

      </tabSet>

    </contextualTabs>

  </ribbon>

</customUI>

 

Lo riportiamo quasi solo per dare un’idea della gran varietà del fluent Ribbon. In particolare, la sezione dei Commands  serve a ridefinire le azioni associate a comandi standard e la qat a inserire controlli nella Quick Access Toolbar.

Uno schema XML ibrido per uso “dittatoriale”

Lo schema che stiamo per vedere utilizza l’opzione startFromScratch=”true” e la sezione di ridefinizione dei comandi, relativamente a quelli del menu Office, in modo da soddisfare varie esigenze:

  • mantenere la tab Home consentendo all’utente le formattazioni;
  • eliminare il comando Nuovo (cattiveria per meri fini didattici);
  • resuscitare invece il pulsante Stampa, ma associandolo a una macro particolare;
  • in conseguenza, disabilitare e occultare i pulsanti sottostanti al menu Stampa ossia: Stampa (pulsante, da non confondere col suo omonimo padre), Stampa immediata e Anteprima di stampa.

Lo schema qui sotto è ricco di commenti che ne facilitano la comprensione.

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">

  <commands>

   <command idMso="FileSave" />

   <!—Disabilita il comando Nuovo-->

   <command idMso="FileNew" enabled="false" />

   <!—Associa il comando Stampa alla macro StampaCondiz-->

   <command idMso="FilePrint" onAction="StampaCondiz" />

  </commands>

  <ribbon startFromScratch="true">

    <officeMenu>

     <!—Abilita e mostra il menu Print-->

     <menu idMso="FilePrintMenu" enabled="true" visible ="true">

      <!—Disabilita i 3 pulsanti sotto il menu Print-->

      <button idMso="FilePrintPreview" enabled="false" visible="false" />

      <button idMso="FilePrint" enabled="false" visible="false" />

      <button idMso="FilePrintQuick" enabled="false" visible="false" />

     </menu>

    </officeMenu>

    <tabs>

     <!—visualizza la tab Home-->

     <tab idMso="TabHome" visible="true" />

     <!—Inserisci una tab personale prima della tab Home-->

     <tab id="PersonTab" label="Mia bella Tab" insertBeforeMso="TabHome">

       <group id="GruppoEsempio" label="Macro varie">

        <button id="Button1" size="large" tag="AggTotali"

         label="Aggiungi totali" onAction="AggTot"/>

        <button id="Button2" size="large" tag="PiccoloTest"

         label="PiccoloTest" onAction=" PiccoloTest"/>

       </group>

     </tab>

    </tabs>

  </ribbon>

</customUI>

 

Per comprendere la cosa esaminare il file ExcelRibbonControls.xls, dal quale si evince che FilePrintMenu è un gruppo che fa parte della tab OfficeMenu e, insieme, è – si badi bene! - un menu, comprendente i button FilePrint, FilePrintQuick (stampa immediata) e FilePrintPreview (anteprima). Si dovrebbe così comprendere il significato delle tag incastonate tra <menu …> e </menu>, nonché il fatto che la prima, relativa a FilePrintMenu lo abilita e visualizza, a onta della direttiva dittatoriale startFromScratch=”True” che lo vorrebbe defunto. Quanto ai button compresi nel menu Office gli specifici tag li tolgono di mezzo.

Quanto ai command  incapsulati tra commands e /commands vi ritroviamo pulsanti standard (built-in) come quelli facenti parte del menu Office. Risulta così possibile ridefinirne la funzione mediante macro onAction associate che vanno a sostituire e prevaricare (inglese "override") la funzione normale.

Venendo a possibili routine associate, quella che prevarica sul normale funzionamento del comando Stampa potrebbe essere la seguente che impone che la stampa avvenga solo al mattino:

Sub StampaCondiz(ctrl As IRibbonControl, cancelDefault As boolean)

  Dim Msg As String

  Msg = "Buogiorno! Puoi Stampare" & vbLf & "solo al mattino! "

  If Time > 0.5 Then

    MsgBox Msg & " Spiacente..."

  Else

    MsgBox Msg & " Contento?"

    ThisWorkbook.PrintPreview

  End If

  cancelDefault = False

End Sub

Si noti l’argomento cancelDefault, che mantiene l’override.

Quest’altra Sub, viene invece scatenata dal primo pulsante della Mia bella tab e aggiunge la funzione =SOMMA() in una zona pre-denominata "Totali" posta in fondo a un elenco con intestazioni:

Sub AggiungiTot(ByVal ctrl As IRibbonControl)

  Dim RifCol As String

  With Range("Totali")(0, 1)

    RifCol = Range(.Cells(1), .End(xlUp)(2, 1)).Address(False, False)

  End With

  Range("Totali").Formula = "=SUM(" & RifCol & ")"

End Sub

Quanto alla macro associate al secondo pulsante della tab ognuno può crearsela a suo gusto. Ribadiamo infatti che a patto di mantenere i nomi delle callback il codice relativo può essere sempre modificato senza ritocchi al Ribbon custom.

NOTA. I modelli più chiusi per l’utente finale non possono comunque impedire che egli ricorra a short cut di tastiera, per Salvare, stampare e quant’altro. Accadeva lo stesso con le Commandbar.

Altro caso di Office menu personalizzato

Lo schema XML, relativo alla sola sezione del menu Office è il seguente:

<officeMenu>

  <!--I pulsanti di officeMenu NON supportano l’attributo size-->

  <button id="OffButton1" label="PulsOffice 1"

   imageMso="HappyFace" onAction="MacPulsOff1" />

  <button id="OffButton2" label="PulsOffice 2"

   imageMso="HappyFace"  onAction="MacPulsOff2" />

  <menu id="MioOfficemenu" label="Sotto-menu del menu Office">

    <button id="mioMenuOffbtn1" label="Mio menu Office puls. 1"

     onAction="MacPulsmioMenu1" />

    <button id="mioMenuOffbtn2" label="Mio menu Office puls. 2"

     onAction="MacPulsmioMenu2" />

   </menu>

</officeMenu>

 

Per brevità si riporta soltanto il risultato nella figura 6, confidando nella sua eloquenza. E le callback sono lasciate per esercizio.

http://www.giannigiaccaglini.it/download/FigRibbon-06.jpg

Figura 6

Aggiornamento del Ribbon a run-time

Chi ha ben seguito la nostra trattazione avrà compreso che la tecnologia RibbonX ha diverse limitazioni (almeno per i palati più esigenti), che a nostro avviso si collegano al fatto che non si tratta di un vero modello a oggetti. In particolare non sembra possibile accedere ai vari controlli per ottenerne o, peggio ancora, modificarne programmaticamente proprietà o valori. Abbiamo intravisto una scappatoia nell’uso di variabili a livello modulo aggiornate da talune (non tutte) routine Callback come onChange o getText.

Un’altra possibilità avanzata, anche se un poco contorna è data dalla callback onLoad relativa all’intero ribbon, che in una certa misura permette di ridefinirlo a run-time e, con esso, gestirne taluni componenti.

Un esempio specifico è la scelta migliore. La figura 7 mostra un modello dotato di una tab personale comprendente una casella di testo, di cui si vuole aggiornare il contenuto tramite macro, l’appena annunciata callback onLoad.

http://www.giannigiaccaglini.it/download/FigRibbon-07.jpg

Figura 7

L’XML relativo è riportato qui sotto.

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"

 OnLoad="RibbonCarica">

  <ribbon startFromScratch="true">

    <tabs>

      <tab id="TabPers" label="MiaTab">

        <group id="GruppoPers" label="Mio gruppo">

          <editBox id="MiaCas" label="Scrivi:"

           sizeString="precipitevolissimevolmente" getText="Prenditesto" />

          <separator id="Lineadivisoria" />

          <button id="MioPuls" label="Ruota testo" size="large"

           onAction="RuotaTesto" imageMso="HappyFace" />

        </group>

      </tab>

    </tabs>

  </ribbon>

</customUI>

 

Ed ecco la fatidica callback associata all’attributo onLoad del nostro ribbon e quelle associate alla editBox e al button della tab personale.

Dim RegRibbon As IRibbonUI

 

Sub RibbonCarica(ribbon As IRibbonUI)

  Set RegRibbon = ribbon

End Sub

 

Sub PrendiTesto(Ctrl As IRibbonControl, RetVal)

  RetVal = Range("CellaOrigine")

End Sub

 

Sub RuotaTesto(Ctrl As IRibbonControl)

  'Callback del pulsante MioPuls

  Dim N As Integer, Testo As String

  With Range("CellaOrigine")

    N = .Characters.Count

    Testo = .Text

    .Value = Right(Testo, 1) & Left(Testo, N - 1)

  End With

  RegRibbon.InvalidateControl ("MiaCas")

End Sub

 

La sub RibbonCarica imposta (Set) il nostro ribbon nella variabile definita a livello modulo RegRibbon di tipo IRibbonUI che inequivocabilmente si attaglia a un oggetto ribbon. Anche la Sub PrendiTesto dell’editBox non ha misteri: preleva il valore della cella pre-denominata "CellaOrigine" (B4, in figura). Nei casi normali tale acquisizione si avrebbe una tantum, al caricamento del nostro ribbon, ma qui interviene la classe IribbonUI cui appartiene RegRibbon. Essa espone due soli metodi:

-       Invalidate e

-       InvalidateControl(Idcontrollo)

Il primo "invalida" l’intero nastro customizzato, in pratica inizializzandolo nuovamente, il secondo metodo compie lo stesso mestiere limitatamente al controllo specificato, tramite il suo Id, "MiaCas" nella fattispecie. Ciò consente alla Sub RuotaTesto connessa al button "MioPuls" di modificare la "CellaOrigine", in questo caso facendo ruotare ciclicamente di un carattere il suo testo, che subito viene acquisito dalla editBox tramite la sua "risvegliata" callback PrendiTesto. Lo stesso avviene con una routine esterna del tutto simile, connessa al pulsante classico del foglio Ruota un carattere e in entrambi i casi ci si può divertire con clic ripetuti che via via girano in circolo la scritta sia nella cella che nell’editBox.

Tutto bene? Non al cento per cento. Una routine connessa al secondo pulsante di figura che invoca la Sub Ruota un carattere per un numero di volte pari alla lunghezza del testo, a sorpresa agisce soltanto nella cella, mentre l’editBox resta immutato. Il motivo? Appare misterioso, comunque non c’è che da prendere atto di questa oggettiva limitazione.

Affidiamo altri dettagli e gli aspetti più avanzati a quanti volessero approfondire il romanzo di un giovane… ricco. Fin troppo, per cui la nostra trattazione termina qui, convinti che basti, anzi travalichi le normali necessità.

posted @ lunedì 1 gennaio 0001 00:00 | Feedback (0) |

Powered by:
Powered By Subtext Powered By ASP.NET