Delphi создание компонента runtime
Елена Филиппова
дата публикации 06-12-2000 00:00
Конец ноября в этом году выдался довольно забавный, и погода в Москве была неестественная для этого времени года и респондентов Круглого стола как прорвало. Если раньше можно было выделить десяток основных животрепещущих вопросов, например как выдвинуть CD-Rom, поместить иконку в Tray и обязательно добавить в Caption формы непрямоугольную кнопку, то теперь появился новый и явный лидер.
И в личной почте и в вопросах на Круглый стол, и даже по Аське, несмотря на отсутствие авторизации, я получила за неделю десяток практически дословно повторяющихся вопросов от совершенно разных и незнакомых мне людей.
"Как создать кнопку во время работы? Как назначить ей обработчики событий? Почему нельзя написать (Edit + IntToStr(i)).Text:='' и как же тогда можно писать? Не перебирать же все Edit'ы у меня их на форме 100 штук! Ну Дельфя и дает. "
И так далее с небольшими вариациями. Может курсовые задачи во всех ВУЗах одинаковые или это магнитные бури с солнечной активностью. А может "Дельфя" дает далеко не всем.
Итак, зачетной сессии посвящается.
Материал предназначен для начинающих программистов, умеющих работать с компонентами Delphi в режиме design-time но уже не считающих, что программировать это значит "накликать мышкой форму". Никаких интересных моментов для профи статья не содержит, это исключительно учебный материал.
Пояснения к проекту:
Это очень просто, главное - знать какой именно это компонент и где он будет лежать. Например, создадим TButton на нашей панели PanelTest. Комментарии к коду.
Хотя код короткий и довольно простой, для "новичков" стоит дать некоторые пояснения.
Определение переменной Var New : TButton НЕ СОЗДАЕТ новой кнопки, а только говорит о том, что в переменной New будет лежать ссылка на экземпляр класса TButton. Этот момент надо понять очень четко. Извиняюсь перед продвинутыми начинающими за прописные истины, но получаемые мной многочисленные письма заставляют обращать внимание на эти мелочи. Это довольно важные мелочи.
Примечание:
Советую прочесть статью Максима Игнатьева "Путешествуя по TObject. Или как оно работает."
Итак, создаем новый экземпляр класса TButton, а попросту говоря, нашу кнопку: Конструктор имеет входной параметр где указан Owner , то есть "хозяин", создаваемого объекта. Хозяин компонента отвечает за его корректное удаление и освобождение памяти. В качестве хозяина мы передаем ему панель PanelTest, это означает, что при удалении PanelTest будет удалена и наша кнопка. Если в качестве параметра указать nil, то и заботиться об удалении кнопки придется самим.
Какие комментарии можно добавить к прозрачным командам New.Top:= . ?
Ну вот, например такие: если мы создаем компонент, для которого требуется задать не только координаты левого верхнего угла, но и его ширину и высоту, то вместо четырех присвоений используйте метод TControl.SetBounds .
Назначение имени для динамических компонентов совершенно не обязательно, они прекрасно могут существовать и без имен. Только тогда невозможно будет найти их методом FindComponent, что, впрочем, не всегда необходимо. В нашем случае я назначаю имя всем компонентам исключительно от лени - присваивание New.Name:='Button' автоматически заполнит поле Text для TEdit и поле Caption для TLabel, TButton и TCheckBox и об этом можно не заботиться.
Созданная кнопка почти готова к самостоятельно жизни, за одним маленьким исключением. ее пока не видно.
Посмотрите повнимательнее Help на тему TControl.Parent, это то самое свойство, которое нам нужно. Parent - это визуальный родитель контрола.
Присваивание New.Parent:=PanelTest помещает кнопку New в массив дочерних контролов для панели PanelTest. Теперь кнопка будет не просто видна на панели, а будет принадлежать этой панели. То есть при возможном перемещении PanelTest или изменении ее размеров , наша кнопка будет оставаться внутри PanelTest.
Но и это еще не все. Если кнопка нам нужна не для украшения формы, то хотелось бы, чтобы она адекватно реагировала на некоторые события, ну хотя бы на свое собственное нажатие.
Это свойство определяет реакцию на событие, которое возникает при клике мышки или нажатии Enter на контрол.
Смотрим help по теме "Procedural types" , то есть "процедурные типы".
Например тип : это процедурный тип, который является ссылкой(указателем) на адрес процедуры с определенным списком параметров. Переменная MyProcedure содержит адрес соответствущей процедуры. Таким образом процедуру можно передавать как параметр в другие процедуры и функции. Тип TNotifyEvent это не просто указатель на процедуру, это ссылка на метод, об этом говорит директива "of object". Чем отличается ссылка на процедуру от ссылки на метод?
На самом деле тип "ссылка на метод" реально содержит две ссылки - непосредственно адрес метода(процедуры) и ссылку на сам объект, которому этот метод принадлежит.
Теперь наша кнопка прям как настоящая!
Итак, начнем.
Компоненты будем создавать при двойном клике мышкой на панели PanelTest.
В реальных примерах в run-time приходится добавлять на форму РАЗНЫЕ компоненты.
В нашем примере будем создавать не только кнопки (TButton) , а еще и TLabel, TEdit и TCheckBox.
Радиокнопки rgComponents как раз указывают, что именно мы собираемся создавать.
Можно пойти самым простым путем, воспользуемся уже разобранным кодом, добавим CASE на все наши случаи и для каждого класса перепишем этот код, изменяя тип создаваемого компонента.
Самый простой путь не всегда самый правильный.
Во-первых, если Вам понадобится добавить еще один тип, придется еще дописать кусок кода. А во-вторых, лениво повторять один и тот же код сто раз. :о)
То, что не красиво выглядит, с большой степенью вероятности, не совсем верно реализовано.
Настоящий программист, человек довольно ленивый. Именно это заставляет его оптимизировать процесс разработки. Именно по этой причине появился первый компилятор :о)
По этой же причине мы пойдем другим путем.
Ссылка на класс.
Хорошо бы передать Delphi тип компонента, экземпляр которого мы хотим создать. Тогда бы задача упростилась.
Формируем массивчик типов, передаем очередной элемент массива и Delphi сама вызывает нужные методы именно того класса, который мы ей дали!
А ведь мы можем это сделать : для этой цели существуют ссылки на класс - class references. Посмотрите help по этой теме, там довольно подробно объясняется это понятие и приводятся примеры.
Для примера: class of TObject это ссылка на класс TObject. Переменная типа TClass не может содержать экземпляр TObject, это только ссылка на определенный класс.
Мы можем определить свой собственный тип, как ссылку на класс, который является родительским по отношению ко ВСЕМ нашим типам создаваемых компонент. Нам нужна ссылка на TControl.
В Delphi есть уже "готовые" типы ссылок на классы. Кроме TClass есть еще несколько , в том числе и TControlClass. Воспользуемся им. Нам понадобится список классов, с которыми будем работать : На событие OnDblClick панели PanelTest разбираем, что именно мы должны создать и создаем это. Все! И никаких CASE'ов :о)
Привязываем положение нового компонента к той точке, в которой кликнули мышкой. Процедра ScreenToClient пересчитывает абсолютные (экранные) координаты глобального объекта Mouse в координаты относительно левого верхнего угла панели.
Вы обратили внимание на строку New.Tag:=1 ?
Что это за свойство и в чем его смысл?
Это целое число типа LongInt(длиной 4 байта), которое является полноценным свойством компонента и никак не учитывается средой. Delphi на него не обращает внимания. Можете там что-нибудь сохранить. На всякий случай.
Итак, присвоим нашим новеньким Tag равный 1.
Строка связывает наши компоненты с popup-меню pmComponent, которое теперь будет вызываться при нажатии правой кнопки на компоненте.
Не смущайтесь приведением к типу TEdit, дело в том, что свойство PopupMenu у класса TControl определено как protected и может быть использовано только его потомками. Чтобы не перебирать все наши типы, выбираем один и используем его для проникновения к нужному нам свойству. Так как PopupMenu есть у всех наших классов и оно то самое, которое наследовано от TControl.PopupMenu , то присвоение будет верным.
Меню pmComponent содержит три опции : Первая устанавливает свойство Tag равным 1, вторая меняет его на 2. И последняя опция удаляет компонент по нашему желанию.
Обратите внимание на основное меню окна, а именно на его пункт "Измененить цвет" Будем изменять цвет шрифта наших компонентов по выбранному условию. Все три пункта меню "Измененить цвет" используют один и тот же обработчик: Sender в этой процедуре - выбранный пункт меню. Обратите внимание в самом проекте, как расставлено свойство Tag у пунктов меню "Измененить цвет".
Перебираем в цикле массив Controls панели PanelTest, он содержит наши компоненты, и изменяем цвет шрифта по условию - если значение Tag выбранного пункта меню совпадает со значением Tag очередного компонента, это наш клиент!
Здесь мы изменяли свойство у всех компонентов, незавсимо от их типа. А в меню "Очистить" проводится почти такая же операция, но условием выступает принадлежность к определенному типу. Если мы хотим очистить TEdit (то есть очистить его свойство Text ), то перебор списка Controls будет выглядеть так: В удалении компонента нет никаких сложностей. В нашем примере только надо понять, что именно удаляется.
Воспользуемся свойством TPopupMenu.PopupComponent : TComponent , определяющим компонент, над которым в данный момент нажали правую кнопку мыши и вызвали это меню.
На рисунке показан момент работы проекта:
Было бы обидно, если Delphi разрешала бы программистам хранить для своих нужд только целочисленный признак. А мало ли какие у кого нужды?
Если внимательно прочесть Help, то в самой последней строке нам откроется истина : в свойстве Tag можно хранить что угодно длинной 4 байта ( any 32-bit value such as a component reference or a pointer ) !
Это может быть целое число , а может быть ссылка (pointer). Например, ссылка на компонент. Чувствуете, какие открываются перспективы?!
Пункт "Отметить CheckBox" основного меню в design-time имеет только один пункт (полоску считать не будем). По смыслу задачи в этот пункт должны добавляться подпункты со списком созданных к этому моменту TCheckBox'ов. При нажатии на нужный пункт, соответствующий TCheckBox на панели будет отмечаться (Checked:=True). Чудное(ударение на первый слог) свойство Tag поможет очень изящно решить эту задачу. Достраиваться меню будет в момент его вызова (событие OnClick), ибо зачем нам в другие моменты эта информация? Не ищите функцию NewItem в проекте, ее там нет. Это функция из VCL модуля Menus. Посмотрите его, найдете еще много-много интересного.
Вообще читайте исходники почаще. Это самый лучший учебный материал.
Итак, для каждого TCheckBox на нашей панели создаем новый пункт в меню и. вот оно! Приведение типов к LongInt необходимо для компилятора, иначе он не разрешит нам это присваивание.
В Delphi класс сам по себе является ссылкой, то есть PanelTest.Controls[i] содержит не сам компонент, а его адрес.
Свойству Tag присваем адрес соответствующего компонента. Собственно и все.
Вы обратили внимание на то, что мы сразу при создании пункта меню привязали к нему обработчик на событие OnClick? Вот этот обработчик: IF TMenuItem(Sender).Tag = 0 - проверка на пункт "Отметить все", здесь мы пользуемся старым способом перебора массива PanelTest.Controls.
А вот если это пункт для единичного TCheckBox'а . используем свойство Tag иным манером :о)
В принципе неплохо бы еще и проверять, что возвращает Ptr. Примерно так Это общий случай - защита от ошибочных ситуаций.
В нашем примере в TMenuItem(Sender).Tag ничего иного быть и не может, так что проверять не обязательно.
Хотя, с проверкой надежнее :о)
Изменим немного код создания компонент: И процедура OnClickButton изменится соответствующим образом: Изменение строки привяжем к меню pmComponent, добавив туда еще один пункт. Обратите внимание, что пункт этот имеет смысл только для кнопок. Поэтому перед показом popup-меню, на событие OnPopup, делаем соответствующий пункт видимым или невидимым. Да! Перед тем, как записать адрес новой строки в Tag, освободим память от предыдущей, ведь она нам больше не нужна. При удалении компонента нам теперь надо учесть этот момент - если удаляется кнопка, надо удалить ее строку.
Напоследок, для полного оживления картины, сделаем наши компоненты подвижными. Разрешим им свободно перемещаться по панели, таская их мышкой.
Это будет не drag & drop, а совершенно обычное перемещение, как в режиме design-time. Для его реализации нам понадобится обработать самим два события для передвигаемого компонента: OnMouseDown - если нажата левая кнопка мышки, запомним ее текущее положение в переменной DragPoint и и будем считать эти координаты точкой отсчета. OnMouseMove - если нажата левая кнопка мышки, передвигаем компонент по новым координатам, сдвигая его так же, как сдвинулась мышка относительно нашей точки отсчета. Тем самым компонент будет плавно передвигаться вслед за мышкой. Пишем эти процедуры сами, список параметров должен соответствовать описаниям этих событий ( для этого снова к Help'у ). В принципе можно посмотреть, как создает обработчики этих событий сама Delphi и оттуда переписать параметры.
Естественно, что при создании компонент необходимо добавить назначение этих процедур в качестве обработчиков нужных нам событий.
Ну, а теперь, мышку в руки и смело вперед!
В статье я довольно подробно разобрала некоторые вопросы, некоторые затронула вскользь.
Не дала прямого ответа на вопрос, почему нельзя писать "(Edit + IntToStr(i)).Text:=''". В самом проекте оставлено несколько забавных нюансов, от которых бы надо избавиться (например, при перетаскивании компонентов срабатывает событие OnClick, что делает кнопки особенно навязчивыми).
Это не от лени, в этом была стратегическая задумка.
Никакой Интернет со всеми его конференциями, статьями и примерами никогда не заменит программисту собственного опыта. Только то, что добыто (разобрано и понято) своими силами, запоминается надолго и приносит пользу.
Опыта надо набираться обязательно. Читайте help, ищите ответ в исходниках, экспериментируйте с проектом сколько душе угодно, но только обязательно сами.
Удачи!
Елена Филиппова,
специально для Королевства Delphi
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.
Итак, рассмотрим на первый взгляд сложный вопрос о создании компонентов в runtime (то есть во время работы программы). Но на самом деле этот вопрос довольно просто решается.
Давайте вместе попробуем написать код, чтобы при нажатии на кнопку на форме появлялось текстовое поле с каким-нибудь текстом. Для этого надо проделать следующие действия: объявить переменную необходимого вам типа компонента, в нашем случае TEdit, затем необходимо описать процедуру Create для нашей переменной, задать обязательное свойство Parent (то есть где появится наш компонент), ну и установить необязательные параметры типа высоты, ширины и т.д. Лучше разбираться на конкретном примере, так что смотрите какой у меня получился код: Как вы видите все очень просто. Поупражняйтесь с различными параметрами.
Процессы создания визуальных и невизуальных компонентов несколько отличаются (последний попроще будет). Поскольку Edit мы уже создали (а это как раз визуальный компонент), теперь будем создавать невизуальный компонент, например FontDialog. Поставьте на форму еще кнопку. Обработчик события OnClick может выглядеть так: Вы свободно можете изменять любые свойства компонента, созданного во время работы приложения.
Теперь мы попробуем вместе проделать такую вещь: мы отсортируем находящиеся в Memo данные. Для этого поставьте на форму Memo и напишите в ней 4 строки, например:
Memo4
Memo1
Memo3
Memo2
Поскольку само Memo сортировать данные не умеет, то нам придется во время работы программы создать какую-нибудь переменную абстрактного класса TStringList (этот класс сортировать умеет), затем присвоить этому классу строки из Memo, отсортировать их и присвоить их обратно Memo. Поставим еще одну кнопку на форму, которая будет запускать процесс. Код получится примерно таким: Теперь рассмотрим еще один вопрос, касающийся создания компонентов в Run-time. Допустим вам надо создать 20 полей для ввода текста (Edit) и еще десять меток (Label), не будете же вы 20 раз писать одно и тоже для каждого edit'a. В этой ситуации есть очень элегантный выход: воспользоваться массивом компонентов. В общем виде объявление массива компонентов может выглядеть так: имя_переменной:array[нижний_индекс..верхний_индекс] of тип_компонента. Теперь поупражняемся в этом. Создайте новое приложение. На форму поместите только кнопку. Обработчик события OnClick которой у меня получился таким: Ну как?! Иногда воспользоваться массивом компонентов очень даже удобно, потому что в массиве обращение к его элементам происходит по индексу, а в обычной ситуации обращение происходит по имени компонента, что не всегда удобно.
Дельфи имеет открытую архитектуру - это значит, что каждый программист волен усовершенствовать эту среду разработки, как он захочет. К стандартным наборам компонентов, которые поставляются вместе с Дельфи можно создать еще массу своих интересных компонентов, которые заметно упростят вам жизнь (это я вам гарантирую). А еще можно зайти на какой-нибудь крутой сайт о Дельфи и там скачать кучу крутых компонентов, и на их основе сделать какую-нибудь крутую прогу. Так же компоненты освобождают вас от написания "тысячи тонн словесной руды". Пример: вы создали компонент - кнопку, при щелчке на которую данные из Memo сохранятся во временный файл. Теперь как только вам понадобится эта функция вы просто ставите этот компонент на форму и наслаждаетесь результатом. И не надо будет каждый раз прописывать это, для ваших новых программ - просто воспользуйтесь компонентом.
Шаг 1. Придумывание идеи
Первым шагом нужно ответить себе на вопрос: "Для чего мне этот компонент и что он будет делать?". Затем необходимо в общих чертах продумать его свойства, события, на которые он будет реагировать и те функции и процедуры, которыми компонент должен обладать. Затем очень важно выбрать "предка" компонента, то есть наследником какого класса он будет являться. Тут есть два пути. Либо в качестве наследника взять уже готовый компонент (то есть модифицировать уже существующий класс), либо создать новый класс.
- Создание Windows-элемента управления (TWinControl)
- Создание графического элемента управления (TGraphicControl)
- Создание нового класса или элемента управления (TCustomControl)
- Создание невизуального компонента (не видимого) (TComponent)
Невизуальные компоненты видны только во время разработки приложения (Design-Time), а во время работы приложения (Run-Time) их не видно, но они могут выполнять какую-нибудь работу. Наиболее часто используемый невизуальный компонент - это Timer.
Итак, что бы приступить от слов к делу, попробуем сделать какой-нибудь супер простой компонент (только в целях ознакомления с техникой создания компонентов), а потом будем его усложнять.
Шаг 2. Создание пустого модуля компонента
Рассматривать этот шаг я буду исходя из устройства Дельфи 3, в других версиях этот процесс не сильно отличается. Давайте попробуем создать кнопку, у которой будет доступна информация о количестве кликов по ней.
- Закройте проекты, которые вы разрабатывали (формы и модули)
- В основном меню выберите Component -> New Component.
- Перед вами откроется диалоговое окно с названием "New Component"
- В поле Ancestor Type (тип предка) выберите класс компонента, который вы хотите модифицировать. В нашем случае вам надо выбрать класс TButton
- В поле Class Name введите имя класса, который вы хотите получить. Имя обязательно должно начинаться с буквы "T". Мы напишем туда, например, TCountBtn
- В поле Palette Page укажите имя закладки на которой этот компонент появиться после установки. Введем туда MyComponents (теперь у вас в Делфьи будет своя закладка с компонентами!).
- Поле Unit File Name заполняется автоматически, в зависимости от выбранного имени компонента. Это путь куда будет сохранен ваш модуль.
- В поле Search Path ничего изменять не нужно.
- Теперь нажмите на кнопку Create Unit и получите следующее:
Шаг 3. Начинаем разбираться во всех директивах
Что же здесь написано? да собственно пока ничего интересного. Здесь объявлен новый класс TCountBtn и процедура регистрации вашего компонента в палитре компонентов.
Директива Private. Здесь вы будете писать все скрытые поля которые вам понадобятся для создания компонента. Так же в этой директиве описываются процедуры и функции, необходимые для работы своего компонента, эти процедуры и функции пользователю не доступны. Для нашего компонент мы напишем туда следующее (запись должна состоять из буквы "F" имени поля: тип этого поля): Буква "F" должна присутсвовать обязательно. Здесь мы создали скрытое поле Count, в котором и будет храниться число кликов по кнопке.
Директива Protected. Обычно я здесь пишу различные обработчики событий мыши и клавиатуры. Мы напишем здесь следующую строку:
Это указывает на то, что мы будем обрабатывать щелчок мыши по компоненту. Слово "override" указывает на то, что мы перекроем стандартное событие OnClick для компонента предка.
Шаг 4. Пишем процедуры и функции.
Начнем с написания конструктора. Это делается примерно так: Здесь в принципе понимать ничего не надо. Во всех своих компонентах я писал именно это (только класс компонента менял и все). Также сюда можно записывать любые действия, которые вы хотите сделать в самом начале работы компонента, то есть в момент установки компонента на форму. Например можно установить начальное значение нашего свойства Count. Но мы этого делать не будем.
Теперь мы напишем процедуру обработки щелчка мышкой по кнопке: "Inherited click" означает, что мы повторяем стандартные методы обработки щелчка мышью (зачем напрягаться и делать лишнюю работу:)).
И если вы все поняли и сделали правильно, то у вас должно получится следующее: Скорее сохраняйтесь, дабы не потерять случайным образом байты набранного кода:)).
Шаг 5. Устанавливаем компонент
Если вы сумели написать и понять, все то что здесь предложено, то установка компонента не должна вызвать у вас никаких проблем. Все здесь делается очень просто. В главном меню выберите пункт Component -> Install Component. перед вами открылось диалоговое окно Install Component. В нем вы увидите две закладки: Into exsisting Package и Into new Package. Вам предоставляется выбор установить ваш компонент в уже существующий пакет или в новый пакет соответственно. Мы выберем в уже существующий пакет.
В поле Unit File Name напишите имя вашего сохранненого модуля (естественно необходимо еще и указать путь к нему), а лучше воспользуйтесь кнопкой Browse и выберите ваш файл в открывшемся окне.
В Search Path ничего изменять не нужно, Делфьи сама за вас все туда добавит.
В поле Package File Name выберите имя пакета, в который будет установлен ваш компонент. Мы согласимся с предложенным по умолчанию пакетом.
Создание свойств своего типа
Теперь мы попробуем создать свойство нестандартного типа. Рассмотрим это на примере метки - TLabel. У этого компонента есть такое свойство: Alignment. Оно может принимать следующие значения: taLeftJustify, taCenter, taRightJustify. Приступаем к созданию свойства. Ничего интересного мне придумать не удалось, но тем не менее я вам покажу это на примере того свойства, которое я придумал. Оно очень простое и поможет вам разобраться. Свойство будет называться ShowType (тип TShowTp), в нашем компоненте оно будет отвечать за отображение свойства Count. Если пользователь установит свойство ShowType в Normal, то кнопка будет работать, как и работала. А если пользователь присвоит этому свойтсву значение CountToCaption, то количество кликов, будет отображаться на самой кнопке.
Для начале нам необходимо объявить новый тип. Описание типа нужно добавить после слова Type. Вот так это выглядело вначале: Вот так это должно выглядеть: Здесь мы объявили новый тип TShowTp, который может принимать только два значения. Все значения, которые вы хотите добавить перечисляются через запятую.
Теперь нам понадобиться создать поле этого типа. Это мы уже умеем и делать и поэтому не должно вызвать никаких сложностей. В директиву Private напишите: Мы создали поле ShowType, типа TShowTp.
Конечно же необходимо добавить это свойство в инспектор объектов: Ну и наконец, чтобы наш компонент реагировал на изменение этого свойства пользователем надо слегка изменить обработчик события OnClick. После небольшой модификации он может иметь примерно такой вид: Объясню что произошло. Вначале мы увеличиваем счетчик на единицу. Затем проверяем какое значение имеет свойство ShowType. Если Normal, то ничего не делаем, а если CountToCaption, то в надпись на кнопке выводим количество кликов. Не так уж и сложно как это могло показаться с первого раза.
Имплантируем таймер в компонент
Очень часто бывает, что вам необходимо вставить в компонент, какой-нибудь другой компонент, например, таймер. Как обычно будем рассматривать этот процесс на конкретном примере. Сделаем так, что через каждые 10 секунд значение счетчика кликов будет удваиваться. Для этого мы встроим таймер в нашу кнопку. Нам понадобиться сделать несколько несложных шагов.
После раздела uses, где описаны добавленные в программу модули, объявите переменную типа TTimer. Назовем ее Timer. Приведу небольшой участок кода: Дальше в директиву Protected необходимо добавить обработчик события OnTimer для нашего таймера. Это делается так: Поскольку наш таймер это не переменная, а компонент, его тоже надо создать, для этого в конструктор нашей кнопки напишем: Здесь создается экземпляр нашего таймера и его свойству Iterval (измеряется в миллисекундах) присваивается значение 10000 (то есть 10 секунд если по простому).
Собственно осталось написать саму процедуру OnTimer. Я сделал это так:
Вот примерно то, что у вас должно получиться в конце: Если у вас что-то не сработало, то в начале проверьте все ли у вас написано правильно. Затем проверьте может у вас не хватает какого-нибудь модуля в разделе Uses.
Переустановка компонента
Очень часто бывает необходимо переустановить ваш компонент. Если вы попробуете сделать это путем выбора Component->Install Component, то Дельфи вас честно предупредит о том, что пакет уже содержит модуль с таким именем. Перед вами открывается окно с содержимым пакета. В нем вы должны найти имя вашего компонента и удалить его (либо нажать кнопочку Remove). Теперь в пакете уже нет вашего компонента. Затем проделайте стандартную процедуру по установке компонента.
Дельфи имеет открытую архитектуру - это значит, что каждый программист волен усовершенствовать эту среду разработки, как он захочет. К стандартным наборам компонентов, которые поставляются вместе с Дельфи можно создать еще массу своих интересных компонентов, которые заметно упростят вам жизнь (это я вам гарантирую). А еще можно зайти на какой-нибудь крутой сайт о Дельфи и там скачать кучу крутых компонентов, и на их основе сделать какую-нибудь крутую прогу. Так же компоненты освобождают вас от написания "тысячи тонн словесной руды". Пример: вы создали компонент - кнопку, при щелчке на которую данные из Memo сохранятся во временный файл. Теперь как только вам понадобится эта функция вы просто ставите этот компонент на форму и наслаждаетесь результатом. И не надо будет каждый раз прописывать это, для ваших новых программ - просто воспользуйтесь компонентом.
Первым делом нужно ответить себе на вопрос: "Для чего мне этот компонент и что он будет делать?". Затем необходимо в общих чертах продумать его свойства, события, на которые он будет реагировать и те функции и процедуры, которыми компонент должен обладать. Затем очень важно выбрать "предка" компонента, то есть наследником какого класса он будет являться. Тут есть два пути. Либо в качестве наследника взять уже готовый компонент (то есть модифицировать уже существующий класс), либо создать новый класс. Для создания нового класса можно выделить 4 случая:
Создание Windows-элемента управления (TWinControl)
Создание графического элемента управления (TGraphicControl)
Создание нового класса или элемента управления (TCustomControl)
Создание невизуального компонента (не видимого) (TComponent)
Теперь попробую объяснить что же такое визуальные и невизуальные компоненты. Визуальные компоненты видны во время работы приложения, с ними напрямую может взаимодействовать пользователь, например кнопка Button - является визуальным компонентом. Невизуальные компоненты видны только во время разработки приложения (Design-Time), а во время работы приложения (Run-Time) их не видно, но они могут выполнять какую-нибудь работу. Наиболее часто используемый невизуальный компонент - это Timer.
Итак, что бы приступить от слов к делу, попробуем сделать какой-нибудь супер простой компонент (только в целях ознакомления с техникой создания компонентов), а потом будем его усложнять.
Создание пустого модуля компонента шаг я буду исходя из устройства Дельфи 7, в других версиях этот процесс не сильно отличается. Давайте попробуем создать кнопку, у которой будет доступна информация о количестве кликов по ней. Чтобы приступить к непосредственному написанию компонента, вам необходимо сделать следующее:
Закройте проекты, которые вы разрабатывали (формы и модули) В основном меню выберите Component -> New Component.
Перед вами откроется диалоговое окно с названием "New Component" В поле Ancestor Type (тип предка) выберите класс компонента, который вы хотите модифицировать. В нашем случае вам надо выбрать класс TButton В поле Class Name введите имя класса, который вы хотите получить. Имя обязательно должно начинаться с буквы "T". Мы напишем туда, например, TCountBtn В поле Palette Page укажите имя закладки на которой этот компонент появиться после установки. Введем туда MyComponents (теперь у вас в Делфьи будет своя закладка с компонентами!). Поле Unit File Name заполняется автоматически, в зависимости от выбранного имени компонента. Это путь куда будет сохранен ваш модуль. В поле Search Path ничего изменять не нужно. Теперь нажмите на кнопку Create Unit и получите следующее: Что же здесь написано? да собственно пока ничего интересного. Здесь объявлен новый класс TCountBtn и процедура регистрации вашего компонента в палитре компонентов.
Директива Private. Здесь вы будете писать все скрытые поля которые вам понадобятся для создания компонента. Так же в этой директиве описываются процедуры и функции, необходимые для работы своего компонента, эти процедуры и функции пользователю не доступны. Для нашего компонент мы напишем туда следующее (запись должна состоять из буквы "F" имени поля: тип этого поля): Буква "F" должна присутсвовать обязательно. Здесь мы создали скрытое поле Count, в котором и будет храниться число кликов по кнопке. Директива Protected. Обычно я здесь пишу различные обработчики событий мыши и клавиатуры. Мы напишем здесь следующую строку: Это указывает на то, что мы будем обрабатывать щелчок мыши по компоненту. Слово "override" указывает на то, что мы перекроем стандартное событие OnClick для компонента предка.
Для создания формы нам понадобится переменная MyForm: TForm. Создадим форму: MyForm := TForm.Create( Self ). Теперь MyForm это форма, с которой можно делать все, что душе угодно. А нашей душе угодно получше эту форму оформить. Для этого проинициализируем некоторые ее свойства (MyForm.Width, MyForm.Height, MyForm.Caption и т.д.). После инициализации показываем форму: MyForm.ShowModal. На практике это будет выглядеть примерно так.
В этом примере мы создали обработчик события OnClose. Это сделано для того, чтобы после закрытия нашей формы список TList освобождался. Проще всего этот (и все другие) обработчик сделать следующим образом: создать обработчик OnClose для главной формы Form1, а затем просто переименовать его.
Теперь о списке TList, зачем он нужен? TList - это "объект-контейнер", который может хранить в себе кучу других объектов. Точнее сказать, он хранит только ссылки на эти объекты, но это не главное. Главное - TList позволяет хорошо управлять хранящимися в нём объектами. На форме мы будем создавать кнопки, для каждой из которых будем создавать обработчик события OnClick. Вернее сказать, обработчик будет один для всех созданных кнопок. При создании кнопки, мы поместим указатель на нее в список TList, а свойству Tag созданной кнопки присвоим ее индекс в списке TList. Что это за свойство Tag? Это просто целое значение, которое можно использовать по своему усмотрению. Это абсолютно не влияет на сам компонент, а этот индекс нам пригодится.
Обработчик OnClick для кнопки выглядит следующим образом.
Здесь мы выводим Caption кнопки, по которой кликнули. Но как узнать, какая кнопка была нажата? Для этого воспользуемся TButton( Sender ).Tag (помните, в свойстве Tag мы сохраняли индекс кнопки в TList). Мы обращаемся к ячейке TList, индекс которой хранится в свойстве Tag, и получаем из этой ячейки указатель на кнопку, по которой щелкнули.
Иногда может понадобиться удалить один или несколько динамически созданных компонентов. Допустим мы создали на форме кнопку с заголовком "Del my".
Для ее удаления напишем следующий код:
Здесь мы в цикле перебираем все компоненты на форме, проверяя каждый найденный на принадлежность к классу TButton (if Components[i] is TButton). Если принадлежит, проверяем заголовок, и в случае совпадения удаляем кнопку.
Вот в принципе и все. Полностью код данного примера вы можете посмотреть в исходниках, прилагающихся к данной статье (исходники прокомментированы, так что разберетесь без проблем). Удачи в программировании!
Читайте также: