Visual Basic 6. Руководство разработчика

       

Скелет элемента управления ActiveX


Перед добавлением кода следует изучить, что именно сделал мастер. Переклю­читесь в окно Project Explorer и выполните двойной щелчок на имени созданного элемента управления, чтобы открыть режим разработки Затем выполните двойной щелчок на форме элемента UserControl, чтобы открыть окно с кодом и просмотреть строки, вставленные мастером.

Программа 16.2. ActiveX Control

Private m_Caption As String

Private m_Effect As Integer

Private m TextAlignment As Integer

' Значения свойств по умолчанию:

Const m_def_Caption = "3D Label"

Const m_def_Effect = 2

Const m_def_TextAlignment = 4

' Переменные свойств:

' Объявления событий:

Event DblClick()

Event Click()

Event KeyUp(KeyCode As Integer, Shift As Integer)

Event KeyPress(KeyAscii As Integer)

Event KeyDown(KeyCode As Integer, Shift As Integer)

Event MouseUp(Button As Integer, Shift As Integer, X As Single, _

Y As Single)

Event MouseMove(Button As Integer, Shift As Integer, X As Single, _

     Y As Single)

Event OLEStartDrag(Data As DataObject, AllowedEffects As Long)

Event OLESetData(Data As DataObject, DataFormat As Integer)

Event OLEGiveFeedback(Effect As Long, DefaultCursors As    Boolean)

Event OLEDragOver(Data As DataObject, Effect As Long, _

     Button As Integer, Shift As Integer, X As Single, _

     Y As Single, State As Integer)

Event OLEDragDrop(Data As DataObject, Effect As Long, _

Button As Integer, Shift As Integer, X As Single, _

Y As Single)

Event Resize ()

Public Property Get Font() As Font

Set Font = UserControl.Font

End Property

Public Property Set Font(ByVal New_Font As Font)

Set UserControl.Font = New_Font

PropertyChanged "Font"

End Property

Public Property Get BorderStyle() As Integer

BorderStyle = UserControl.BorderStyle

End Property

Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)

UserControl.BorderStyle() = New_BorderStyle

PropertyChanged "BorderStyle"

End Property

Public Property Get BackStyle() As BackgroundStyle


BackStyle = UserControl.BackStyle

End Property

Public Property Let BackStyle(ByVal New_BackStyle As _

BackgroundStyle)

UserControl.BackStyle() = New_BackStyle

PropertyChanged "BackStyle"

End Property

Public Property Get Appearance () As Integer

Appearance = UserControl.Appearance

End Property

Private Sub UserControl_DblClick()

RaiseEvent DblClick

End Sub

Private Sub UserControl_Click()

RaiseEvent Click

End Sub

Public Property Get Enabled() As Boolean

Enabled = UserControl.Enabled

End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)

UserControl.Enabled() = New_Enabled

PropertyChanged "Enabled"

End Property

Public Property Get ForeColor() As OLE_COLOR

ForeColor = UserControl.ForeColor

End Property

Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR)

UserControl.ForeColor() = New ForeColor

PropertyChanged "ForeColor"

End Property

Public Property Get hDC() As Long

hDC = UserControl.hDC

End Property

Public Property Get hWnd() As Long

hWnd = UserControl.hWnd

End Property

Private Sub UserControl_KeyUp( KeyCode As Integer, Shift As Integer)

RaiseEvent KeyUp(KeyCode, Shift)

End Sub

Private Sub UserControl_Keypress(KeyAscii As Integer)

RaiseEvent Keypress(KeyAscii)

End Sub

Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)

RaiseEvent KeyDown(KeyCode, Shift)

End Sub

Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, _

X As Single, Y As Single)

RaiseEvent MouseUp(Button, Shift, X, Y)

End Sub

Public Property Get MousePointer() As Integer

MousePointer = UserControl.MousePointer

End Property

Public Property Let MousePointer(ByVal New_MousePointer As Integer)

UserControl.MousePointer() = New_MousePointer

PropertyChanged "MousePointer"

End Property

Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer,     _



X As Single, Y As Single)

RaiseEvent MouseMove(Button, Shift, X, Y)

End Sub

Private Sub UserControl_OLEStartDrag(Data As Data0bject, _

AllowedEffects As Long)

RaiseEvent OLEStartDrag(Data, AllowedEffects)

End Sub

Private Sub UserControl_OLESetData(Data As DataObject, _

DataFormat As Integer)

