Я разработал шаблон, упрощающий процедуру вставки в документ изображений из указанной папки. При загрузке шаблона появляется дополнительная группа на вкладке «Вставка»

Возможности:
- Выбор папки, из которой нужно часто вставлять изображения.
- Просмотр эскизов изображений в галерее.
- Обрабатываются (пока) только изображения форматов: "png", "jpg", "jpeg", "bmp", "gif".
- Всплывающая подсказка к каждому изображению содержит имя файла, размеры изображения и разрешение по горизонтали и по вертикали.
- Вставка изображений в заданном режиме: в текст или с обтеканием.
- Автоматическая вставка названия к изображению с нумерацией или без.
- Автоматическая вставка имени файла в название к изображению.
В раскрытом виде галерея может выглядеть так:

Галерея имеет фиксированное количество столбцов (5), количество строк зависит от количества изображений в выбранной папке.
Скачать шаблон можно
отсюда
С точки зрения работы с лентой, этот шаблон интересен несколькими моментами.
Во-первых, в нём реализована загрузка на ленту не только изображений bmp, но и других форматов.
Это стало возможным благодаря использованию функций GDI+. За основу взяты примеры для книги
RibbonX: Customizing the Office 2007 Ribbon, которые можно скачать
отсюда
Дело в том, что для отображения на ленте Office понимает только один формат изображения IPictureDisp. Получить этот формат изображения из файла можно функцией
LoadPicture. Но она может загружать только изображения bmp. В шаблоне используется похожая функция
LoadImage, описанная в модуле GDIPlusAPI. Код модуля выглядит так:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
Attribute VB_Name = "GDIPlusAPI"
Option Private Module
Option Explicit
Public Declare Function GdiplusStartup Lib "gdiplus" (token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As GpStatus
Public Declare Function GdipCreateBitmapFromFile Lib "gdiplus" (ByVal filename As Long, bitmap As Long) As GpStatus
Public Declare Function GdipCreateHBITMAPFromBitmap Lib "gdiplus" (ByVal bitmap As Long, hbmReturn As Long, ByVal background As Long) As GpStatus
Public Declare Function GdipDisposeImage Lib "gdiplus" (ByVal image As Long) As GpStatus
Public Declare Function GdiplusShutdown Lib "gdiplus" (ByVal token As Long) As Long
Public Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PicDesc As PICTDESC, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
Public Declare Function GdipGetImageDimension Lib "gdiplus" (ByVal image As Long, Width As Single, Height As Single) As GpStatus
Public Declare Function GdipGetImageWidth Lib "gdiplus" (ByVal image As Long, Width As Long) As GpStatus
Public Declare Function GdipGetImageHeight Lib "gdiplus" (ByVal image As Long, Height As Long) As GpStatus
Public Declare Function GdipGetImageHorizontalResolution Lib "gdiplus" (ByVal image As Long, resolution As Single) As GpStatus
Public Declare Function GdipGetImageVerticalResolution Lib "gdiplus" (ByVal image As Long, resolution As Single) As GpStatus
Public Declare Function GdipGetImageThumbnail Lib "gdiplus" (ByVal image As Long, ByVal thumbWidth As Long, ByVal thumbHeight As Long, thumbImage As Long, Optional ByVal callback As Long = 0, Optional ByVal callbackData As Long = 0) As GpStatus
Public Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal filename As String, image As Long) As GpStatus
Public Enum GpStatus
OK = 0
GenericError = 1
InvalidParameter = 2
OutOfMemory = 3
ObjectBusy = 4
InsufficientBuffer = 5
NotImplemented = 6
Win32Error = 7
WrongState = 8
Aborted = 9
FileNotFound = 10
ValueOverflow = 11
AccessDenied = 12
UnknownImageFormat = 13
FontFamilyNotFound = 14
FontStyleNotFound = 15
NotTrueTypeFont = 16
UnsupportedGdiplusVersion = 17
GdiplusNotInitialized = 18
PropertyNotFound = 19
PropertyNotSupported = 20
End Enum
Public Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Public Type PICTDESC
Size As Long
Type As Long
hPic As Long
hPal As Long
End Type
Public Type GdiplusStartupInput
GdiplusVersion As Long
DebugEventCallback As Long
SuppressBackgroundThread As Long
SuppressExternalCodecs As Long
End Type
Public Function LoadImage(ByVal strFName As String) As IPicture
Dim uGdiInput As GdiplusStartupInput
Dim hGdiPlus As Long
Dim hGdiImage As Long
Dim hBitmap As Long
Dim imgThumb As Long
Dim imgHeight As Single, imgWidth As Single
uGdiInput.GdiplusVersion = 1
'Запускаем GDI+
If GdiplusStartup(hGdiPlus, uGdiInput) = OK Then
'Создаём изображение в памяти
If GdipCreateBitmapFromFile(StrPtr(strFName), hGdiImage) = OK Then
'Получаем размеры изображения
Call GdipGetImageDimension(hGdiImage, imgWidth, imgHeight)
'Делаем из изображения уменьшенное
Call GdipGetImageThumbnail(hGdiImage, ItemWidth, ItemWidth * imgHeight / imgWidth, imgThumb)
'Указатель на изображение
Call GdipCreateHBITMAPFromBitmap(imgThumb, hBitmap, 0)
'Конвертируем изображение в IPicture
Set LoadImage = ConvertToIPicture(hBitmap)
GdipDisposeImage hGdiImage
End If
GdiplusShutdown hGdiPlus
Else
MsgBox "Ошибка при загрузке GDI+!", vbCritical
End If
End Function
Public Function ConvertToIPicture(ByVal hPic As Long) As IPicture
Dim uPicInfo As PICTDESC
Dim IID_IDispatch As GUID
Dim IPic As IPicture
Const PICTYPE_BITMAP = 1
With IID_IDispatch
.Data1 = &H7BF80980
.Data2 = &HBF32
.Data3 = &H101A
.Data4(0) = &H8B
.Data4(1) = &HBB
.Data4(2) = &H0
.Data4(3) = &HAA
.Data4(4) = &H0
.Data4(5) = &H30
.Data4(6) = &HC
.Data4(7) = &HAB
End With
With uPicInfo
.Size = Len(uPicInfo)
.Type = PICTYPE_BITMAP
.hPic = hPic
.hPal = 0
End With
OleCreatePictureIndirect uPicInfo, IID_IDispatch, True, IPic
Set ConvertToIPicture = IPic
End Function |
Загрузка изображений происходит в модуле RibbonCallbacks в процедуре
getItemImage, которая, в свою очередь, определена в XML-схеме для галереи.
68
69
70
71
72
| 'galleryImagesFromFolder (компонент: gallery, атрибут: getItemImage)
Sub getItemImage(control As IRibbonControl, index As Integer, ByRef image)
If ImagesCount = 0 Then Exit Sub
Set image = LoadImage(arImagePaths(index))
End Sub |
В этой процедуре arImagePaths — массив с путями к файлам изображений, index — номер элемента в галерее.
Во-вторых, на примере данного шаблона можно понять как работает механизм изменения состояния одних элементов ленты в зависимости от состояния других. Начнём с XML-схемы трёх флажков, расположенных в правой части группы, которые определяют правила вставки названия к вставляемому изображению.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| <!-- Разделитель группы -->
<separator id="sep1" />
<checkBox id="chbInsertImageWithCaption"
label="Вставлять название"
supertip="Установите этот флажок, чтобы автоматически вставлять подпись к вставляемому рисунку."
onAction="chb_onAction" />
<checkBox id="chbUsePathInCaption"
label="Имя файла в названии"
supertip="Установите этот флажок, чтобы подпись к вставляемому рисунку содержала имя файла рисунка."
getEnabled="getEnabled"
onAction="chb_onAction" />
<checkBox id="chbNumberImage"
label="Нумеровать изображение"
supertip="Установите этот флажок, чтобы автоматически нумеровать вставляемое изображение."
getPressed="chb_getPressed"
getEnabled="getEnabled"
onAction="chb_onAction" /> |
У всех трёх флажков определён один общий динамический атрибут
onAction, определяющий процедуру, которая выполняется при клике на соответствующем флажке. Двум последним флажкам задан атрибут
getEnabled, определяющий процедуру, изменяющую активность этих флажков. Активность этих флажков меняется в зависимости от состояния первого флажка.
И, наконец, у третьего флажка задан атрибут
getPressed, определяющий процедуру, изменяющую состояние флажка.
Теперь посмотрим, как это реализовано в VBA:
29 'galleryImagesFromFolder (компонент: gallery, атрибут: getEnabled)
30 'chbUsePathInCaption (компонент: checkBox, атрибут: getEnabled)
31 'chbUsePathInCaption (компонент: checkBox, атрибут: onAction)
32 'chbNumberImage (компонент: checkBox, атрибут: getEnabled)
33 Sub getEnabled(control As IRibbonControl, ByRef enabled)
34 Select Case control.ID
35 Case "chbUsePathInCaption"
36 enabled = chbInsertImageWithCaptionChecked
37 Case "chbNumberImage"
38 enabled = chbInsertImageWithCaptionChecked
39 Case Else
40 enabled = CBool(ImagesCount)
41 End Select
42 End Sub
Эта процедура при помощи селективного оператора определяет состояние какого элемента ленты нужно установить и присваивает ему значение соответствующей глобальной переменной.
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
| 'chbInsertImageWithCaption (компонент: checkBox, атрибут: onAction)
'chbUsePathInCaption (компонент: checkBox, атрибут: onAction)
'chbNumberImage (компонент: checkBox, атрибут: getPressed)
Sub chb_onAction(control As IRibbonControl, pressed As Boolean)
Select Case control.ID
Case "chbUsePathInCaption"
chbUsePathInCaptionChecked = pressed
Case "chbNumberImage"
chbNumberImageChecked = pressed
Case "chbInsertImageWithCaption"
chbInsertImageWithCaptionChecked = pressed
If Not myRibbon Is Nothing Then
myRibbon.InvalidateControl "chbUsePathInCaption"
myRibbon.InvalidateControl "chbNumberImage"
Else
MsgBox "Связь с пользовательским интерфейсом customUI утеряна. Попробуйте переоткрыть документ, или переподключить шаблон", vbInformation + vbOKOnly
End If
End Select
End Sub |
В этой процедуре, также с помощью селективного оператора, определяется флажок, на котором щёлкнул пользователь и состояние этого флажка, переданное параметром
pressed, записывается в соответствующую глобальную переменную. Кроме того, если сработал первый флажок, то обновляется состояние остальных двух.
140
141
142
143
| 'chbNumberImage (компонент: checkBox, атрибут: getPressed)
Sub chb_getPressed(control As IRibbonControl, ByRef returnValue)
returnValue = chbNumberImageChecked
End Sub |
Здесь всё просто: состояние флажка, на которое ссылается переменная
returnedValue, устанавливается в соответствии со значением глобальной переменной. Здесь не используется селективный оператор, поскольку эта процедура вызывается только для одного флажка.
Замечания и пожелания приветствуются.