Дата публикации статьи: 12.01.2008 10:41

Меню на VBA. Готовим профессионально

Автор: Виталий Шаповал
[Скачать пример к статье] [Комментировать в форуме]

Введение

Любая прикладная программа, ориентированная на широкий круг пользователей, должна иметь простые и удобные средства для взаимодействия с ними. Данные средства, в совокупности именуемые пользовательским интерфейсом, предназначены для подачи определенной команды работающей программе, выбора необходимого режима работы или осуществления какого-либо стандартного действия. В графическом интерфейсе Windows для передачи команд приложению используются меню и панели управления.

При разработке интерфейса программы основное проблемой является юзабилити, т.е. ориентированность на максимальное психологическое и эстетическое удобство для пользователя.

VBA, в отличие от своего "старшего" собрата, не имеет собственного редактора меню, однако он может использовать стандартные объекты MS Office. Конечно, в офисных разработках вполне можно обойтись и без меню. Однако меню придает программе профессиональный вид, позволяя избежать использования множества командных кнопок, натыканных на листы и/или формы, позволяя достичь того самого юзабилити.

Теоретическое отступление

В объектной модели MS Office все меню и панели инструментов представлены объектами типа CommandBar. Каждая панель инструментов, строка меню, каждое меню в строке меню и даже подменю, заключающееся в пункте меню - это объекты типа CommandBar. Все объекты CommandBar любого приложения Office объединены в семейство CommandBars данного приложения (рис.1).

Иерархическая схема объекта CommandBar

Рис. 1 - Иерархическая схема объекта CommandBar

Элементы управления, находящиеся на панели инструментов, представлены объектами типа CommanBarControl, которые объединены в семейство CommandBarControls, где CommandBarButton - кнопка или элемент меню, вызывающий выполнение команды; CommandBarComboBox - сложно организованные меню, такие как список, поле ввода или поле со списком; CommandBarPopUp - непосредственно меню либо вложенное меню.

Таким образом, меню - это набор пунктов, каждый из которых соответствует той или иной команде или действию, а панели инструментов представляют собой обычные кнопки с пиктограммами, объединенные в единое целое и сгруппированные по функциональному назначению [1, 2].

Зачем все это?

Практически каждый пользователь MS Office знает, что с помощью диалогового окна Сервис - Настройка можно создавать новые панели инструментов и дополнительные пункты главного меню для всех приложений Office, а в Access - еще и новую строку меню [3]. Однако данные настройки действую глобально для всего приложения MS Office.

Программирование же позволяет создавать для разрабатываемых прикладных приложений (на базе Excel, Word и т.д.) собственный интерфейс, например, исключить из меню и панелей инструментов родительского приложения кнопки и команды, не используемые в пользовательском приложении и добавить новые необходимые средства. Причем изменения в стандартный интерфейс приложений Офис будут внесены только на время работы дочернего приложения, и по его закрытии все вернется на круги своя.

Пример реализации

В принципе, процесс создания собственной панели инструментов или даже собственного меню достаточно подробно рассмотрен в [3, 4]. В данной статье остановимся лишь на специфической задаче, а именно - добавления пользовательского пункта меню в основное меню Excel, подобно тому, как это делают Trados, Adobe Acrobat, Promt и т.п. Однако наше меню должно появляться только при запуске пользовательской программы и благополучно удаляться по завершении работы, никак не влияя на работоспособность исходного приложения.

