Я неоднократно сталкивался с ситуациями, когда создавая нестандартный интерфейс, вынужден был использовать стандартные компоненты, не отвечающие общей идее. Самым ярким примером может служить линейка прокрутки. Это наверное единственный элемент управления, который не может изменять свою окраску. Поэтому создавая разноцветные формы, чтобы избежать не согласованности, всегда приходится думать чем заменить линейку прокрутки. В конце концов это меня вынудило создать свой собственный ActiveX Control, который отвечал бы моему интерфейсу. Художник я неважный поэтому нашел способ, позволяющий без особых проблем создавать различного вида схематические рисунки. В данном случае я использовал Автофигуры в Word'е с последующей их раскраской. Сохранив документ как HTML-файл, я получил возможность использовать их в своей программе.
Если уж делать, то делать, убивая сразу двух зайцев. Я решил вместо двух линеек прокрутки (горизонтальной и вертикальной) создать один элемент управления, обладающий свойствами обеих. Если Вам это интересно, то последовательно вместе со мной Вы сможете создать себе такой же.
Создадим проект ActiveX Control: Name = DoubleScroll; сам UserControl назовем DblScroll. Расположим на нем:
pic |
PictureBox |
Является
контейнером для нижеуказанных
элементов управления |
picSignH |
PictureBox |
Height=Width=195
твипов |
picSignV |
PictureBox |
Height=Width=195
твипов |
На первом этапе, еще не создавая свойств и событий, добьемся чтобы наш будущий контрол имел прозрачную подложку. Я не буду подробно останавливаться на на этих функциях (они достаточно хорошо описаны на сайте vbrussian.com). Скажу только, что смысл их заключается в попиксельном считывании картинки и невключении пикселов заданного цвета в регион. Далее выводим этот регион на нашем UserControl'е. Данную процедуру (Draw) необходимо инициализировать в событии UserControl_Show, для полноценного отображения всех наших преобразований во время выполнения.
NB! Попиксельное считывание картинки - достаточно длительная процедура. Помните об этом, когда будете создавать свои картинки, не делайте их слишком большими!
Создайте тестировочный проект, расположите на форме создаваемый контрол и посмотрите промежуточный результат.
Расположите picSignH на горизонтальной части линейки прокрутки, а picSignV - на вертикальной. Займемся движениями бегунков при нажатии на них и перетаскивании.
NB! Обратите внимание на константы, объявляемые нами в разделе деклараций:
Private Const SIGN_SIZE = 195 'высота(ширина) бегунка в твипах
Private Const SIDE_SIZE = 420 'высота(ширина) звездочки (заменяет стрелку на обычной линейке) в твипах
Если Вы будете использовать свой рисунок, не забудьте поменять значения этих констант для корректной работы контрола.
Создадим 2 процедуры, считывающие начальную и конечную координаты бегунков:
Private Sub picSignMouseDown()
Dim res As Long
startMove = True
res = GetCursorPos(FirstPos)
End Sub
Private Sub picSignMouseUp()
Dim res As Long
res = GetCursorPos(LastPos)
startMove = False
End Sub
И используем их, соответственно, для событий MouseDown и MouseUp наших бегунков. А вот в событии MouseMove мы будем перемещать непосредственно сам бегунок, предварительно ограничив его движения по краям.
Если сейчас мы запустим тестировочный проект, то вполне сможем насладиться нашим контролом и перетаскиванием бегунков. Однако, до получения законченного результата еще далеко, так как в настоящий момент мы имеем "вещь в себе". Красивая безделушка, не связанная ни с чем. Настало самое время добавить свойства и методы.
Воспользуемся мастером создания ActiveX Control'ов и создадим элементы интерфейса, указанные ниже в таблице. Учитывая, что у нас, по сути, 2 линейки прокрутки, все свойства придется дублировать (вертикальные и горизонтальные):
Имя |
Тип |
Значение по умолчанию |
Описание |
Свойство |
MaxH |
Long |
100 |
Максимальное значение горизонтальной части |
Свойство |
MaxV |
Long |
100 |
Максимальное значение вертикальной
части |
Свойство |
MinH |
Long |
0 |
Минимальное значение горизонтальной части |
Свойство |
MinV |
Long |
0 |
Минимальное значение вертикальной части |
Свойство |
LargeChangeH |
Long |
10 |
Смещение (в единицах) при щелчке между бегунком и краем по горизонтали |
Свойство |
LargeChangeV |
Long |
10 |
Смещение (в единицах) при щелчке между бегунком и краем по вертикали |
Свойство |
SmallChangeH |
Long |
1 |
Смещение (в единицах) при щелчке на
концевую часть по горизонтали |
Свойство |
SmallChangeV |
Long |
1 |
Смещение (в единицах) при щелчке на концевую часть по вертикали |
Свойство |
ValueH |
Long |
0 |
Текущее горизонтальное значение |
Свойство |
ValueV |
Long |
0 |
Текущее вертикальное значение |
Событие |
Scroll |
|
|
Событие, возникающее при щелчке на любую из линеек |
Событие |
HorizontalScroll |
|
|
Событие, возникающее при щелчке на горизонтальную линейку |
Событие |
VerticalScroll |
|
|
Событие, возникающее при щелчке на вертикальную линейку |
Напишем две процедуры, описывающие положение бегунка, с учетом ограничения движения (вот где нам понадобились константы!):
Private Sub PosHorizontal()
picSignH.Left = (pic.ScaleWidth - (2 * SIDE_SIZE) - SIGN_SIZE) * m_ValueH / (m_MaxH - m_MinH) + SIDE_SIZE
End Sub
Private Sub PosVertical()
picSignV.Top = (pic.ScaleHeight - (2 * SIDE_SIZE) - SIGN_SIZE) * m_ValueV / (m_MaxV - m_MinV) + SIDE_SIZE
End Sub
Вставим эти процедуры в Property Let свойств Min, Max и Value (горизонтальные и вертикальные соответственно).
И теперь (наверно, самое сложное в этом контроле) мы должны описать реакцию нашего элемента на щелчок по его различным "частям тела". Делается это в событии pic_MouseDown. Здесь же устанавливаются проверки на допустимость выставляемых значений свойств.
Не забудьте добавить выполнение событий контрола в picSignV_MouseMove и picSignV_MouseMove.
Вот теперь наш контрол готов. Осталось добавить необходимые мелочи: описание свойств и событий для возможности их прочтения в Object Browser, создания PropertyPage, формы About и желательно Help).
Данный контрол вполне работоспособен, но это не ограничивает Вас от дальнейших экспериментов и наращивания его мощностей.