Создание массивов в ActiveX Control'е
На этом уроке создаем комбинированный ActiveX Control. Напомню: это контрол, состоящий из уже готовых контролов. Особенностью сегодняшнего (это будет кнопка с выпадающим меню) будет наличие массивов в нем. Сделать это в форме не представляет особого труда, но создавая контрол, мы обязаны предусмотреть ряд ситуаций, которые в обычном проекте отрабатываются автоматически и поэтому не обращают на себя Вашего внимания.
Создадим новый проект с названием ButtonMenu и присвоим имя для UserControl'a - ButtMenu. Разместим на нем кнопку (Name - cmdButtMenu, Caption - "ButtonMenu"). Вызовем Редактор меню Tools/Menu Editor... Введем 2 записи: для меню (Name = mnuGeneral, Caption = "mnuGeneral" - хотя это и не принципиально, имя здесь дано, чтобы не было пустой строки, Index = [Пусто], Checked = False, Enabled = True, Visible = False) и подменю (Name = mnuMenu, Caption = "#", Index = 0, Checked = False, Enabled = True, Visible = True).
Определимся со свойствами, методами и событиями.
Свойства
Имя |
Описание |
Тип |
Значение по умолчанию |
BackColor |
Цвет кнопки |
OLE_COLOR |
&H8000000F |
Caption |
Надпись на кнопке |
String |
"ButtonMenu" |
Font |
Шрифт надписи |
Font |
MS Sans Serif, 8 |
Методы:
Имя |
Принимаемые параметры |
Описание |
AddMenu |
sCaption As String |
Добавляет новые строки меню |
События: Click, MouseDown, MouseMove, MouseUp
Введем эти свойства с помощью мастера.
NB! Если Вы программируете в VB5, сразу же исправьте ошибочные записи, сделанные мастером в UserControl_ReadProperties и UserControl_WriteProperties, соответственно:
Set cmdButtMenu.Font = PropBag.ReadProperty("Font", Ambient.Font) и
Call PropBag.WriteProperty("Font", cmdButtMenu.Font, Ambient.Font)
Другие свойства и событие введем позже, вручную в окно кодов. Это как раз тот случай, когда переделывать за мастером - себе накладней.
Создадим масштабируемость контрола.
Private Sub UserControl_Resize()
cmdButtMenu.Move 0, 0, ScaleWidth, ScaleHeight
End Sub
Займемся подробнее методом AddMenu:
Public Sub AddMenu(sCaption As String)
Dim iCount%
'проверяем количество меню, имеющихся в настоящий момент у контрола
iCount = mnuMenu.Count
'загружаем данные и показываем меню. Отнимаем 1, т.к. индекы меню начинаются с 0.
mnuMenu(iCount - 1).Caption = sCaption
mnuMenu(iCount - 1).Visible = True
'загрузка следующего меню, но невидимого. Данное действие пришлось :( использовать,
‘т.к. mnuMenu с индексом 0 у нас изначально грузится.
Load mnuMenu(iCount)
mnuMenu(iCount).Visible = False
End Sub
В принципе, желающие могут расширить этот метод примерно так:
Public Sub AddMenu(sCaption As String, Optional bChecked As Boolean, _
Optional bEnabled As Boolean, Optional bVisible As Boolean)
но тогда не забудте в теле метода прописать эти установки.
Теперь пару слов насчет метода RemoveMenu. Лично мне кажется, что данный метод будет использоваться крайне редко (это же не ListBox или ComboBox), а заниматься переиндексацией меню и отслеживать потом в командах… Поэтому я его не объявляю. Лучше я использую свойство Visible для данного меню. Но это ни в коем случае не ограничивает Вас – экспериментируйте!
Переходим к событиям: MouseDown, MouseMove, MouseUp –оставим без изменений, как их создал мастер. А вот в событие Click внесем поправку.
Private Sub cmdButtMenu_Click()
RaiseEvent Click
‘ эту проверку вставляем на случай отсутствия меню, тогда наше mnuMenu(0) – уже
‘ загруженное, но пустое не будет появляться и контрол будет работать как обычная кнопка.
If mnuMenu.Count > 1 Then
‘ на 60 твипов сдвигаем влево чисто с эстетическими побуждениями
PopupMenu mnuGeneral, , 60, ScaleHeight
End If
End Sub
Создадим новое событие, реагирующее на щелчок по меню – ClickMenu:
В разделе General объявим его: Event ClickMenu(Index As Integer), а ниже запишем:
Private Sub mnuMenu_Click(Index As Integer)
RaiseEvent ClickMenu(Index)
End Sub
Напоследок займемся теми методами из-за которых, собственно говоря, и писалась эта статья. Это методы: MenuCaption, MenuChecked, MenuEnabled, MenuVisible. Полностью я их все расписывать не буду (для этого существует Листинг), а покажу на примере одного.
И в Property Get и в Property Let в скобках делаем ссылку на Index элемента. В остальном все то же самое.
Public Property Get MenuCaption(Index As Integer) As String
MenuCaption = mnuMenu(Index).Caption
End Property
Public Property Let MenuCaption(Index As Integer, ByVal New_MenuCaption As String)
mnuMenu(Index).Caption = New_MenuCaption
PropertyChanged "MenuCaption"
End Property
А вот в UserControl_ReadProperties строка будет озвучиваться несколько по-иному (не забудьте вначале объявить переменную Index):
mnuMenu(Index).Caption = PropBag.ReadProperty("MenuCaption" & Index, vbNullString)
и в UserControl_WriteProperties соответственно:
Call PropBag.WriteProperty("MenuCaption" & Index, mnuMenu(Index).Caption, vbNullString)
Заметили хитрость? Здесь я считываю и записываю не в свойство MenuCaption, а в свойства MenuCaption0, MenuCaption1 и т.д. – столько, сколько у нас меню.
И теперь немного кода для тестировочного проекта – как это все работает.
Option Explicit
Private Sub Form_Load()
ButtMenu1.AddMenu "Checked"
ButtMenu1.AddMenu "Enabled"
ButtMenu1.AddMenu "Visible"
ButtMenu1.AddMenu "-"
ButtMenu1.AddMenu "Восстановить"
ButtMenu1.AddMenu "-"
ButtMenu1.AddMenu "Выход"
End Sub
Private Sub Form_Click()
ButtMenu1.Font.Bold = True
ButtMenu1.Caption = "Новое имя"
End Sub
Private Sub ButtMenu1_ClickMenu(Index As Integer)
Select Case Index
Case 0
ButtMenu1.MenuChecked(Index) = Not ButtMenu1.MenuChecked(Index)
Case 1
ButtMenu1.MenuEnabled(Index) = False
Case 2
ButtMenu1.MenuVisible(Index) = False
Case 4
ButtMenu1.MenuEnabled(1) = True
ButtMenu1.MenuVisible(2) = True
Case 6
End
End Select
End Sub
За листингом сюда.
1999