|
|
|||||||||||||||||||||||||||||
|
Visual Basic: Subclassing в VB.NET (исходники)Источник: VBstreets
ВведениеПрежде всего необходимо сказать несколько слов для начинающих программистов, возможно впервые сталкивающихся со словом subclassing 1 (читается как "сабклассинг"). По-простому можно объяснить этот термин, как создание некоторой "обертки", расширяющей уже имеющуюся функциональность, для уже существующего класса. Допустим, уже имеется такой контрол как TreeView, и нет особого смысла заново создавать этот элемент управления, гораздо проще расширить уже имеющийся, например добавив возможность подсветки разными цветами, либо включением анимированных gif картинок и т.п. Ранее, при использовании Visual Basic вплоть до шестой версии, приходилось идти на различные ухищрения для реализации subclassing'а. Порой, напарываясь на множество подводных камней, разработчик отказывался от идеи использования функций "чужого" контрола и писал свой. Для реализации subclassing'а в VB требовалось достаточно много не всегда понятного начинающим программистам кода. Примером могут служить популярные библиотеки, используемые для реализации subclassing: SSubTmr.dll, автор: Steve McMahon (доступна на http://www.vbaccelerator.com/ с исходным кодом), либо SubTimer.dll, автор: Bruce McKinney (на основе этой библиотеки создан SSubTmr.dll). В Visual Basic .NET эта проблема решена! Теперь subclassing это достаточно простой и удобный метод создания контролов с расширенной функциональностью. (Примером может служить мой контрол DiskTree, опубликованный на этом сайте). В этой статье я постараюсь достаточно подробно и понятно рассказать о использовании subclassing'а. Статья рассчитана как на начинающих программистов, так и на опытных программистов VB6 переходящих на VB.NET. Принципы subclassing'аОсновной принцип subclassing'a - переопределение методов и свойств имеющихся объектов. Переопределение реакции на различные события, происходящие для данного объекта. Допустим, существует некоторый элемент управления, который по клику мышки на нем записывает в файл некоторую информацию. Нам же требуется, чтобы эта информация не сохранялась в файле, а записывалась в системный журнал Windows. Для этого мы переопределяем событие OnClick таким образом, чтобы выполнялись именно требуемые действия. Таким образом можно создать новый элемент управления, как бы содержащий старый, но иначе реагирующий на событие щелчка мышкой. Также это может быть необходимо для переопределения некоторых методов "отрисовки" контрола, примером может служить cPopMenu с вышеуказанного сайта http://www.vbacelerator.com/. На основе стандартного меню создается новый контрол, позволяющий использовать иконки напротив пунктов меню и рисовать меню в стиле Office 2000. В VB.NET эти действия являются естественными - все элементы, формы и даже типы данных - это классы. И, в соответствии с концепциями ООП, допускают наследование и переопределение методов и свойств. Subclassing формыНачнем с наиболее простого и наиболее понятного. Создайте новый проект (либо, если не хотите делать все своими руками, посмотрите прилагаемый к статье пример). По умолчанию в него будет включена одна форма. Перейдите к просмотру кода (Code View) и посмотрите на два выпадающих списка вверху окна редактирования. К моему большому удивлению, немногие знают или догадываются, что код для обработки событий и переопределения методов можно не набирать руками, а использовать автоматически генерируемый средой Visual Studio. В левом списке выберите Overrides, а в правом WndProc. Вы получите следующий код.
Все, таким образом мы получаем контроль над всеми событиями формы. Так или иначе события обрабатываются данной процедурой. Ключевое слово Overrides означает, что эта функция переопределяет уже существующую. На этом простом примере я покажу основные принципы реализации subclassing'а. Допустим, надо перехватить событие щелчка левой кнопкой мыши по форме, для этого напишем следующий код:
Поясню этот код. Для начала происходит проверка, какое событие "попало в нашу функцию". В данном случае нас интересует только "отжатие" левой кнопки. Константа WM_LBUTTONUP - обозначает именно сообщение, получаемое формой, при "отжатии" левой кнопки мыши. Полный список констант вы можете посмотреть в модуле WindowsMessages.vb, входящем в проект, прилагаемый к статье. В модуле я собрал наиболее часто используемые сообщения Windows для легкого и быстрого использования в проектах. Теперь еще чуть-чуть проиграемся с этим кодом. Напишем следующий код:
Запустив проект мы обнаружим, что при щелчке по форме отображаются последовательно два MsgBox. То есть происходят оба события. И, как и должно быть, сначала происходит "отжатие кнопки", а потом событие щелчка. Теперь добавим еще одну строку кода:
Теперь второй MsgBox не будет появляться, что служит свидетельством того, что форма не получила предназначенного ей события. Таким образом я показал, как можно перехватывать события формы до того, как она их получит, и выполнять какие-либо действия, что иногда бывает очень удобно. Помимо методов, можно переопределять и свойства. Для этого добавьте следующий код:
По нажатию кнопки, текст заголовка формы будет изменен на "Кнопка:" плюс код нажатой клавиши, но переопределенное свойство Text проводит некоторую операцию перед выводом текста на экран. Таким образом, при нажатии пробела будет отображен заголовок "Кнопка: Пробел", при этом получая значение свойства, мы получим "Кнопка: 32". Этот пример достаточно бессмысленный, но он иллюстрирует способ изменения свойств объекта. Subclassing элемента управленияТеперь самое время перейти к более интересному варианту - расширим свойства стандартного элемента управления TextBox. Для этого снова создайте новый проект (либо, опять-таки возьмите мой из архива). Прежде всего определимся, чего бы нам хотелось получить от этого нового-старого контрола. На этот раз не будем проявлять особую оригинальность и создадим компонент позволяющий вводить только числа, такой контрол нам всегда пригодится. При этом этот контрол не позволяет производить копирование и вставку текста и не отображает ниспадающего меню по щелчку правой кнопкой мыши. Также, в качестве тренировки, добавим запрет на присвоение значения Text непосредственно из кода. Добавьте в проект новый UserControl, назовите его NumbersBox . И переходите сразу к редактированию кода. По умолчанию новый класс наследуется от System.Windows.Forms.UserControl, но нам это не подходит, мы же не хотим добавить TextBox на наш контрол и создавать элемент управления содержащий TextBox. Наша задача - расширить функциональность TextBox непосредственно. Поэтому смело заменяем строку:
На:
Так мы получили контрол, который уже включает в себя все функции, методы и свойства стандартного элемента TextBox. Теперь в Toolbox на вкладке My User Controls отображается наш NumbersBox. Налюбовавшись на это чудо дивное, перейдем непосредственно к реализации задуманного. Опять-же, основная часть кода будет сосредоточена в WndProc.
А для того, чтобы запретить присвоение значения Text из кода (то есть текст может быть введен только непосредственно с клавиатуры), нужно переопределить свойство Text базового контрола TextBox. Заметьте, мы не можем сделать это свойство ReadOnly, т.к. базовое свойство таковым не является, но это легко обходится с помощью небольшой хитрости.
Теперь вы можете просто перетащить контрол на форму, запустить проект на выполнение и порадоваться этому "гениальному" творению. Этот пример фактических повторяет предыдущий, но несколько в ином контексте. Дополнительным примером к этому разделу статьи может служить контрол DiskTree, опубликованный на этом же сайте. Создание класса для subclassing'aТеперь перейдем к созданию класса для закрепления сведений, изложенных в статье. Для этого создадим новое приложение (эх, неужели так лениво? Ну открывайте мой пример). И добавим новый класс, который унаследуем от System.Windows.Forms.NativeWindow. NativeWindow - специальный класс созданный для поддержки Subclassing'а для Windows Forms, класс уже содержит все необходимые методы и свойства для реализации subclassing'а, поэтому мы и используем его. Код класса:
Как видите - идея до гениальности проста - класс просто вызывает событие EventHappend, как только получает какое-либо сообщение. Далее мы привязываем объект к кнопке, предварительно помещенной на форму.
При нажатии клавиши программа будет отображать MsgBox. Таким образом subclassing любой формы или контрола осуществляется очень легко - для этого достаточно сопоставить описатель элемента (Handle) с объектом Subclasser и написать код обработки сообщений по событию EventHappened. ЗаключениеВ этой статье рассматривались основы subclassing'а в Visual Basic .NET. Как могли убедится читатели, работавшие ранее с VB6 и пробовавшие реализовать subclassing, это стало намного проще и понятнее. При этом большую часть работы берет на себя среда .NET, а программисту остается только лишь пользоваться "благами цивилизации".
|
|