RaiseEvent OLESetData(Data, DataFormat)

End Sub

Private Sub UserControl_OLEGiveFeedback(Effect As Long, _

DefaultCursors As Boolean)

RaiseEvent OLEGiveFeedback(Effect, DefaultCursors)

End Sub

Public Property Get OLEDropMode() As Integer

OLEDropMode = UserControl.OLEDropMode

End Property

Public Property Let OLEDropMode(ByVal New_OLEDropMode As Integer)

UserControl.OLEDropMode() = New_OLEDropMode

PropertyChanged "OLEDropMode"

End Property

Private Sub UserControl_OLEDragOver(Data As DataObject, _

Effect As Long, Button As Integer, Shift As Integer, _

X As Single, Y As Single, State As Integer)

RaiseEvent OLEDragOver(Data, Effect, Button, Shift, X, Y, State)

End Sub

Private Sub UserControl_OLEDragDrop(Data As Data0b]ect, Effect As    Long, _

Button As Integer, Shift As Integer, X As Single, _

Y As Single)

RaiseEvent OLEDragDrop(Data, Effect, Button, Shift, X, Y)

End Sub

Public Sub OLEDrag()

UserControl.OLEDrag

End Sub

Public Property Get Picture() As Picture

Set Picture = UserControl.Picture

End Property

Public Property Set Picture(ByVal New Picture As     Picture)

Set UserControl.Picture = New_Picture

PropertyChanged "Picture"

End Property

Private Sub UserControl_Resize ()

RaiseEvent Resize

End Sub

Public Property Get Caption() As String

Caption = m_Caption

End Property

Public Property Let Caption(ByVal New_Caption As     String)

m_Caption = New Caption

PropertyChanged "Caption"

End Property

Public Property Get Effect() As Integer

Effect = m_Effect

End Property

Public Property Let Effect(ByVal New_Effect As Integer)



m_Effect = New_Effect

PropertyChanged "Effect"

End Property

Public Property Get TextAlignment() As Integer

TextAlignment = m_TextAlignment

End Property

Public Property Let TextAlignment(ByVal New_TextAlignment As Integer)

m_TextAlignment = New_TextAlignment

PropertyChanged "TextAlignment"

End Property

' Инициализация свойств

Private Sub UserControl_InitProperties()

Set Font = Ambient.Font

m­_Caption = m_def_Caption

m_Effect = m_def_Effect

m_TextAlignment = m_def_TextAlignment

UserControl.BorderStyle = 1

UserControl.BackStyle = 1

End Sub

' Загрузка значений свойств

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

Set Font = PropBag.ReadProperty("Font",Ambient.Font)

UserControl.BorderStyle = PropBag.ReadProperty ("BorderStyle", 0)

UserControl.BackStyle = PropBag.ReadProperty ("BackStyle", 1)

UserControl.Enabled = PropBag.ReadProperty ("Enabled", True)

UserControl.ForeColor = PropBag.ReadProperty ("ForeColor", _

   &H80000012)

UserControl.MousePointer = PropBag.ReadProperty ("MousePointer", 0)

UserControl.OLEDropMode = PropBag.ReadProperty ("OLEDropMode", 0)

Set Picture = PropBag.ReadProperty ("Picture", Nothing)

m_Caption = PropBag.ReadProperty ("Caption", m_def_Caption)

m_Effect = PropBag.ReadProperty ("Effect", m_def_Effect)

m_TextAlignment = PropBag.ReadProperty ("TextAlignment", _

  m_def_TextAlignment)

UserControl.BackColor = PropBag.ReadProperty ("BackColor", _

  SH8000000F)

End Sub

' Сохранение значений свойств

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

Call PropBag.WriteProperty("Font", Font, Ambient.Font)

Call PropBag. WriteProperty("BorderStyle",

UserControl.BorderStyle,0)

Call PropBag.WriteProperty("BackStyle", UserControl.BackStyle, 1)

Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True) Call PropBag.WriteProperty ("ForeColor", UserControl.ForeColor, _



&H80000012)

Call PropBag. WriteProperty ("MousePointer", _

UserControl.MousePointer, 0)

Call PropBag. WriteProperty ("OLEDropMode", _

UserControl.OLEDropMode, 0)

Call PropBag.WriteProperty("Picture", Picture, Nothing)

