Dodawanie własnych przycisków na wstążce w programie MS Project jest dużo trudniejsze niż w przypadku Worda, Excela czy PowerPointa.
Nie będę tutaj od podstaw opisywał jak się tworzy własne przyciski na wstążce, tylko wskażę różnice. Dlatego jeśli nie miałeś do czynienia z wstążką zapoznaj się z notką Dodawanie przycisków do własnych funkcji na wstążce.
Różnica nr #1: Niemożność skorzystania z programu Office RibbonX Editor lub Custom UI Editor form Microsoft Office.
Pliki dla nowego pakietu Office to tak naprawdę archiwa ZIP zawierające kilka(naście) plików XML. Dodanie własnych przycisków na wstążce polegało tak naprawdę na wstrzyknięciu dodatkowego pliku XML (oraz ewentualnie plików z własnymi ikonami) do archiwum zawierającego opis wstążki (i dodanie odpowiedniej referencji do tego pliku). W przypadku programu MS Project pliki tworzone przez ten program nie są archiwami ZIP tylko plikami binarnymi typu CFBF (Compound File Binary Format) czyli są to pliki takiego typu jak tworzone przez programy Word czy Excel sprzed wersji 2007.
Dlatego też nie możemy do takiego pliku „dokleić” pliku XML zawierającego opis wstążki. Dlatego też należy wygenerować kod XML (przechowywać wygląd wstążki w kodzie w zmiennej typu string albo odczytać z zewnętrznego pliku) i wywołać metodę:
ActiveProject.SetCustomUI (xml)
Różnica nr #2: Funkcje callback dotyczące wstążki muszą być w module ThisProject
Nie wiem z czego to wynika. Pisząc aplikacje dla Excela, Worda czy Accessa (w przypadku Accessa też niektóre rzeczy są nieco inne niż w przypadku tria: Word, Excel & PowerPoint) zawsze wszystkie funkcje Callback wywoływane przez wstążkę umieszczałem w osobnym module (np. modRibbon). W przypadku MS Project kod ładujący wstążkę może być w dowolnym module, ale funkcje Callback muszą być w module This Project. Jeśli tego nie ma to po kliknięciu w przycisk na wstążce wyskakiwał błąd Automation error. Wystąpił wyjątek.
Różnica nr #3: Funkcje Callback są bezargumentowe
W przypadku Worda, Excela, PowerPointa czy Accessa funkcja Callback przyjmowała argument typu IRibbonControl. Dzięki temu mogłem w funkcji Callback utworzyć prostą konstrukcję Select Case i po ID klikniętego przycisku wywoływać odpowiednie funkcje. Jeśli funkcja Callback będzie przyjmowała jakikolwiek argument (nawet typu Variant) pojawi się dobrze już znany błąd Automation Error. O taki kod używałem np. w Excelu:
‘Ta funkcja callback nie działa w MS Project
Sub ButtonOnAction(control As IRibbonControl)
Select Case control.ID
Case "Pierwszy"
MsgBox "Kliknąłeś w PIERWSZY przycisk", vbInformation
Case "Drugi"
MsgBox "Kliknąłeś w DRUGI przycisk", vbInformation
Case "Trzeci"
MsgBox "Kliknąłeś w TRZECI przycisk", vbInformation
Case Else
MsgBox "Dodaj kod obsługujący przycisk o ID: " + control.ID, vbExclamation
End Select
End Sub
Tutaj funkcje callback są bezargumentowe więc dla każdego przycisku muszą tworzyć osobną funkcję Callback.
Różnica nr #4: nie można dodawać własnych ikon
Ponieważ nie można wstrzyknąć do archiwum własnych ikon to należy korzystać z biblioteki Mso. Oto zestaw przykładowych ikon, jakie mamy do dyspozycji. Pewnie by się dało jakoś ładować swoje ikony z zewnętrznych plików, ale brakło mi cierpliwości na dogłębny research.
Przykładowa wstążka
Oto prosty przykład dodający nową kartę z trzema przyciskami.
Private Sub Project_Open(ByVal pj As Project)
Call LoadRibbon
End Sub
Sub rPierwszy()
MsgBox "Hello world!", vbInformation
End Sub
Sub rCalc()
Shell "calc.exe"
End Sub
Sub RemoveCustomUI()
Dim xml As String
If MsgBox("Czy chcesz usunac wstazke", vbInformation Or vbYesNo) = vbYes Then
xml = "<mso:customUI xmlns:mso=""http://schemas.microsoft.com/office/2009/07/customui"">"
xml = xml + "<mso:ribbon></mso:ribbon></mso:customUI>"
ActiveProject.SetCustomUI (xml)
End If
End Sub
Public Sub LoadRibbon()
Dim xml As String
xml = ""
xml = xml + "<customUI xmlns=""http://schemas.microsoft.com/office/2009/07/customui"">"
xml = xml + "<ribbon>"
xml = xml + "<tabs>"
xml = xml + "<tab id=""tabTestowaKarta"" label=""Moje przyciski"">"
xml = xml + "<group id=""grpPierwszaGrupa"" label=""Pierwsza grupa"">"
xml = xml + "<button id=""Pierwszy"" label=""Testowy przycisk"" imageMso=""HappyFace"" onAction=""rPierwszy""/>"
xml = xml + "<button id=""Kalkulator"" label=""Kalkulator"" imageMso=""Calculator"" onAction=""rCalc""/>"
xml = xml + "<button id=""Usun"" label=""Usun wstazke"" imageMso=""Delete"" onAction=""RemoveCustomUI""/>"
xml = xml + "</group>"
xml = xml + "</tab>"
xml = xml + "</tabs>"
xml = xml + "</ribbon>"
xml = xml + "</customUI>"
'Debug.Print xml
ActiveProject.SetCustomUI (xml)
End Sub