Ниже приведен код с подробными комментариями, содержащими всю полноту информации. Отмечу только, что основной код находится в программном модуле VBA (Module), а процедуры, выполняемые при открытии и закрытии - в модуле "ЭтаКнига" (ThisWorkbook). Для автоматического запуска при том или ином событии макрос должен иметь одно из следующих имен:

  • AutoExec - запускается при старте приложения или загрузке глобального шаблона.
  • AutoNew - запускается при создании нового документа.
  • AutoOpen - запускается при открытии документа.
  • AutoClose - запускается при закрытии документ.
  • AutoExit - запускается при выходе из приложения или при закрытии глобального шаблона.
  • Кроме того, с помощью логического флага производится проверка на наличие уже существующего пункта меню с таким названием. Это сделано во избежание дублирования меню вследствие повторного запуска программы.

    Листинг кода из Module
    '
    ' Создание выпадающего меню приложения в главном меню Excel
    '
    ' Запрет использования недекларированных переменных
    Option Explicit
                            
    ' Объявляем наши переменные
    Dim WorksheetsMenuBar As CommandBar     ' Основная панель Excel
    Dim cmdBarCtrl As CommandBarControl     ' Пункт основного меню Excel
    '
    ' Функция формирования меню при открытии файла
    '
    Private Sub Auto_open()
    
    Dim MyNewMenu As CommandBarPopup       	' Выпадающее пользовательское меню
    Dim cmdSubBarCtrl As CommandBarControl 	' Пункт выпадающего меню
    Dim MenuExists As Boolean             		' Флаг существования пользовательского меню
    Dim SubMenu As CommandBarPopup      	' Выпадающее подменю
    Dim SubCmdCtrl As CommandBarControl   	' Пункт выпадающего подменю
    '
    ' Проверка существования меню с таким названием
    '
    Set WorksheetsMenuBar = CommandBars.ActiveMenuBar
        MenuExists = False
        For Each cmdBarCtrl In WorksheetsMenuBar.Controls
            If cmdBarCtrl.Caption = "&Новое меню" Then
            MenuExists = True
        Exit For
            End If
        Next cmdBarCtrl
    
    If Not MenuExists Then          ' Если меню не существует, то
    '
    ' Формирование нового меню
    '
    Set MyNewMenu = WorksheetsMenuBar.Controls.Add(Type:=msoControlPopup, Temporary:=True)
        MyNewMenu.Caption = "&Новое меню"
    '
    ' Формирование пункты нового меню
    '  
    Set cmdSubBarCtrl = MyNewMenu.Controls.Add(Type:=msoControlButton)
        With cmdSubBarCtrl
            .BeginGroup = True
            .FaceId = 926
            .Caption = "&О программе"
            .OnAction = "About"
       End With
    '
    ' Добавление выпадающего подменю
    '
    Set SubMenu = MyNewMenu.Controls.Add(Type:=msoControlPopup, Temporary:=True, Before:=1)
        SubMenu.Caption = "Подменю"
    '
    ' Пункты выпадающего подменю
    '
    Set SubCmdCtrl = SubMenu.Controls.Add(Type:=msoControlButton, ID:=1)
        With SubCmdCtrl
            .FaceId = 71
            .Caption = "&Подпункт 1"
            .OnAction = "SubMacro1"
        End With
    Set SubCmdCtrl = SubMenu.Controls.Add(Type:=msoControlButton, ID:=2)
        With SubCmdCtrl
            .BeginGroup = True
            .FaceId = 72
            .Caption = "&Подпункт 2"
            .OnAction = "SubMacro2"
        End With
    End If
    
    End Sub
    '
    ' Функция удаления пользовательского меню 
    ' и восстановления исходного меню при закрытии файла
    '
    Private Sub Auto_close()
    
    On Error Resume Next
    Set WorksheetsMenuBar = CommandBars.ActiveMenuBar
        For Each cmdBarCtrl In WorksheetsMenuBar.Controls
            If cmdBarCtrl.Caption = "&Новое меню" Then
            WorksheetsMenuBar.Reset
        Exit For
            End If
        Next cmdBarCtrl
    
    End Sub
    '
    ' Собственно, обработка пунктов нового меню
    ' Сейчас здесь прописаны заглушки, вместо которых
    ' подставляются ваши макросы
    '
    Private Sub About()  ' Пункт основного меню
        MsgBox "Выполнен пункт меню", vbInformation, "О программе"
    End Sub
    
    Private Sub SubMacro1()  ' Подпункт 1 выпадающего меню
        MsgBox "Запущен макрос из подпункта 1", vbInformation, "Выполнен"
    End Sub
    
    Private Sub SubMacro2()   ' Подпункт 2 выпадающего меню
        MsgBox "Запущен макрос из подпункта 2", vbInformation, "Выполнен"
    End Sub
    Листинг кода из "Эта книга"
    Option Explicit
    
    Private Sub Workbook_Open()
        With Application
            .Caption = "Создаем свое меню"
        End With
    	' Собственно, формируем меню при открытии
    	ActiveWorkbook.RunAutoMacros xlAutoOpen
    End Sub
    
    Private Sub Workbook_BeforeClose(Cancel As Boolean)
        With Application
           .Caption = Empty
        End With
    	' Возвращаем все, как было до нас
          ActiveWorkbook.RunAutoMacros xlAutoClose
    End Sub

    В результате запуска на выполнение меню должно приобрести вид, подобный изображенному на рис. 2. В одном меню можно расположить несколько подменю - главное знать меру и не запутать самих себя. Меню могут быть украшены пиктограммами, т.н. FaceIDs. (О том, как их получить, будет рассказано в следующей статье).

    Наше приложение с нашим меню

    Рис. 2 - Наше приложение с нашим меню

    В архиве находится готовый файл, который можно использовать в качестве шаблона для разработки собственных решений.

    Литература
    1. Хорев В.Д. Самоучитель программирования на VBA в Microsoft Office. - К.: Юниор, 2001. - 296 с.
    2. Гарнаев А. Ю. Самоучитель VBA. - СПб.: БХВ-Петербург, 2002. - 512 с.
    3. Биллиг Владимир Арнольдович. Основы офисного программирования и язык VBA
    4. Тихвинский Виталий. VBA Создание меню