Call PropBag. WriteProperty ("Caption", m_Caption, _

m_def_Caption)

Call PropBag.WriteProperty("Effect", m_Effect,

m_def_Effect)

Call PropBag. WriteProperty ("TextAlignment", _

m_TextAlignment, m_def_TextAlignment)

Call PropBag.WriteProperty ("BackColor", _

UserControl.BackColor, &H8000000F)

End Sub

' ВНИМАНИЕ! НЕ УДАЛЯЙТЕ И НЕ ИЗМЕНЯЙТЕ

' СЛЕДУЮЩУЮ ЗАКОММЕНТИРОВАННУЮ СТРОКУ

' MappingInfo=UserControl,UserControl,-1,BackColor

Public Property Get BackColor() As OLE_COLOR

BackColor = UserControl.BackColor

End Property

Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)

UserControl.BackColor() = New_BackColor

PropertyChanged "BackColor"

End Property

Программа довольно длинная, но не так сложна, как выглядит. Рассмотрим каждый раздел кода подробно, начиная с раздела объявлений.

Option Explicit

' Значения свойств по умолчанию

Private m_Caption As String

Private m_Effect As Integer

Private m_TextAlignment As Integer

Эти переменные содержат значения специальных свойств элемента управ­ления. Свойства элемента управления отображены на закрытые переменные кода элемента управления. Как и в случае с компонентом ActiveX, чьи свойства доступны извне, эти свойства являются, фактически, простыми переменными. Позже будет видно, как элемент управления получает значение, введенное пользователем в окне свойств (или код во время выполнения), и связывает их с закрытыми переменными. (Вспомните манипулирование свойствами OLE-сервера с помощью процедур Property Let и Property Get, рассмотренное в предыдущей главе. Тот же самый подход работает и с элементами управления ActiveX, но об этом позже.).

Дальше следуют определения нескольких констант, которые соответствуют значениям определенным в окне Set Attributes мастера. Эти константы будут исполь­зоваться дальше в коде как начальные значения для различных свойств. Учтите, что нет необходимости запускать мастер для того, чтобы просто поменять эти значения. Можно отредактировать код элемента управления. Обратите также внимание имена констант основаны на именах свойств, и код можно легко редактировать.



' Значения свойств по умолчанию:

Const m_def_Caption = "3D Label"

Const m_def_Effect = 2

Const m_def_TextAlignment =  4

Дальше следуют объявления событий. Это события, которые были определены в первых двух окнах мастера и отображены на объект UserControl. Щелчок на элементе управления генерирует событие Click, которое передается приложению, как будто оно было сгенерировано самим элементом управления ActiveX. В списке определено несколько больше событий, но нет нужды повторяться.

' Объявления событий:

Event DblCllck()

Event Click()

Event KeyUp(KeyCode As Integer, Shift As Integer)

Event Keypress(KeyAscii As Integer)

Event KeyDown(KeyCode As Integer, Shift As Integer)

Event MouseUp(Button As Integer, Shift As Integer,

X As Single, Y As Single)

Event MouseMove(Button As Integer, Shift As Integer, _

X As Single, Y As Single)

Примечание

Если событие Click не было отображено на объект UserControl, то только UserControl будет видеть событие Click. Если нужно выполнять специальные действия, когда на элементе выполнен двойной щелчок, следует запрограммировать событие Click в коде элемента управления. Пользователь не сможет программировать событие Click, пока оно не будет инициировано из кода элемента управления.

В нашем элементе управления не требуется как-то по особенному использовать событие Click (и другие обычные события мыши и клавиатуры), поэтому предоставим их приложению, которое использует элемент управления ActiveX.

Установка и чтение значений свойств

Теперь рассмотрим несколько подпрограмм: по две для каждого свойства.

Программа 16.3. Процедуры свойства Caption

Public Property Get Caption() As String

Caption =

m_Caption

End Property

Public Property Let Caption(ByVal New Caption As String)

m_Caption = New Caption

PropertyChanged "Caption"

End Property

Каждое свойство определено двумя Public-процедурами:

•   Property Let,

•   Property Get.

