| ||||||||||||||||
![]() | ||||||||||||||||
| ||||||||||||||||
![]() | ||||||||||||||||
| ||||||||||||||||
![]() |
Как создать ActiveX Control (заключительная статья)
Я очень рад, что мои статьи, судя по письмам, оказались нужными очень многим. Вполне возможно, что еще столько же прочитали их, нашли что-то для себя, но поленились написать мне. Я не в обиде. Это нормальное состояние. Начиная первую статью, я хотел показать, что пределов в создании ActiveX Control'ов - практически не существует. Пределы нам устанавливают только VB и объем наших знаний. Поэтапно проводя Вас от простого к более сложному, я и сам много чему научился. Ведь чтобы доступно преподать какие-то знания необходимо самому представлять этот процесс очень и очень ясно. Кроме того, необходимо было подобрать примеры, и не просто примеры, а чтобы они отражали суть статьи, и, кроме того, были бы еще нестандартными, и, что самое главное, нужными. А листинги. Сколько раз приходилось выверять их, чтобы не было ошибок, описок и т.п. Ведь просто скопировав их и запустив в своей программе, если они не будут работать ... Это моя последняя в этом цикле статья. Посмотрев, как делают другие авторы в заключительных статьях - сводят воедино все, что было дано в предыдущих, я решил не отставать от них. Но как оказалось - это достаточно скучно (ведь это все уже было!). Поэтому я решил сделать компромиссный вариант: будет и новое и старое. Да, кое-что я буду повторять в n-ый раз, кое-чему научу Вас новому. Однако особенностью данной, заключительной, статьи будет полное пошаговое описание всех процессов создания ActiveX Control'a. NB! - [аббревиатура от лат. Nota Bene!] обрати внимание! - Это обозначение будет встречаться там, где могут возникнуть определенные сложности. Что будем создавать сегодня? Контрол-контейнер произвольной формы, причем форму будет задавать сам программист, работающий с уже готовым контролом. Почему опять контейнер? Да просто потому, что превратить его затем в кнопку, лейбл или текстовое поле не представит особого труда. С какими трудностями мы столкнемся? Первая и основная — создание массива свойств пользовательского типа. Если честно говорить, сам я шел к этому не один месяц. Итак, начнем. Откроем VB и создадим новый проект с именем FigureControl. Для UserControl установим следующие параметры: Name = FigCtrl, AutoRedrive = True, ScaleMode = 3 (Pixel). NB! Большинство (если не все) API-функции работают с пикселами, а не твипами. Установим свойства проекта. Для этого щелкнем правой клавишей в окне проектов на FigureControl и выберем меню FigureControl Properties... Или так: меню Project/ FigureControl Properties... Далее. В Project Description напишем "Контейнер произвольной формы". Под ярлыком Make установим Auto Increment, заполним графы во фрейме Version Information. Под ярлыком Compile выберем опцию компиляции Compile to P-Code. Не откладывая в долгий ящик сразу же создадим тестировочный проект (меню File/Add Project... и выберем Standart EXE). Обзовем: Name = prjTest; для формы: Name = frmTest. NB! Если у Вас VB6, то не забудте щелкнуть правой клавишей в окне проектов на prjTest и выбрать меню Set us Start Up. VB5 делает это автоматически. Определимся со свойствами, методами и событиями контрола. Свойства контрола:
Методы контрола:
События контрола:
Ну вот, вроде со всем определились. Теперь пора бы и за создание взяться. Давайте начнем с самого трудного: с определения контуров будущего контрола. Если бы мы жестко прописали ряд возможных форм для нашего контрола, то особых трудностей это не составило бы. Просто мы определили бы какое-то свойство вроде FormForControl, через энум описали возможные варианты, а в коде программы жестко прописали бы каждую точку каждого варианта. Аналогичные манипуляции мы проводили, когда создавали ProgressBar в форме песочных часов (см. статью 4). Все сложности начинаются, когда мы собираемся предоставить программисту самому рисовать форму контрола такую, какую он хочет. Проблема заключается в следующем: создание фигуры произвольной формы описывается двумя API-функциями и типом: Declare Function SetWindowRgn Lib "user32" (ByVal hWnd As Long, ByVal hRgn As Long, _ Type POINTAPI X As Long Y As Long End Type Однако если мы попробуем создать свойство со ссылкой на пользовательский тип данных (а именно таковым воспринимает VB тип POINTAPI), то получим грозное сообщение о том, что это недопустимо. Желающие и неверующие могут проверить :-) Натура программиста такова, что если не получается взять наскоком напрямую, он начинает искать обходные пути. Не скажу что таких путей много. Мой вариант - это создание коллекции классов. Однако, в процессе написания статьи, Boris Rudoy предложил более изящный вариант работы с массивами, который я и хочу предложить Вашему вниманию. В разделе (General) объявим переменные Private rgn() As POINTAPI Private FirstAdding As Boolean Private rgnItemX() As Long Private rgnItemY() As Long Добавим внутреннюю функцию, определяющую общее количество точек Private Function PointCount() As Integer PointCount = UBound(rgnItemX) End Function И непосредственно сами методы добавления точек и вырезания фигуры. Public Sub AddPoint(ByVal X As Long, ByVal Y As Long) Dim i As Integer i = UBound(rgnItemX) If FirstAdding Then’ если добавляется первая точка i = 0 FirstAdding = False Else i = i + 1 End If ReDim Preserve rgnItemX(i)’переопределяем массивы ReDim Preserve rgnItemY(i) rgnItemX(i) = X rgnItemY(i) = Y End Sub Public Sub ShowFigure() Dim i As Integer, count As Long, hRgn As Long On Error Resume Next count = PointCount + 1 ReDim rgn(count) As POINTAPI’инициализируем массив точек For i = 1 To count rgn(i).X = rgnItemX(i - 1) rgn(i).Y = rgnItemY(i - 1) Next hRgn = CreatePolygonRgn(rgn(1), count, 0)’ рисуем SetWindowRgn UserControl.hWnd, hRgn, True’ и вырезаем контрол End Sub
Изменим цвет UserControl'a на какой-нибудь другой, отличный от серого, чтобы во время исполнения мы могли его видеть на серой форме. Установим у тестировочной формы свойство ScaleMode = 3 (Pixel), AutoRedraw = True и разместим на ней наш прототип контрола. Запишем ей код: Private Sub Form_Load() 'Рисуем точки контура With FigCtrl1 .AddPoint .Width / 2, 0 .AddPoint .Width, .Height / 2 .AddPoint .Width / 2, .Height .AddPoint 0, .Height / 2 End With FigCtrl1.ShowFigure End Sub Запускаем программу. Если все было сделано правильно, то контрол должен приобрести форму ромба. Итак, самое сложное сделано: мы создали вывод контрола произвольной формы. Пойдем дальше. Не всегда вырезанный контрол имеет ровный край и это смотрится не очень презентабельно. Давайте обведем контуры. У нас для этого предусмотрено 2 свойства, отвечающие за цвет и толщину окантовки. Создадим коды для них с помощью Wizard’а. А чтобы они заработали нужно совсем чуть-чуть кода. Допишем в ShowFigure в самый конец: DrawWidth = m_BorderThickness For i = 1 To count If i = count Then’ для соединения последней и первой точек Line (rgn(i).X, rgn(i).Y)-(rgn(1).X, rgn(1).Y), m_BorderColor Else’ для всех остальных точек line (rgn(i).X, rgn(i).Y)-(rgn(i + 1).X, rgn(i + 1).Y),m_BorderColor End If Next Попробуем в тестировочной форме. Займемся теперь градиентной заливкой. Но человек существо неудовлетворенное. Жесткие градации переходов цвета … Давайте предоставим пользователю самому устанавливать нужную расцветку. Обратимся опять к Wizard’у и добавим свойства, отвечающие за градиентную заливку. В Property Let каждого из вновь добавленных свойств введем ссылку на внутреннюю процедуру DrawControl, а для свойств ответственных за градиентный цвет вначале введем проверку типа If New_GradientRed < 0 Or New_GradientRed > 255 Then New_GradientRed = -1 End If Займемся самой процедурой. Private Sub DrawControl() Cls’ очистка контрола от графики If m_Gradient = True Then Dim R%, G%, B% Dim i%, NbrRects%, GradValue%, GradColor& NbrRects% = 127 ScaleMode = 3’ установка свойств контрола DrawWidth = 2 DrawStyle = 6 AutoRedraw = True For i = 1 To NbrRects GradValue = 255 - (i * 2 - 1) If m_GradientRed = -1 Then R = GradValue Else R = m_GradientRed End If If m_GradientGreen = -1 Then G = GradValue Else G = m_GradientGreen End If If m_GradientBlue = -1 Then B = GradValue Else B = m_GradientBlue End If GradColor = RGB(R, G, B) ‘ непосредственный вывод заливки в зависимости от ориентации Select Case m_GradientOrientation Case 0 Line (0, ScaleHeight * (i - 1) / NbrRects)- (ScaleWidth, ScaleHeight * i/ NbrRects), _ GradColor, BF Case 1 Line (ScaleWidth * (i - 1) /NbrRects, 0)-(ScaleWidth* i/ NbrRects, ScaleHeight), _ GradColor, BF Case Else 'если по ошибке поставят < 0 или > 1 Line (0, ScaleHeight * (i - 1) /NbrRects)- (ScaleWidth,ScaleHeight * i /NbrRects), _ GradColor, BF End Select Next i End If ShowFigure’ вырезаем фигуру End Sub Не откладывая в дальний ящик, давайте создадим Property Page, где будут отражаться наши свойства (Name = ppFigureControl, Caption = "Figure Control” – именно Caption будет выводиться в качестве ярлыка). Т.к. GradientOrientation имеет тип constOrientation, то мастер его не увидит. Поэтому давайте используем ComboBox для вывода этого свойства (подробнее как это делается см. статью 6). На этом можно было бы успокоиться, но давайте сделаем установку свойств GradientRed, GradientGreen и GradientBlue более удобной. Удалим текстовые поля, относящиеся к ним и расположим CheckBox и Scroll для каждого из этих свойств. Дадим имена по принципу chkRed и scrRed. Кроме того для каждой линейки прокрутки установим свойства: LargeChange = 10, Max = 255, Min=0, SmallChange = 1. Подробнее коды можно посмотреть в листинге. Вернемся к нашему контролу. У нас осталось три свойства отвечающие за вывод надписи. С помощью того же Wizard’а создаем коды для них и в Property Let делаем ссылку на процедуру DrawControl. А в саму процедуру перед ShowFigure допишем: CurrentX = (ScaleWidth - TextWidth(m_Caption)) / 2 CurrentY = (ScaleHeight - TextHeight(m_Caption)) / 2 UserControl.ForeColor = m_ForeColor UserControl.Print m_Caption Добавим в проект форму About (меню Project/Add Form) и коды в проект Public Sub About() frmAbout.Show vbModal End Sub Теперь сделаем описание для наших свойств, событий и методов. Меню Tools/Procedure Attributes … кнопка Advanced. Для метода About в поле Procedure ID выберем опцию AboutBox. Для всех свойств в поле Property Category введем «Figure Control» для группирования их в окне свойств под ярлыком Categorized. Свойству Caption кроме всего прочего в поле Procedure ID установим опцию (Default). Естественно, не забудем для всех свойств, событий и методов в поле Description написать что же они выполняют. Подготовим Help-файл и прикрепим его к контролу. И вот только теперь можно «трубить в фанфары»: ACTIVEX CONTROL – готов! Но и сейчас не поленитесь – «погоняйте» его в тестировочной форме во всех мыслимых режимах, а в немыслимых - будет это делать пользователь :-). Не забудьте так же и о поддержке версий, так называемые апгрейды (кто не помнит как это делается см. статью 5) По традиции - листинг Напоследок, хочу напомнить, что я не единственный, кто создает контролы. Пишите о своих находках и ньюансах создания. ПОДЕЛИСЬ – БОГАЧЕ СТАНЕШЬ! [Назад][Содержание] |
|
![]() | ||||||||||||||||
| ||||||||||||||||
![]() | ||||||||||||||||
|