Процедура Property Let вызывается каждый раз, когда свойство изменяется ли­бо через окно свойств (во времени конструирования) либо из программы (во время выполнения). При изменении свойства работает код, состоящий из двух строк. Первая строка получает значение, передаваемое в параметре процедуры (которое является новым значением свойства), и присваивает его закрытой переменной, которая представляет свойство в элементе управления. Остальной код видит только локальное свойство m_Caption, а не фактическое свойство. Вторая строка сообщает Visual Basic, что свойство изменило значение. Метод PropertyChanged важен и должен быть включен в процедуру Property Let, так как именно так VB сохраняет любые изменения свойства, сделанные во время конструирования, чтобы эти значения имели эффект во время выполнения.



Процедура Property Get вызывается всякий раз, когда программа обращается к значению свойства. Эта процедура читает значение закрытой переменной m_Caption и присваивает его свойству Caption. Для каждого свойства должны быть определены процедуры Property Get и Property Let, включающие приведенные строки. Они составляют минимальный механизм для установки или чтения значений свойств.

Конечно, в эти процедуры можно добавлять и код проверки допустимости значений. Значение свойства TextAlignmen должно быть в диапазоне от 0 до 9. На данный момент элемент управления позволяет пользователю ввести любое значение этого свойства в окне свойств. Добавим проверку допустимости значения в проце­дуру Property Let для свойства TextAlignment. Сам код прост: он отвергает любые значения меньше 0 и больше 8.

Программа 16.4. Код проверки допустимости свойства TextAlignment в процедуре Property Let

Public Property Let TextAlignment(ByVal New_TextAlignment As _

Integer)

If m_TextAlignment >=0 And m_TextAlignitient<=8 Then

   m_TextAlignment = New_TextAlignment

PropertyChanged "TextAlignment"

Else

MsgBox "Invalid value for this property"

  ' (Недопустимое значение для этого свойства)

End If

End Property

Оператор If проверяет допустимость введенного значения, и, если новое значение находится вне допустимого диапазона, попытка изменить свойство отклоняется. Измените процедуру Property Let согласно приведенной схеме и затем переключитесь на тестовую форму проекта. Выберите элемент управления FLEXLabel на форме, откройте окно свойств и установите свойство TextAlignment в заведомо недопустимое значение (13 или 1000, например). При попытке изменить свойство, установив его в недопустимое значение, элемент управления выдаст предупреждение и отклонит изменения. Пока не совсем понятно, как добиться, чтобы допустимые значения свойства отображались в раскрывающемся списке, как в других элементах управления VB? Это требует написания еще небольшого ко­личества кода, о чем чуть позже.



После процедур Property Let и Property Get

для всех свойств идет код инициа­лизации некоторых переменных.

Программа 16.5. Код инициализации

' Инициализация свойств элемента управления

Private Sub UserControl_InitProperties ()

Set Font = Ambient.Font

m_Caption = m_def_Caption

m_Effect = m_def_Effect

m_TextAlignment = m_def_TextAlignment

UserControl.BorderStyle = 1

UserControl.BackStyle = 1

End Sub

Операторы подпрограммы InitProperties() присваивают начальные значения закрытым переменным, которые представляют свойства элемента управления. Константы m_def_Caption, m_def_TextAlignment и m_def_Effect были определены ранее в программе. При помещении этого элемента управления на форму Visual Basic читает значения переменных m_Caption, m_TextAlignment и m_Effect и выво­дит их в соответствующих строках окна свойств элемента.

Сохранение и чтение значений свойств

Далее в тексте идут две интересные подпрограммы:

•  ReadProperties;

•   WriteProperties.

При изменении каких-либо свойств через окно свойств новые значения должны быть где-то сохранены. Зачем?

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

Visual Basic предусматривает специальный объект для сохранения всех значений свойств - PropertyBag. Этот объект предусматривает два метода: один - для сохранения значения свойства, другой - для его чтения. Разработчику элемента управления необязательно знать все подробности сохранения значений. Visual Basic сохраняет значения свойств и при запросе предоставляет их.

Первый метод имеет следующий синтаксис:

WriteProperty propertyName, value, defaultValue

где

propertyName - имя свойства (например, Effect), value

может иметь буквальное значение(1 или "some sizzling effect"), но почти всегда - это имя закрытой пере­менной, которая содержит значение свойства, defaultValue - значение свойства по умолчанию.



Примечание

Зачем нужно указывать одновременно и собственно значение и значение по умолчанию при вызове метода? Дело в том, что VB сравнивает эти два параметра, и, если значения совпадают, то VB не выполняет сохранение (для ускорения процесса сохранения и восстановления значений свойства). При последующем запросе значения свойства с помощью метода ReadProperty Visual Basic просто возвращает значение по умолчанию.

Метод ReadProperty имеет следующий синтаксис:

ReadProperty propertyName, defaultValue

где propertyName — имя свойства, defaultValue — значение этого свойства, сохраненное ранее в объекте PropertyBag. В коде события Write Properties объекта UserControl необходимо вызвать метод WriteProperty для каждого из свойств. Аналогично, в коде процедуры ReadProperties для каждого свойства необходимо вызвать метод ReadProperty. Ниже приведен код процедур Write Properties и ReadProperties сгене­рированный мастером для элемента управления FLEXLabel.

Программа 16.6. Процедура ReadProperties элемента управления

' Загрузка значений свойств

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

Set Font == PropBag.ReadProperty("Font", Ambient.Font)

UserControl.BorderStyle = PropBag.ReadProperty ("BorderStyle", 0)

UserControl.BackStyle = PropBag.ReadProperty ("BackStyle", 1)

UserControl.Enabled = PropBag.ReadProperty("Enabled", True)

UserControl.ForeColor = PropBag.ReadProperty ("ForeColor", _

&H80000012)

UserControl.MousePointer = PropBag.ReadProperty ("MousePointer", 0)

UserControl.OLEDropMode = PropBag.ReadProperty ("OLEDropMode", 0)

Set Picture = PropBag.ReadProperty ("Picture", Nothing)

m_Caption = PropBag.ReadProperty("Caption", m_def_Caption)

m_Effect = PropBag.ReadProperty("Effect", m_def_Effect)

m_TextAlignment = PropBag.ReadProperty ("TextAlignment", _

m_def_TextAlignment)

UserControl.BackColor = PropBag.ReadProperty ("BackColor", _



&H8000000F)

End Sub

Программа 16.7. Процедура WriteProperties элемента управления

' Сохранение значений свойств

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

   Call PropBag.WriteProperty("Font", Font, Ambient.Font)

   Call PropBag.WriteProperty ("BorderStyle", UserControl.BorderStyle, 0)

   Call PropBag.WriteProperty("BackStyle", UserControl.BackStyle, 1)

   Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)

   Call PropBag.WriteProperty("ForeCoior", UserControl.ForeColor, _

&H80000012)

   Call PropBag.WriteProperty ("MousePointer", _

UserControl.MousePointer, 0)

   Call PropBag.WriteProperty ("OLEDropMode", _

UserControl.OLEDropMode, 0)

   Call PropBag.WriteProperty ("Picture", Picture, Nothing)

   Call PropBag.WriteProperty("Caption", m_Caption, m_def_Caption)

   Call PropBag.WriteProperty("Effect", m_Effect, m_def_Effect)

   Call PropBag. WriteProperty ("TextAlignment", _

m_TextAlignment, m_def_TextAlignment)

   Call PropBag.WriteProperty ("BackColor", _

UserControl.BackColor, &H8000000F)

End Sub

Передача событий

Последний раздел кода отображает различные события элемента управления на эквивалентные события объекта UserControl. Когда пользователь щелкает мышью на элементе управления ActiveX, Windows отправляет событие Click объекту UserControl. Разработчик элемента управления может обработать это событие в самом элементе управления (в этом случае приложение, которое использует элемент, не видит события Click), или передать событие приложению-контейнеру (в этом случае разработчик приложения, использующего элемент управления, сможет обработать сообщение), или сделать и то, и другое (сначала обработать событие в элементе управления, а затем передать его контейнеру).

Передать событие приложению можно с помощью метода

RaiseEvent. Событие Click объекта UserControl определено таким образом.

Private Sub UserControl_Click()

RaiseEvent Click

End Sub

Код остальных событий практически идентичен. Эти события вызывают оператор ReiseEvent для передачи события приложению-контейнеру. Если событие имеет параметры, например KeyPress, эти параметры перечисляются в круглых скобках после имени события.

Все, что сделал мастер — это вставил достаточно простой код. За исключением методов ReadProperty и WriteProperty, все остальное должно быть более или менее знакомо большинству программистов на Visual Basic. ActiveX — элемент управления, следовательно, не намного сложнее по сравнению со стандартным проектом. Осталось добавить еще несколько строк кода. В конце концов, необходимо указать элементу управления, как выравнивать надпись и обрисовывать ее с трехмерным эффектом.


Содержание раздела