26.01.2022

Среда Delphi и простейшее приложение. Создание, удаление и проверка на наличие папки в Delphi


Разработка программного обеспечения для ОС Windows и иных популярных может осуществляться посредством самых разных типов инструментов. В числе тех, что характеризуются большой популярностью в среде российских и зарубежных программистов, — программа Delphi. Какова специфика данного инструмента разработки? Каковы наиболее примечательные его возможности?

Общие сведения о Delphi

Delphi — среда разработки прикладных программ, которые предназначены для запуска в ОС Windows, MacOS, а также в мобильных операционных системах — iOS и Android. Характеризуется простотой языка и процедур генерации кода.

При необходимости обеспечивает низкоуровневую коммуникацию с ОС и библиотеками, составленными на языках C и C++. Программы, которые создаются с помощью Delphi, не требуют сторонних оболочек для запуска — таких как, например, Java Virtual Machine. Delphi — среда разработки, которая может успешно применяться как профессионалами, так и в учебных целях. Для того чтобы освоить базовые ее возможности, необязательно обладать высокой квалификацией и знанием сложных языков программирования.

Основные преимущества

Изучим то, каковы ключевые преимущества программного продукта, о котором идет речь. Когда в той или иной IT-компании осуществляется обоснование выбора среды разработки, Delphi становится выбором многих программистов и рекомендуется ими к использованию. Это связано с тем, что данная среда позволяет создавать приложения в самые оперативные сроки, обеспечивать их высокую производительность даже на тех компьютерах, которые имеют скромные аппаратные характеристики. Значимый аргумент в пользу выбора рассматриваемой среды разработки — ее можно дополнять за счет новых инструментов, не предусмотренных стандартным набором решений, присутствующим в интерфейсе Delphi.

Изучим теперь то, каковы нюансы практического пользования возможностями Delphi.

Специфика интерфейса

Прежде всего можно обратить внимание на некоторые особенности интерфейса рассматриваемой среды разработки ПО. Так, структура рабочего пространства программы предполагает одновременную работу с несколькими основными окнами. Рассмотрим данное свойство подробнее.

Среда разработки Delphi, 7 версии в частности, предполагает задействование следующих ключевых модулей: дизайнера форм, редактора, палитры, инспектора объектов, а также справочника. В некоторых модификациях Delphi отмеченные компоненты могут именоваться иначе. Например, редактору может соответствовать окно кода программы, дизайнеру — окно формы. Однако функциональное назначение их будет тем же самым. Отмеченные Delphi могут дополнять различные вспомогательные инструменты. Основными с точки зрения процедур разработки программ считаются первые два. Но важны также и остальные. Рассмотрим особенности пользования отмеченными модулями Delphi.

Дизайнер форм, редактор и палитра

С помощью дизайнера форм разработчик создает интерфейс своей программы. В свою очередь, в редакторе пишется ее код. Многие программисты, которые рекомендуют сделать выбор среды разработки Delphi как самого оптимального решения, в качестве аргумента приводят простоту пользования дизайнером форм. Некоторые специалисты считают, что этот процесс и вовсе больше похож на игру.

Как только пользователь начинает создавать программу и запускает дизайнер форм, то изначально в нем нет никаких элементов, он пустой. Но его тут же можно заполнить с помощью инструментов, расположенных на другом модуле Delphi — палитре. Элементы интерфейса программы, которые настраиваются в дизайнере форм, должны управляться командами, которые, в свою очередь, пишутся в редакторе.

Но вернемся пока что к палитре. С помощью нее можно размещать в области дизайнера форм нужные объекты. Для того чтобы использовать тот или иной инструмент, следует щелкнуть один раз на нем — пока он в области палитры, второй раз — в окне дизайнера форм. После этого соответствующий объект переместится в область разработки, и для него можно прописывать код в редакторе.

Инспектор объектов

Другой значимый элемент, который содержит Delphi — среда разработки приложений для ОС Windows и иных распространенных платформ — инспектор объектов. Можно отметить, что информация, отображаемая в нем, меняется: на это влияет статус объекта, который выбран в области дизайнера форм.

Структура инспектора объектов такова. Он состоит из двух окон. На каждом фиксируются алгоритмы, определяющие поведение соответствующих компонентов. В первом отображаются свойства, во втором — события. Если программист желает внести корректировки в алгоритмы, влияющие на конкретный компонент, то задействуются возможности инспектора объектов. Так, например, можно менять позиционирование тех или иных элементов интерфейса программ, их высоту и ширину.

В инспекторе объектов есть закладки, с помощью которых можно переключаться между страницами, отражающими свойства или события, которые непосредственно связаны с редактором. Так, если два раза щелкнуть на правой части какого-либо из отображаемых на экране пунктов, то код, который соответствует тому или иному событию, зафиксируется в редакторе.

Разработка программного обеспечения в Delphi предполагает использование инспектора объектов для решения самых разных задач. Это предопределяется тем, что с помощью данного инструмента можно изменять свойства фактически любых объектов, расположенных на форме, а также ее самой. Изучим подробнее некоторые особенности работы с инспектором объектов.

Инспектор объектов: использование возможностей

Для того чтобы понять, как функционирует интегрированная среда разработки Delphi в части взаимодействия инспектора объектов и форм, можно попробовать внести изменения в свойства некоторых распространенных элементов интерфейса ПО в Windows — например, Memo, Button и Listbox (чуть позже мы исследуем их сущность подробнее). Для начала их нужно разместить на форме, используя доступные средства Delphi.

Можно попробовать поэкспериментировать со свойством Ctl3D. Для этого нужно щелкнуть мышкой на форме, после чего перейти в инспектор объектов и изменить значение рассматриваемого свойства. После этого форма значительно изменит Одновременно свойство Ctl3D будет изменено на каждом из элементов, что размещены в окне разработки.

После произведенных экспериментов мы можем вновь перейти на форму и активизировать значение Ctl3D. После этого обратимся к элементам Memo и Listbox. Теперь можно изменять их свойства, расположение на форме, внешний вид. Например, выбрав в пункте меню опцию Edit, а затем — Size, программист может изменить ширину и высоту объектов. Есть вариант расположить их по центру, выбрав Edit и Align. Соответствующие действия повлияют на элементы, отображаемые в инспекторе объектов.

С помощью рассматриваемого модуля Delphi можно осуществлять изменение свойств компонентов. Так, например, если стоит задача определить для них конкретный цвет, то есть варианты задействования сразу нескольких инструментов. Во-первых, можно ввести команду, соответствующую цвету - например, красному - clRed, - в область Во-вторых, пользователь может выбрать нужный цвет из списка. В-третьих, есть вариант два раза щелкнуть мышью на свойствах Color — появится окно выбра цвета. Аналогично разработчик может менять и иные атрибуты объектов — к примеру, тип шрифта, его цвет или размер.

Справочник

Delphi — среда разработки, которая дополнена достаточно подробной справочной системой. Для того чтобы обратиться к ней, следует выбрать в меню пункт Help. После этого в окне отобразится один из отмеченных нами выше программных модулей рассматриваемой среды разработки — справочник. Особенность пользования им в том, что при нажатии F1 пользователь получит конкретную подсказку, отражающую специфику задействования текущего инструмента. Например, если программист работает с инспектором объектов, то он может выбрать одно из свойств, после чего нажать на F1 и получить справочную информацию о соответствующей опции. То же самое можно делать при работе с любым другим элементом интерфейса, который включает в себя среда разработки Delphi 7 и иные версии соответствующего типа ПО.

Прочие элементы интерфейса

В числе иных значимых компонентов интерфейса рассматриваемого программного решения — меню, панель быстрого доступа, а также редактор изображений. Касательно меню — оно позволяет программисту получать быстрый доступ к нужным компонентам, присутствующим в структуре среды разработки. Пользоваться им можно как с помощью мыши, так и при задействовании горячих клавиш. Чуть ниже меню располагается панель быстрого доступа. Некоторые из ее функций дублируют те, что характерны для меню, но доступ к ним осуществляется быстрее. Delphi в чем-то похож на программу Paint в Windows. То есть с помощью него можно производить простейшие корректировки картинок, наносить на них надписи и иные элементы.

Средства программирования

Delphi — среда разработки, которая включает большое количество инструментов, призванных повысить эффективность работы программиста. Так, рассмотренные нами выше ключевые модули дополняются набором из специальных инструментов. В числе таковых: отладчик, компилятор, а также компоненты WinSight и WinSpector. Отметим, что в некоторых версиях Delphi отмеченные элементы нужно инсталлировать отдельно. Изучим их специфику.

Отладчик Delphi

Касательно отладчика — данный инструмент дополняет редактор кода в части проведения необходимой проверки соответствующих программных алгоритмов на предмет корректности. С помощью него разработчик может фактически построчно исследовать свой исходник. В некоторых случаях при решении такой задачи, как разработка компонентов, Delphi как самостоятельный продукт может быть дополнен внешним отладчиком, который дает программисту расширенные возможности проверки кода создаваемого ПО.

Компилятор Delphi

Изучим теперь специфику компилятора рассматриваемой среды разработки. Отметим, что в структуре Delphi может присутствовать несколько соответствующих элементов. Так, есть вариант задействовать компилятор DCC, который полезен в тех случаях, когда стоит задача по работе с приложением во внешнем отладчике.

Winsight и WinSpector

Указанные модули относятся к тем, что нужно устанавливать на Delphi дополнительно. Характеризуются относительной сложностью в освоении. Однако многие программисты, осуществившие выбор среды разработки Delphi, считают, что данными компонентами обязательно нужно учиться пользоваться. Так, модуль Winsight используется с целью наблюдения за сообщениями Windows. Такой компонент, как WinSpector, нужен для того, чтобы фиксировать состояние компьютера в специальном файле. Если в ходе разработки ПО будут наблюдаться какие-либо сбои, то всегда можно открыть этот файл и посмотреть, что могло быть причиной неполадки.

Стандартные компоненты

Среда разработки Delphi, общие сведения о которой мы изучаем, включает ряд стандартных компонентов, о которых также полезно знать. Специалисты относят к таковым следующие: MainMenu, PopupMenu, Label, Edit, Memo, Button, Checkbox, Radiobutton, Listbox, Combobox, Scrollbar, Groupbox, Panel, а также Scrollbox. Изучим их специфику подробнее.

Компонент MainMenu предназначен для размещения главного меню в интерфейсе создаваемой программы. Для этого нужно поместить соответствующий элемент на форме, после чего вызвать свойство Items через инспектора объектов, а затем определить необходимые пункты меню.

Компонент PopupMenu предназначен для размещения всплывающих меню в интерфейсе создаваемой программы, то есть открывающихся с помощью щелчка правой кнопкой мыши.

Компонент Label задействуется с целью отображения текста в окне программы. Его можно настраивать, например задавать нужный шрифт в инспекторе объектов.

Компонент Edit задействуется с целью отображения на экране фрагмента текста, который пользователь может редактировать в то время, как программа работает. Его дополняет компонент Memo, с помощью которого, в свою очередь, можно работать с текстами большего объема. Данный элемент включает, например, такие опции, как копирование текста.

Компонент Button предназначен для выполнения тех или иных действий посредством нажатия кнопки в то время, как программа работает. Необходимо разместить соответствующий элемент на форме, после чего вписать нужный программный код.

Компонент Checkbox позволяет отображать на экране строки с небольшим окошком, в котором может ставиться галочка с помощью мыши. Похожий элемент — Radiobutton. Различаются они, во-первых, внешним видом — второй компонент выполняется в виде кружка, а во-вторых, первый элемент разрешает одновременный выбор нескольких опций, Radiobutton — только одной.

Компонент Listbox используется для отображения на экране списка, который пользователь может прокручивать с помощью мыши. Чем-то похож на него другой элемент — Combobox, однако он дополняется возможностью вводить текст в специальном поле.

Компонент Scrollbar — это полоса прокрутки в окнах. Как правило, появляется автоматически, как только текстовое пространство или форма с объектами становятся больше, чем окно.

Компонент Groupbox задействуется для того, чтобы фиксировать порядок перемещения между окнами при нажатии клавиши TAB. Может дополняться элементом Panel, с помощью которого может осуществляться перемещение нескольких объектов на форме.

Компонент Scrollbox позволяет зафиксировать на форме область, которую можно прокручивать как горизонтально, так и вертикально. Данным свойством характеризуются основные окна разработки Delphi по умолчанию. Но если есть необходимость в задействовании подобной опции на конкретном участке формы, можно воспользоваться компонентом Scrollbox.

Резюме

Delphi — среда разработки приложений с большими возможностями, в то же время характеризующаяся простотой использования основных функций. С помощью инструментов, которые входят в ее структуру, можно создавать самые разные типы программ для Windows и иных популярных ОС.

Выбор средств разработки Delphi многие программисты обуславливают удобством пользования интерфейсами соответствующего ПО, а также широким набором инструментов, полезных для работы на любом участке создания программы — на этапе дизайна, программирования алгоритмов или отладки.

Профессиональная разработка приложений с помощью Delphi 5 | Средства разработки | КомпьютерПресс 2"2001

Создание компонентов Delphi

Введение в создание компонентов Delphi

При разработке приложений с помощью Borland Delphi создавать компоненты удобно по следующим причинам:

  1. Простота использования . Компонент помещается на форму, и для него необходимо устанавливать значения свойств и писать код обработчиков событий. Поэтому если в проекте какое-либо сочетание элементов управления и обработчиков связанных с ними событий встречается в двух местах, то имеет смысл подумать о создании соответствующего компонента. Если же сочетание элементов управления и обработчиков связанных с ними событий встречается более двух раз, то создание компонента гарантированно сэкономит усилия при разработке приложения.
  2. Простая организация групповой разработки проекта . При групповой разработке отдельные части проекта можно определить как компоненты и поручить эту работу разным программистам. Компоненты можно отладить отдельно от приложения, что сделать достаточно легко.
  3. Простой и эффективный способ обмена кодом с другими программистами. Имеется немало сайтов, например http://www.torry.net/ , где можно найти свободно распространяемые компоненты или приобрести их за символическую плату.

Пакеты компонентов

В Delphi компоненты хранятся в пакетах (packages). Список используемых пакетов компонентов можно вызвать с помощью пункта меню Component/Install Packages (правда, этот диалог почему-то имеет заголовок Project Options).

При помощи этого диалога можно добавить новый пакет (Add), удалить имеющийся (Remove). Удаление означает не физическое удаление файла с диска, а удаление ссылки из среды разработки на данный пакет. При добавлении нового пакета компоненты, хранящиеся в нем, появляются на палитре, а при удалении – наоборот, исчезают. Пакет можно не удалять, а «спрятать» его содержимое на этапе разработки посредством снятия отметки напротив имени пакета в списке. Можно также просмотреть компоненты и их пиктограммы (Components). И наконец, можно отредактировать добавленные пользователем пакеты (Edit) – пакеты, поставляемые вместе с Delphi, редактировать нельзя (кнопка Edit недоступна).

В данном диалоге можно указать, каким образом создавать проект: с использованием runtime-пакетов или без них. Отсюда ясно, что пакеты компонентов бывают двух типов: runtime package (пакет, работающий во время выполнения) и design-time package (пакет, используемый во время разработки). Все они представляют собой DLL (динамически загружаемые библиотеки).

Runtime-пакеты (расширение *.bpl) поставляются конечному пользователю вместе с проектом, если проект был скомпилирован с включенной опцией Build with runtime packages. Само приложение (*.exe или *.dll) в этом случае получается небольшим, но вместе с ним надо передавать довольно объемные *.bpl-файлы. Согласно оценкам специалистов поставка проекта с runtime-пакетами дает преимущество в объеме поставляемых файлов, если только он включает пять или более модулей (*.exe или *.dll), написанных на Delphi. При совместной работе этих модулей достигается экономия ресурсов операционной системы, поскольку один загруженный в ОЗУ пакет обслуживает несколько модулей.

Design-time-пакеты (расширение *.dcp) используются только на этапе разработки. Во время разработки они поддерживают создание компонентов на форме. В скомпилированный проект Delphi включает код не из пакета компонентов, а из *.dcu-файлов. Хотя *.dcp-файл генерируется из *.dcu-файла, их содержимое может не совпадать, если в *.pas-файл были внесены изменения и пакет не был перекомпилирован. Компиляция возможна только для пакетов, созданных программистами. Это достигается нажатием кнопки Edit в вышеупомянутом диалоге. После этого появляется форма, которая позволяет производить манипуляции с пакетом.

Пакет содержит две секции. В секции Contains приведен список модулей, формирующих компоненты данного пакета (*.pas- и *.dcu-файлы) и их пиктограммы (*.dcr-файлы). Секция Required содержит ссылки на другие пакеты, необходимые для работы этих компонентов. Добавление нового компонента к пакету выполняется кнопкой Add, удаление имеющегося – кнопкой Remove. До тех пор пока пакет не будет скомпилирован нажатием кнопки Compile, все изменения, вносимые в пакет, не будут появляться в среде разработки. И наконец, команда Install доступна в том случае, когда содержимое пакета удалено из среды разработки посредством снятия отметки напротив имени пакета в предыдущем диалоге.

Команда Option позволяет выбрать для компиляции пакета опции, аналогичные опциям проекта. В них можно определить тип данного пакета: работающий во время выполнения, работающий во время разработки, или тот и другой одновременно (тип пакета по умолчанию). В опциях определяются каталоги, в которых следует искать необходимые модули и сохранять результаты компиляции. В них также определяются действия, необходимые для отладки: проверять или нет диапазон допустимых значений, как осуществлять оптимизацию, как обрабатывать ошибки ввода-вывода. И наконец, в опции может быть включена информация о версии пакета. Это очень важно, если приложение распространяется вместе с runtime-пакетами: при работе программы установки информация о версии позволит корректно заменить устаревшие версии пакетов, и наоборот, при попытке инсталлировать пакет более ранней версии, чем уже имеющийся на данном компьютере, последний не будет перезаписан.

Шаблоны компонентов

Delphi позволяет создавать простейшие составные компоненты из нескольких обычных компонентов, выбранных на форме во время разработки. Соответствующий эксперт вызывается с помощью пункта меню Components/Create Component Template. Этот пункт меню доступен, если на форме выделен хотя бы один компонент. После его выбора появляется диалоговая панель Component Template Information.

В этом диалоге следует указать имя класса и имя страницы на палитре компонентов, куда следует поместить новый компонент. Если страница с данным именем отсутствует на палитре компонентов, то она будет создана. Можно также изменить предложенную пиктограмму нового компонента, загрузив подходящий *.bmp-файл.

При создании шаблона запоминаются как свойства, измененные программистом в инспекторе объектов, так и обработчики событий, связанные с выделенными элементами управления. При этом обработчики событий запоминаются полностью, без фильтрации обращений к другим (не выделенным на форме) компонентам, глобальным переменным, методам и т.д. Соответственно, если в другом проекте такие компоненты (переменные, методы) отсутствуют, то при попытке скомпилировать такой проект будет получено диагностическое сообщение Unknown Identifier.

Когда следует пользоваться шаблонами? Прежде всего, в случаях, если необходимо изменить какие-либо свойства, которые имеются по умолчанию в базовом классе. Например, в каком-либо приложении используется элемент управления для редактирования строки текста желтого цвета. Можно поместить компонент TEdit на форму, изменить свойство Color на желтый, отметить данный компонент и сохранить как шаблон. После этого можно обращаться к данному шаблону, и помещенный на форму компонент будет иметь желтый цвет. Однако не стоит злоупотреблять данной возможностью, ведь для элемента управления с измененным цветом будет создан новый класс и в памяти будут размножены все виртуальные методы. Это отрицательно скажется на ресурсах операционной системы.

Использовать шаблоны компонентов удобно также, когда необходимо перенести ряд компонентов вместе с обработчиками событий с одной формы на другую. Для этого все они выделяются, создается шаблон компонентов, который и помещается на новую форму. При этом будут перенесены не только сами компоненты, но и обработчики событий, чего нельзя достичь при вызове команд Copy/Paste – в последнем случае обработчики событий будут утеряны.

Компоненты, создаваемые при помощи команды Create Component Template, существенно отличаются от обычных компонентов, создаваемых стандартным способом (описанным ниже). Визуально главное различие заключается в следующем: если шаблон включает в себя несколько элементов управления, то, после того как такой компонент помещен на форму, можно выделить отдельный элемент управления и удалить его – при этом остальные сохранятся на форме. Для стандартных компонентов, если они включают в себя несколько элементов управления, невозможно выделить один из них и удалить –компонент выделяется и удаляется целиком.

Создание простейшего компонента

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

Поставим задачу следующим образом. Необходимо создать кнопку, которая будет издавать писк при нажатии, и реализовать ее в виде компонента так, чтобы программист мог поместить ее на форму и воспользоваться ею. Вообще, при рассмотрении компонентов мы довольно часто будем пользоваться простейшими внешними эффектами: писк, вывод сообщения и т.д. При этом подразумевается, что в тех местах, где используются внешние эффекты, может быть помещен любой, достаточно сложный код. Просто в данный момент он нас не интересует.

Создание компонента начинается с выбора пункта меню Component/New components. После этого сразу же появляется диалог New Component.

В этом диалоге необходимо определить класс-предок, имя вновь создаваемого класса, страницу на палитре, куда будет помещен новый компонент, имя модуля, содержащего реализацию нового компонента, и путь к нему. Если новый компонент использует другие модули, путь к которым не описан, то их необходимо определить в поле Search Path.

Итак, первая (и, пожалуй, главная) задача – выбор класса-предка. В выпадающем списке в качестве класса-предка предлагаются все компоненты, имеющиеся на палитре, в том числе и те, которые не входят в стандартную поставку Delphi. Необходимо в качестве класса-предка выбрать класс, который максимально приближен по свойствам к создаваемому классу. Для нашей задачи можно, например, выбрать в качестве предка TWinControl, но в этом случае нам потребуется реализовывать все визуальные эффекты нажатия кнопки и т.д. Поэтому мы выбираем в качестве предка TButton.

Имя вновь создаваемого класса должно отражать содержание компонента и ни в коем случае не совпадать с именем уже зарегистрированного компонента! На этапе заполнения данного диалога имена на совпадения не проверяются – приключения, связанные с такой ошибкой, начнутся позже…

При выборе страницы необходимо знать, что если задать имя несуществующей страницы, то будет создана новая.

И наконец, при нажатии как кнопки Install, так и кнопки OK, будет создана заготовка для реализации нового компонента. Однако при нажатии кнопки Install заготовка будет помещена на палитру компонентов, а при нажатии кнопки OK – просто создана. Рекомендуется пользоваться кнопкой Install. После того как компонент будет инсталлирован, его можно поместить на форму. Теперь все изменения, вносимые в код реализации компонента, будут компилироваться вместе с проектом, и программист сразу же будет получать сообщения об ошибках. Если компонент не инсталлировать, то для поиска ошибок его необходимо компилировать через редактор пакетов (см. выше) нажатием кнопки Compile, что менее удобно.

Итак, после нажатия кнопки Install появляется еще один диалог, который позволяет определить пакет, куда будет помещен данный компонент.

В этом диалоге имеются две страницы, на первой из них можно выбрать один из существующих пакетов, а на второй – создать новый. Весьма желательно давать краткое текстовое описание пакета, именно оно будет показываться в диалоге, вызываемом по команде Component/Install packages (см. выше). После выбора пакета и нажатия клавиши OK вызывается редактор пакета, куда автоматически помещается вновь созданный модуль реализации нового компонента. Полезно не закрывать его, а сдвинуть в один из углов экрана, чтобы он мог быть активирован нажатием клавиши мыши.

Одновременно в редакторе кода будет создана «заготовка» для описания нового компонента:

Unit ButtonBeep; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TButtonBeep = class(TButton) private { Private declarations } protected { Protected declarations } public { Public declarations } published { Published declarations } end; procedure Register; implementation procedure Register; begin RegisterComponents("Samples", ); end; end.

В самом новом классе объявлены четыре секции, значение которых детально описано в разделе «Область видимости переменных и методов» предыдущей статьи данного цикла (КомпьютерПресс № 1"2001). Кроме того, в новом классе определена процедура Register, которая вызывается средой разработки Delphi при инсталляции данного модуля как компонента. Она содержит имя страницы на палитре, куда помещается данный компонент, и в квадратных скобках – имя класса. Вообще, в качестве параметра метод Register принимает массив типов классов, ведь в одном модуле может быть реализовано несколько компонентов. Поэтому они отделяются друг от друга запятой, например:

Procedure Register; begin RegisterComponents("Samples", ); end;

Продолжим решение поставленной задачи – создание кнопки, которая издает писк. Поступим сначала тривиально (но как выяснится потом, неверно) – назначим обработчик события OnClick в конструкторе кнопки. Для этого в секции private определим заголовок нового метода BtClick(Sender:TObject) и реализуем его в секции реализации:

Procedure TButtonBeep.BtClick(Sender:TObject); begin Beep; end;

constructor Create(AOwner:TComponent); override;

с обязательной директивой override! Реализуем его в секции реализации:

Constructor TButtonBeep.Create(AOwner:TComponent); begin inherited Create(AOwner); OnClick:=BtClick; end;

После этого скомпилируем компонент. Поставим со страницы Samples кнопку на форму и запустим проект на выполнение. Можно убедиться, что кнопка при нажатии пищит!

Теперь вновь перейдем в среду разработки и назначим обработчик события OnClick в инспекторе объектов. В обработчике события выведем текст в заголовок формы:

Procedure TForm1.ButtonBeep1Click(Sender:TObject); begin Caption:="Test"; end;

Запустим проект на выполнение и попробуем нажать на кнопку. Заголовок формы меняется, но кнопка пищать перестала! Ошибка заключается в том, что на одно событие кнопки OnClick мы попытались определить два обработчика: один внутри компонента BtClick, а другой назначили с помощью инспектора объектов. После отработки конструктора TButtonBeep у нас была ссылка на первый обработчик BtClick. Затем происходит загрузка ресурсов, обработчику события OnClick назначается метод ButtonBeep1Click. При этом ссылка на первый обработчик - BtClick - безвозвратно теряется.

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

Как же все-таки корректно решить данную задачу? Один из способов создания компонентов - переписывание уже имеющихся методов. При рассмотрении файла StdCtrls.pas, где реализованы исходные коды для компонента TButton, можно отметить в нем наличие динамического метода Click, который можно переписать. Поэтому вновь возвращаемся к исходному коду, созданному экспертом Delphi при создании компонента (убираем конструктор и метод BtClick). Затем в секции public определяем заголовок метода:

Procedure Click; override;

и приводим реализацию метода:

Procedure TButtonBeep.Click; begin inherited Click; beep; end;

Можно убедиться, что кнопка при нажатии издает писк. Кроме того, при назначении обработчика событий в инспекторе объектов этот обработчик выполняется и писк не исчезает! Компонент реализован корректно.

На данном примере полезно проанализировать возможные ошибки при написании кода:

  1. Забытая директива override при определении заголовка метода Click. Кнопка перестает пищать, следовательно, метод Click не вызывается.
  2. Забытый вызов метода-предка (inherited Click) в реализации процедуры Click. Кнопка продолжает пищать при нажатии, но код в назначенном в инспекторе объектов обработчике событий не выполняется. Следовательно, метод Click класса TButton вызывает событие OnClick.

Теперь поменяем пиктограмму компонента TButtonBeep на палитре. По умолчанию для нового компонента используется пиктограмма компонента-предка. Для этого вызовем редактор Image Editor командой Tools/Image Editor. В редакторе вызовем команду File/New/Component Resource File (*.dcr). После команды Resource/New/Bitmap появится диалог, в котором предлагается размер пиктограммы 32х32. Эти размеры по умолчанию следует изменить на 24х24 – такой размер обязаны иметь пиктограммы компонентов! После нажатия кнопки OK следует нарисовать какое-либо изображение при помощи стандартных инструментов, похожих на инструменты редактора Paint. Помните, что цвет левого нижнего пиксела является цветом маски – данный цвет будет «прозрачным».

После этого необходимо переопределить имя ресурса с пиктограммой, по умолчанию его имя ‑ Bitmap1. Новое имя ресурса обязано совпадать с именем класса – в нашем случае TButtonBeep.

Теперь необходимо сохранить файл с пиктограммой в том же самом каталоге, где находится модуль, содержащий процедуру Register для данного компонента, и с тем же самым именем, что и имя модуля. Только вот расширение у файла будет не *.pas, а *.dcr. Файл с пиктограммой компонента готов. Однако если мы посмотрим на палитру компонентов, то увидим, что там по-прежнему сохраняется старая пиктограмма. Если перезагрузить Delphi или даже операционную систему, старая пиктограмма по-прежнему останется на палитре. Для того чтобы поменять пиктограмму, необходима повторная регистрация компонента. Для этого необходимо:

Данный пример следует рассматривать как тестовое упражнение. Перед написанием нового компонента необходимо посмотреть, существуют ли аналогичные среди свободно распространяемых компонентов. Имеются практически любые кнопки: прозрачные, убегающие, круглые, цветные и т.д. Примерно так же обстоит дело с другими компонентами – потомками одного класса. Поэтому чаще всего приходится реализовывать компоненты, состоящие из нескольких элементов управления.

Таким образом, в данном примере мы изучили применение переписывания методов для создания новых компонентов.

Создание сложного компонента

Предположим, в приложении необходимо ввести список фамилий клиентов. В том же самом приложении потребуется и ввод списка телефонов. Ввод списка ‑ довольно распространенная операция, поэтому следует подумать о реализации его в виде компонента.

Для ввода нового элемента в список потребуется редактор – компонент TEdit. Далее пользователь должен иметь возможность просмотреть список – понадобится компонент TListBox. Кроме того, потребуются команды для занесения текущего значения из TEdit в список, редактирование выбранного элемента списка и его удаление. Проще всего эти команды реализовать с помощью кнопок. Для упрощения задачи поместим на форму одну кнопку, при нажатии которой будем добавлять содержимое компонента TEdit в список.

Итак, мы должны создать новый компонент, который включал бы в себя TEdit, TListBox и TButton. Как всегда, начнем его создание с команды Component/New Component. После этого появляется диалог, в котором следует определить класс-предок, имя класса, имя модуля. С именем класса и именем модуля никаких сложностей не возникает, а вот имя класса-предка неясно. У нас имеются три элемента управления. Общим классом-предком для них является TWinControl. Но если в качестве класса-предка выбрать его, нас ожидает очень длительная и утомительная реализация кода TButton, TEdit и TListBox. В таких случаях необходимо в качестве класса-предка выбирать компонент, способный быть «папой» по отношению к другим компонентам. Среди стандартных компонентов, распространяемых вместе с Delphi, таких три: TPanel, TGroupBox, TScrollBox. Выберем в качестве класса-предка панель, но не сам компонент TPanel, а класс TCustomPanel. Преимущества выбора TCustomPanel перед TPanel мы обсудим ниже.

Назовем новый класс именем TListAdd и нажмем кнопку Install. После выбора пакета компонент будет установлен в палитру, откуда его можно поместить на форму вновь созданного приложения. Это удобно, поскольку при компиляции проекта модуль компонента также будет компилироваться и при наличии ошибок компилятор выдаст сообщение.

Было бы удобно поместить наши элементы управления на какую-либо форму и затем создать из них компонент. В стандартной поставке Delphi такой эксперт отсутствует. Поэтому необходимо будет создавать компоненты самим и размещать их на панели. Создание элементов управления – TButton, TEdit и TListBox ‑ разумно выполнить в конструкторе TCustomPanel, для чего, очевидно, необходимо его переписать. Разместим пока элементы управления в квадрате 100х100. Координаты их также необходимо определять в конструкторе. При этом следует иметь в виду, что после отработки конструктора любого элемента управления он еще не имеет родителя, то есть не знает, относительно какого окна ему надо отсчитывать координаты левого верхнего угла. Попытка изменить координаты дочернего окна, у которого отсутствует родитель, немедленно приведет к генерации исключения. Поэтому первым оператором после вызова конструктора элемента управления будет назначение ему родителя, в качестве которого выберем TCustomPanel. Ее же сделаем и их владельцем, в этом случае не понадобится переписывать деструктор.

Итак, в секции uses добавляем модуль StdCtrls, где находятся описания классов TEdit, TButton и TListBox, а в секции private определяем три переменные:

Private FEdit:TEdit; FListBox:TListBox; FButton:TButton;

В секции public объявляем заголовок конструктора с обязательной директивой override:

Constructor Create(AOwner:TComponent); override;

Реализуем конструктор в секции реализации:

Constructor TListAdd.Create(AOwner:TComponent); begin inherited Create(AOwner); FButton:=TButton.Create(Self); FButton.Parent:=Self; FButton.Left:=5; FButton.Top:=5; FButton.Width:=40; FButton.Height:=25; FEdit:=TEdit.Create(Self); FEdit.Parent:=Self; FEdit.Left:=50; FEdit.Top:=5; FEdit.Width:=45; FEdit.Height:=25; FListBox:=TListBox.Create(Self); FListBox.Parent:=Self; FListBox.Left:=5; FListBox.Top:=35; FListBox.Width:=90; FListBox.Height:=60; end;

Еще раз следует подчеркнуть, что деструктор в данном случае переписывать не надо: панель является владельцем всех элементов управления, и при вызове ее деструктора деструкторы элементов управления будут вызваны автоматически.

После перекомпиляции компонента при помощи редактора пакетов изменения в компоненте уже можно увидеть визуально, на этапе разработки.

Первый недостаток, который бросается в глаза, – неадекватное поведение элементов управления при масштабировании компонента. При изменении его размеров размеры и положение элементов не меняются. Кроме того, компонент можно сделать маленьким, так что три элемента управления не уместятся на нем. И наконец, при установке компонента на форму с палитры компонентов простым щелчком мыши его размеры также оставляют желать лучшего.

Для начала исправим размеры компонентов по умолчанию, то есть те, которые ему присваиваются автоматически при щелчке мышью на палитре компонентов с последующим щелчком на форме. Для этого в конструкторе просто следует указать новые размеры панели:

Width:=100; Height:=100;

Затем требуется улучшить поведение компонента при масштабировании. Для этого необходимо получить сообщение о том, что размеры изменились. При изменении размера какого-либо элемента управления система посылает ему сообщение WM_SIZE. Это сообщение необходимо перехватить. Для этого в секции private опишем заголовок перехватчика сообщения:

Procedure WMSize(var Message:Tmessage); message WM_SIZE;

и в секции реализации реализуем его обработчик:

Procedure TListAdd.WMSize(var Message:TMessage); begin inherited; if Width<100 then Width:=100; if Height<100 then Height:=100; FEdit.Width:=Width-55; FListBox.Width:=Width-10; FListBox.Height:=Height-40; end;

Первый оператор – вызов обработчика WM_SIZE по умолчанию (inherited). После его вызова в свойствах Width и Height будут находиться новая ширина и высота панели. После этого определяются минимальные размеры компонента, в данном случае ‑ 100х100. Если размер по горизонтали или вертикали меньше минимального, то ему присваивается минимальное значение. Затем происходит масштабирование элементов управления так, чтобы они заполняли всю панель с небольшими отступами. Скомпилировав компонент через редактор пакетов, можно уже на этапе разработки отметить корректное поведение элементов управления на панели при масштабировании, а также то, что размер компонента нельзя сделать менее чем 100х100.

Теперь полезно будет запустить весь проект на выполнение, попробовать вводить данные в однострочный редактор текста и нажимать кнопку. При этом ничего в список не добавляется. И не удивительно, что нигде в нашем компоненте не указано, что надо делать при нажатии кнопки. Для того чтобы сделать обработчик события, связанного с нажатием кнопки, можно поступить, как при написании компонента TbuttonBeep, то есть определить новый класс ‑ потомок TButton и переписать метод Click. Однако определение нового класса требует системных ресурсов (размножаются виртуальные методы). Если мы отметим компонент на форме и посмотрим на инспектор объектов, то обнаружим, что компонент TlistAdd экспонирует немного свойств и ни одного события, в том числе ни одного обработчика события кнопки OnClick. Поэтому то, что в прошлой главе мы отвергли как неправильный метод,– переопределение обработчика кнопки OnClick в данном случае применимо, поскольку программист не может в инспекторе объектов назначить новый обработчик. Итак, в секции private описываем заголовок нового метода:

Procedure BtClick(Sender:TObject);

В реализации конструктора TListAdd присваиваем этот обработчик обработчику событий FButton.OnClick:

FButton.OnClick:=BtClick;

И наконец, реализуем метод BtClick:

Procedure TListAdd.BtClick(Sender:TObject); begin if length(FEdit.Text)>0 then begin FListBox.Items.Add(FEdit.Text); FEdit.Text:=""; FEdit.SetFocus; end; end;

Сначала проверим, не пуст ли однострочный редактор: мы не будем добавлять в список пустые строки. Затем переносим содержимое редактора в список (FListBox.Items.Add(FEdit.Text);) и подготавливаем редактор к вводу следующего значения – а именно, очищаем его от текста (который уже перенесен в список) и переносим на него фокус ввода. Теперь после компиляции и запуска приложения можно убедиться, что оно работает корректно – при нажатии кнопки содержимое редактора переносится в список.

Добавление свойств и методов

Если рядом с компонентом TListAdd поместить компонент TPanel и сравнить показываемое в инспекторе объектов, то можно отметить, что для панели экспонируется достаточно большое количество свойств и событий, а для TListAdd – только несколько свойств. Между тем класс TCustomPanel является предком обоих компонентов. Для того чтобы понять причину, откроем модуль ExtCtrls.pas и рассмотрим разницу между классами TCustomPanel и TPanel. Можно отметить, что все методы и переменные, которые обеспечивают функциональность панели, определены на уровне класса TCustomPanel. В нем же определены и свойства, которые затем отображаются в инспекторе объектов для TPanel, только эти свойства определены в секции Protected. Реализация же класса TPanel чрезвычайно проста: в качестве предка определяется TCustomPanel, и свойства этого класса редекларируются, но уже в секции published. Становится понятно, что необходимо сделать в классе TListAdd для появления в инспекторе объектов свойств и методов класса TcustomPanel, а именно редекларировать свойства. В секции published класса TListAdd запишем:

Property Align; property OnMouseDown;

При редекларации свойства не требуется указывать его тип и ссылаться на переменные или методы чтения или записи свойства. После компиляции компонента через редактор пакетов в инспекторе объектов можно наблюдать появление свойства Align и события OnMouseDown. Таким образом, для потомков TCustom…-классов программист имеет возможность выбирать, какие свойства и события следует отображать в инспекторе объектов, а какие нет. Именно по этой причине TCustom…-классы рекомендуется использовать в качестве предков для создания компонентов.

Теперь рассмотрим, как можно ввести новое свойство (то, что мы делали выше –редекларация уже имеющихся свойств). В качестве подходящего свойства для отображения в инспекторе объектов можно использовать текст на кнопке: пусть программист, пользующийся компонентом TListAdd, самостоятельно меняет текст на этапе разработки. Попытка ввести новое свойство (назовем его BtCaption) с помощью объявления:

Property BtCaption:string read FButton.Caption write FButton.Caption;

приводит к ошибке при попытке компиляции компонента. Поэтому определим заголовки двух методов в секции private:

Function GetBtCaption:string; procedure SetBtCaption(const Value:string);

В секции published объявим свойство BtCaption:

Property BtCaption:string read GetBtCaption write SetBtCaption;

И наконец, реализуем два объявленных метода в секции реализации:

Function TListAdd.GetBtCaption:string; begin Result:=FButton.Caption; end; procedure TListAdd.SetBtCaption(const Value:string); begin FButton.Caption:=Value; end;

После компиляции компонента с помощью редактора пакетов в инспекторе объектов появляется новое свойство. Изменение значения этого свойства отражается прямо на этапе разработки.

Теперь определим новое событие. В данной задаче было бы разумным создать событие, позволяющее программисту, использующему данный компонент, анализировать текст перед занесением содержимого редактора в список и разрешить или запретить добавление текста в список. Следовательно, этот метод обязан в качестве параметра содержать текущее значение текста в редакторе и зависеть от логической переменной, которой программист может присвоить значение True или False. Кроме того, любой обработчик события в компоненте обязан зависеть от параметра Sender, в котором вызывающий его компонент передает ссылку на самого себя. Это необходимо делать потому, что в среде разработки Delphi один и тот же обработчик события может вызываться из нескольких различных компонентов и программист должен иметь возможность проанализировать, какой именно компонент вызвал обработчик. Итак, после слова type в секции interface перед определением TListAdd определяем новый тип метода:

Type TFilterEvent=procedure(Sender:TObject; const EditText:string; var CanAdd:boolean) of object;

FOnFilter:TFilterEvent;

И в секции published определяем свойство данного типа:

Property OnFilter:TFilterEvent read FOnFilter write FOnFilter;

При определении нового свойства ссылаемся на переменную FOnFilter, а не на методы – они здесь не требуются. Теперь, если скомпилировать компонент с помощью редактора пакетов, можно обнаружить появление в инспекторе объектов события OnFilter. Однако если мы назначим ему обработчик и запустим проект на исполнение, то он может не вызваться. Это происходит потому, что мы нигде его не вызвали в нашем компоненте. Подходящее место для вызова события OnFilter – обработчик события OnClick для FButton, который уже реализован. Поэтому мы изменим код реализации ранее определенного метода BtClick:

Procedure TListAdd.BtClick(Sender:TObject); var CanAdd:boolean; begin if length(FEdit.Text)>0 then begin CanAdd:=True; if Assigned(FOnFilter) then FOnFilter(Self,FEdit.Text,CanAdd); if CanAdd then begin FListBox.Items.Add(FEdit.Text); FEdit.Text:=""; FEdit.SetFocus; end else beep; end; end;

Итак, в приведенном выше фрагменте кода определяется логическая переменная CanAdd. При написании кода следует учитывать, что программист может не сделать обработчик события OnFilter. Поэтому устанавливаем значение переменной CanAdd по умолчанию равным True – все строки добавлять в список. Далее, перед вызовом FonFilter, следует проверить, а сделал ли программист обработчик события. Это достигается вызовом метода Assigned, который возвращает логическое значение. Для указателя вызов метода Assigned эквивалентен проверке P<>nil. Для метода объекта мы не можем использовать проверку FOnFilter<>nil, так как метод объекта характеризуется двумя адресами и такая проверка не будет разрешена компилятором. Но вызов метода Assigned прекрасно проверяет, был ли сделан обработчик события. Вышеприведенный код – абсолютно стандартный способ вызова обработчика событий из компонента.

Осталось протестировать обработчик события. Поместим два компонента TListAdd на форму, для одного разрешим добавление только целых чисел, а для другого – только слов, начинающихся с прописных английских букв. Соответственно код для обработчиков событий OnFilter будет выглядеть следующим образом:

Procedure TForm1.ListAdd1Filter(Sender: TObject; const EditText: String; var CanAdd: Boolean); var I,N:integer; begin Val(EditText,N,I); CanAdd:=I=0; end; procedure TForm1.ListAdd2Filter(Sender: TObject; const EditText: String; var CanAdd: Boolean); begin CanAdd:=False; if length(EditText)>0 then CanAdd:=(EditText>="A") and (EditText<="Z"); end;

Код прост для понимания, единственным его нюансом является проверка того, что текст представляет собой не пустую строку, перед проверкой первой буквы текста в обработчике события ListAdd2Filter. Проведение такой проверки обязательно: строки в Object Pascal ‑ это объекты, и пустой строке соответствует nil-указатель. При попытке проверить первую букву пустой строки приложение попытается дереференсировать nil, что приведет к возникновению исключения. В данном случае это не страшно: перед вызовом обработчика событий FOnFilter из компонента TListAdd проверяется строка на ненулевую длину. Однако для компонентов, исходный текст которых вам недоступен, такая проверка является обязательной!

Скрытие свойств в инспекторе объектов

Предположим, вы делаете компонент для доступа к данным, например, потомок класса TTable. Допустим, в этом компоненте анализируется список таблиц, имеющихся в базе данных, и по каким-либо признакам (например, наличие поля определенного типа и с определенным именем) выбирается одна для работы. Для нормальной работы компонента имя этой таблицы должно заноситься в свойство TableName. Но это свойство отображается в инспекторе объектов! Программист, использующий этот компонент, может изменить его значение на этапе разработки, что, предположим, сделает компонент неработоспособным. И он будет прав! Если какие-то из свойств или событий нельзя изменять, они должны быть скрыты.

Мы продолжим работу над компонентом TListAdd и в качестве модельной задачи уберем из инспектора объектов свойство Cursor. Это свойство определено в секции published в классе TСontrol и отображается в инспекторе объектов для TListAdd с самого начала разработки компонента. Исходя из этого можно попытаться переопределить данное свойство в секции protected. Компилятор разрешит такое переопределение, но к желаемому результату это не приведет: свойство Cursor как было, так и останется в инспекторе объектов… Любое свойство, будучи однажды определенным в секции published, будет всегда отображаться в инспекторе объектов для всех потомков данного класса.

Для скрытия свойства из инспектора объектов используем две возможности компилятора Delphi, а именно:

  1. При объявлении нового свойства с именем, совпадающем с именем уже имеющегося свойства, ранее определенное свойство «затеняется».
  2. Свойства, которые имеют доступ только для чтения или только для записи, не отображаются в инспекторе объектов, даже если они объявлены в секции published.

Перед началом работы по скрытию свойства Cursor полезно удалить компоненты TListAdd с формы, иначе может произойти исключение при чтении ресурса формы. Итак, в секции private объявляем переменную FDummy:integer (имя и тип переменной могут быть любыми) и в секции published определяем новое свойство:

Property Cursor:integer read FDummy;

Новое свойство обязано называться Cursor, тип его обязан совпадать с типом переменной, определенной выше, свойство должно быть только на чтение или только на запись. После компиляции компонента с помощью редактора пакетов следует вновь поместить компонент TListAdd на форму. Можно обнаружить, что свойство Cursor уже не отображается в инспекторе объектов.

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

Cursor:=crHourGlass;

компилятор Delphi выдаст диагностическое сообщение о том, что нельзя назначить новое значение переменной, предназначенной только для чтения. Если сделать новое свойство «только для записи», то компилятор выдаст уже другое диагностическое сообщение – о несопоставимых типах данных. Если же объявить переменную FDummy:TCursor и сделать ее доступной только для записи, то компилятор разрешит данное присвоение, но при этом вид курсора не изменится: он по-прежнему будет стрелкой.

Тривиальное решение данной проблемы – объявить класс-потомок TCustomPanel, в конструкторе которого нужно присвоить новое значение переменной Cursor, а от него уже производить наш компонент TListAdd. У такого решения имеется два недостатка:

  1. Оно ресурсоемко – размножаются виртуальные методы.
  2. Свойство мы прятали в инспекторе объектов от программиста, который будет использовать данный компонент. Мы же хотим работать с данным свойством.

Поэтому решение данной задачи выглядит следующим образом: в конструкторе TListAdd объявляем оператор:

Inherited Cursor:=crHourGlass;

и все! Этого достаточно для изменения курсора.

Ранее мы пользовались служебным словом inherited только для вызова метода предка. Данная конструкция позволяет глубже понять значение inherited как обращение к классу-предку. Можно обращаться и к свойствам, и к методам. При обращении к свойству его можно как читать, так и присваивать ему новое значение; при этом служебное слово inherited стоит слева от знака присваивания. Аналогично можно вызывать скрытые методы предка. Обращения по иерархии выше, чем класс-предок, запрещено - конструкция

Inherited inherited Cursor:=crHourGlass;

не будет скомпилирована.

На этом будем считать данный проект завершенным. В новом компоненте мы перехватили сообщение, редекларировали свойства, добавили новые свойства и события, спрятали ранее объявленное свойство. Все эти способы применяются для создания компонентов. Ниже мы рассмотрим еще один интересный способ.

Использование Hook-процедур для создания компонентов

Ранее уже упоминалось, что каждый потомок TWinControl имеет процедуру, которая принимает и обрабатывает сообщения. Если имеется ссылка на дескриптор окна (HWND), то можно определить адрес этой процедуры и, что более важно, подменить этот адрес и таким образом обрабатывать получаемые сообщения своим способом. Как правило, никто не пишет полностью обработчики всех сообщений; чаще вызывается старый метод по умолчанию. При этом новая процедура используется как фильтр: при поступлении какого-либо события выполняется код. Фактически это «шпион» в TwinControl: нас уведомляют о приходе какого-либо сообщения и можно выполнить какой-либо код. При правильной реализации Hook-процедуры TWinControl продолжает работать как обычно, не подозревая, что своими сообщениями он делится с кем-то еще.

Hook-процедура определяется следующим образом:

Procedure(var Message:TMessage) of object;

Она зависит от переменной типа TMessage, в которой содержится вся информация о сообщении. Но определить эту процедуру – недостаточно. Она должна копироваться для каждого TWinControl, к которому будет присоединена. Это достигается вызовом WinAPI-метода MakeObjectInstance. В качестве параметра этот метод принимает метод объекта, делает его копию в памяти и возвращает адрес нового метода. Понятно, что при этом резервируются системные ресурсы, которые необходимо вернуть системе. Это достигается вызовом метода FreeObjectInstance.

Еще одно важное условие: перед разрушением TWinControl должна быть восстановлена связь со старой процедурой обработки сообщений, иначе ресурсы не будут возвращены системе. Значит, придется запоминать указатель на старую процедуру, который можно узнать вызовом метода Win API GetWindowLong с параметром GWL_WNDPROC. Этот указатель будет использоваться также для вызова обработчиков событий TWinControl по умолчанию. Обратный метод - SetWindowLong - используется для установки Hook-процедуры.

Итак, сформулируем задачу для следующего упражнения. Предположим, мы хотим создать компонент, который будет заставлять пищать при нажатии кнопки мыши другие компоненты – потомки TWinControl. Понятно, что данный компонент не следует показывать во время выполнения приложения, поэтому в качестве его класса-предка выберем TComponent. Имя класса определим как TBeepWnd. В секции private определим три переменные:

FOldProc,FNewProc:pointer; FControl:TWinControl;

Из названий ясно, что мы будем запоминать ссылку на старую процедуру в переменной FOldProc, ссылка на новую процедуру (после выполнения метода MakeObjectInstance) будет храниться в переменной FNewProc. И в переменной FControl будем сохранять ссылку на элемент управления, на который в данный момент «повешена» Hook-процедура. Определим три метода в этой же секции:

Procedure HookProc(var Message:TMessage); procedure HookWindow(W:TWinControl); procedure UnhookWindow;

и в секции implementation реализуем их:

Procedure TBeepWnd.HookProc(var Message:TMessage); begin case Message.Msg of WM_LBUTTONDOWN:begin {Our task} Beep; Message.Result:=CallWindowProc(FOldProc, FControl.Handle, Message.Msg, Message.WParam, Message.lParam); end; WM_DESTROY:begin {When window is about destroying, remove hook} Message.Result:=CallWindowProc(FOldProc, FControl.Handle, Message.Msg, Message.WParam, Message.lParam); UnhookWindow; end; {Call default handler} else Message.Result:=CallWindowProc(FOldProc, FControl.Handle, Message.Msg, Message.WParam, Message.lParam); end; end;

В самой Hook-процедуре перехватывается сообщение, на которое происходит реакция – WM_LBUTTONDOWN. Кроме того, любая Hook-процедура обязана обрабатывать сообщение WM_DESTROY. Это последнее сообщение, которое передается окну перед тем, как оно будет разрушено. Наша реакция – восстановить предыдущий метод вызовом описанного ниже метода UnhookWindow. И наконец, везде вызываются обработчики сообщений по умолчанию посредством метода CallWindowProc. Забыть обработчик события по умолчанию – то же самое, что забыть inherited в обработчике события, в 80% случаев это приведет к некорректному поведению приложения. Ни в коем случае нельзя забывать присваивать результат вызова метода CallWindowProc полю Result переменной Message! Код в этом случае работать не будет!

Procedure TBeepWnd.HookWindow(W:TWinControl); begin if csDesigning in ComponentState then begin {Checking if component at design or run-time} FControl:=W; Exit; end; if FControl<>nil then UnhookWindow; {Remove hook if it was previously installed} if W<>nil then begin FOldProc:=pointer(GetWindowLong(W.Handle,GWL_WNDPROC)); {Determines address of old procedure} FNewProc:=MakeObjectInstance(HookProc); {Make copy in memory} SetWindowLong(W.Handle,GWL_WNDPROC,integer(FNewProc)); {Set new procedure} end; FControl:=W; {Store reference at control} end;

Этот метод используется для установки новой процедуры обработки сообщений. Сначала проверяется, на каком из этапов находится данный компонент: на этапе разработки или на этапе выполнения. Если компонент находится на этапе разработки, то есть выставлен флаг csDesigning в свойстве ComponentState, то сохраняется просто ссылка на компонент без установки Hook-процедуры. Это сделано для того, чтобы избежать установки Hook-процедуры на среду разработки Delphi. Если ранее эта процедура была установлена на другом элементе управления, она снимается посредством вызова метода UnhookWindow. После этого запоминается адрес старой процедуры (GetWindowLong), делается копия в памяти новой процедуры (MakeObjectInstance) и выставляется адрес новой процедуры (SetWindowLong). Используется приведение типов от integer к pointer, и наоборот – вызываемые методы требуют (или возвращают) переменные не совсем подходящих типов. И наконец, ссылка на элемент управления запоминается в переменной FControl, которую мы определили в секции private.

Procedure TBeepWnd.UnhookWindow; begin if (FControl=nil) or (FOldProc=nil) or (FNewProc=nil) then Exit; {No hook was installed} SetWindowLong(FControl.Handle,GWL_WNDPROC,integer(FOldProc)); {Set old window procedure} FreeObjectInstance(FNewProc); {Free resources} FControl:=nil; {Initiate variables} FOldProc:=nil; FNewProc:=nil; end;

Данный метод восстанавливает старый обработчик события. Он вызывается из метода HookProc и должен еще вызываться из деструктора компонента – снимать Hook необходимо как при разрушении окна, так и при разрушении данного компонента. Метод SetWindowLong c адресом старого метода восстанавливает старый обработчик сообщений. После этого следует вернуть ресурсы системе вызовом метода FreeObjectInstance.

Итак, базовые методы для работы с Hook-процедурой определены. Теперь необходимо переписать деструктор, чтобы Hook-процедура снималась при разрушении данного компонента:

Destructor TBeepWnd.Destroy; begin UnhookWindow; inherited Destroy; end;

И наконец, в секции published определим свойство, которое будет отображаться в инспекторе объектов:

property Control:TWinControl read FControl write HookWindow;

Для установки нового компонента ссылаемся на ранее определенный метод, который во время выполнения приложения немедленно «повесит» Hook-процедуру на компонент, который станет пищать при нажатии кнопки. Напомним, что вместо оператора Beep можно написать любой исполняемый код.

Тестируется компонент достаточно просто: ставится на форму, на которую ставятся и несколько компонентов-потомков TWinControl. После выбора на фоне компонента TBeepWnd при щелчке мышью в инспекторе объектов на поле Control разворачивается список, в котором присутствуют все определенные на форме TWinControl. Следует выбрать один из них и запустить приложение. При нажатии левой кнопки мыши на выбранном компоненте он издает писк.

Редакторы свойств и редакторы компонентов

Все, о чем рассказывалось в предыдущих разделах, относится к созданию кода приложения, которое будет распространяться для пользователей. Однако среда разработки Delphi позволяет модифицировать саму себя. Для этого не требуется знаний специального языка, поскольку все методы для изменения среды разработки пишутся на Delphi. Здесь эти методы, а именно редакторы свойств и редакторы компонентов, рассмотрены частично ‑ в плане создания инструментов для работы с компонентами. При чтении материалов данного раздела следует четко понимать, что конечный пользователь, работающий с вашим приложением, никогда не увидит ни редактора свойств, ни редактора компонентов – они создаются для программистов и работают только в среде разработки Delphi.

Редакторы свойств

Во время разработки приложения свойства отображаются в инспекторе объектов. Обратите внимание: свойства в инспекторе объектов редактируются по-разному. Некоторым свойствам (Width, Caption) можно определить только новое текстовое значение. Свойство типа Cursor предоставляет раскрывающийся список, щелкнув по которому можно выбрать значение. Свойство типа TFont имеет знак «+» слева; при щелчке по нему оно разворачивается, давая возможность модифицировать отдельные поля. Кроме того, справа имеется кнопка с тремя точками (elliptic button), при щелчке на которой появляется диалог редактора свойств.

Каждое из вышеперечисленных свойств имеет свой редактор, и большим преимуществом среды разработки Delphi является возможность создать свои редакторы свойств. Новые редакторы свойств довольно часто встречаются среди распространяемых компонентов. Но к ним надо относиться осторожно: первоначально выполнить тесты на компьютере, где при необходимости можно повторно инсталлировать Delphi. Как правило, они создаются квалифицированными программистами и претензий к коду не бывает, но часто забывают включить в распространяемый редактор свойств какую-либо DLL. После инсталляции такого редактора мы получаем ряд свойств, которые невозможно редактировать, – старый редактор перекрыт, а новый не работает…

Перед созданием нового редактора свойств имеет смысл подумать, стоит ли это делать, – среди стандартных редакторов, вероятно, можно найти подходящий. Если же придется делать редактор свойств, необходимо соблюдать правило: следует избегать создания редакторов для стандартных типов данных (integer, string и др.). Другие программисты привыкли к стандартным редакторам, и ваш может им не понравиться. Следовательно, придется проявить скромность и регистрировать редактор для своего класса, а не для класса TComponent. Если ваш редактор свойств понравится программистам, большинство из них смогут сами изменить регистрацию так, чтобы редактор работал для всех компонентов. Вопрос регистрации редактора мы обсудим ниже.

Итак, поставим модельную задачу, для реализации которой необходимо будет реализовать редактор свойств. Предположим, какой-либо компонент имеет свойство ‑ день недели. В принципе, для ввода дня недели можно воспользоваться стандартным редактором с выпадающим списком. Однако мы хотим, чтобы программист на этапе разработки мог вводить день недели, задавая либо его порядковый номер (1 ‑ понедельник, 2 ‑ вторник и т.д.), либо текст на национальном или английском языке. При вводе текста допускается смешение прописные и строчные букв.

Прежде всего необходимо создать компонент, в котором будет храниться день недели. Создадим новый компонент вызовом команды Component/New component. В качестве класса-предка выберем TComponent и дадим новому классу имя TDayStore. После этого установим компонент в палитру. Теперь надо решить, в каком виде хранить день недели. Ясно, что для однозначной идентификации и экономии ресурсов его следует хранить в виде целого числа с допустимыми диапазонами 1‑7. Однако, если мы собрались создавать редактор свойств, следует вспомнить правило о несоздании новых редакторов для уже имеющихся типов. Поэтому определим новый тип – TDayWeek, причем все операции с ним будем производить как с целыми числами. Определим переменную FDay в секции private компонента. Поскольку эта переменная будет инициализироваться значением 0 при отработке конструктора по умолчанию, а это число находится за пределами допустимых значений, необходимо переписать конструктор. В заключение определим свойство DayWeek в секции published для отображения его в инспекторе объектов. Окончательный вариант компонента выглядит следующим образом:

Type TDayWeek=type integer; TDayStore = class(TComponent) private { Private declarations } FDay:TDayWeek; protected { Protected declarations } public { Public declarations } constructor Create(AOwner:TComponent); override; published { Published declarations } property DayWeek:TDayWeek read FDay write FDay; end; … implementation constructor TDayStore.Create(AOwner:TComponent); begin inherited Create(Aowner); FDay:=1; end;

Следует обратить внимание на редкую конструкцию определения нового типа

TDayWeek=type integer;

Таким образом, вводится новый тип данных, который имеет тот же размер, что и тип integer, все операции над этим типом данных осуществляются как с целыми числами. Смысл этой операции – объявить новый тип данных, чтобы наш редактор свойств был применим именно к нему и не затрагивал другие типы данных.

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

Модуль для создания редакторов свойств называется DsgnIntf.pas (Design Interface), в нем определены базовый класс TPropertyEditor и классы-потомки, предназначенные для редакции стандартных свойств – TIntegerProperty, TFloatProperty, TStringProperty и др. Механизм работы редакторов свойств заключается в следующем:

  1. Он регистрируется в среде разработки Delphi вызовом метода RegisterPropertyEditor. В качестве параметров этот метод принимает следующие значения:

    a) информация о типе свойств, для редакции которых предназначен данный редактор. Из-за наличия этой информации нам пришлось определять новый тип TDayWeek;

    b) информация о компоненте, в котором применим данный редактор. Редактор будет вызываться не только для указанного компонента, но и для всех его потомков. Если установить это значение TComponent, редактор будет вызываться для любого компонента;

    c) имя свойства, для которого используется данный редактор. Если имя – пустая строка, используются два вышеупомянутых фильтра;

  2. Вызывается метод GetValue, когда необходимо считать текущее значение свойства из компонента. Этот метод для любого свойства возвращает строку, которая помещается в инспекторе объектов.
  3. Вызывается метод SetValue, когда программист ввел новое значение свойства в инспекторе объектов. В качестве параметра передается новая строка. В методе она должна быть проанализирована и приведена к типу редактируемого свойства.

Методы GetValue и SetValue являются виртуальными, при их переписывании создаются новые редакторы свойств. Итак, теперь можно начать создание нового редактора свойств.

Сошлемся в секции uses модуля DayPropE.pas на модуль DsgnIntf и определим в секции Interface новый класс:

Type TDWPropED=class(TPropertyEditor) public function GetValue:string; override; procedure SetValue(const Value:string); override; end;

В секции реализации следует реализовать оба этих метода. При этом нам дополнительно потребуется список названий дней недели – в начальной постановке задачи требуется, чтобы программист имел возможность вводить день недели:

Const DayWeek:array of string = ("Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"); DayWeekEn:array of string = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");

Почему я сел писать это пособие

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

Все мои готовые компоненты можно найти на сайте http://MihanDelphi.narod.ru

Для чего нужны компоненты

Дельфи имеет открытую архитектуру - это значит, что каждый программист волен усовершенствовать эту среду разработки, как он захочет. К стандартным наборам компонентов, которые поставляются вместе с Дельфи можно создать еще массу своих интересных компонентов, которые заметно упростят вам жизнь (это я вам гарантирую). А еще можно зайти на какой-нибудь крутой сайт о Дельфи и там скачать кучу крутых компонентов, и на их основе сделать какую-нибудь крутую прогу. Так же компоненты освобождают вас от написания "тысячи тонн словесной руды". Пример: вы создали компонент - кнопку, при щелчке на которую данные из Memo сохранятся во временный файл. Теперь как только вам понадобится эта функция вы просто ставите этот компонент на форму и наслаждаетесь результатом. И не надо будет каждый раз прописывать это, для ваших новых программ - просто воспользуйтесь компонентом.

Шаг 1. Придумывание идеи

Первым шагом нужно ответить себе на вопрос: "Для чего мне этот компонент и что он будет делать?". Затем необходимо в общих чертах продумать его свойства, события, на которые он будет реагировать и те функции и процедуры, которыми компонент должен обладать. Затем очень важно выбрать "предка" компонента, то есть наследником какого класса он будет являться. Тут есть два пути. Либо в качестве наследника взять уже готовый компонент (то есть модифицировать уже существующий класс), либо создать новый класс.

Для создания нового класса можно выделить 4 случая:

1. Создание Windows-элемента управления (TWinControl)

2. Создание графического элемента управления (TGraphicControl)

3. Создание нового класса или элемента управления (TCustomControl)

4. Создание невизуального компонента (не видимого) (TComponent)

Теперь попробую объяснить что же такое визуальные и невизуальные компоненты. Визуальные компоненты видны во время работы приложения, с ними напрямую может взаимодействовать пользователь, например кнопка Button - является визуальным компонентом.

Невизуальные компоненты видны только во время разработки приложения (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 и получите следующее:

unit CountBtn;

Uses

StdCtrls;

Type
TCountBtn = class(TButton)

private
{ Private declarations }

protected
{ Protected declarations }

public
{ Public declarations }

published
{ Published declarations }

Procedure Register;

Implementation

Procedure Register;
begin
RegisterComponents("MyComponents", );
end;

Шаг 3. Начинаем разбираться во всех директивах

Что же здесь написано? да собственно пока ничего интересного. Здесь объявлен новый класс TCountBtn и процедура регистрации вашего компонента в палитре компонентов.

Директива Private Здесь вы будете писать все скрытые поля которые вам понадобятся для создания компонента. Так же в этой директиве описываются процедуры и функции, необходимые для работы своего компонента, эти процедуры и функции пользователю не доступны. Для нашего компонент мы напишем туда следующее (запись должна состоять из буквы "F" имени поля: тип этого поля):

FCount:integer;

Буква "F" должна присутсвовать обязательно. Здесь мы создали скрытое поле Count, в котором и будет храниться число кликов по кнопке.

Директива Protected . Обычно я здесь пишу различные обработчики событий мыши и клавиатуры. Мы напишем здесь следующую строку:

procedure Click; override;

Это указывает на то, что мы будем обрабатывать щелчок мыши по компоненту. Слово "override" указывает на то, что мы перекроем стандартное событие OnClick для компонента предка.

В директиве Public описываются те процедуры и функции компонента, которые будут доступны пользователю. (Например, в процессе написания кода вы пишите имя компонента, ставите точку и перед вами список доступных функций, объявленных в диретиве Public). Для нашего компонента, чтобы показать принцип использования этой директивы создадим функцию - ShowCount, которая покажет сообщение, уведомляя пользователя сколько раз он уже нажал на кнопку. Для этого в директиве Public напишем такой код:

procedure ShowCount;

Осталась последняя директива Published. В ней также используется объявления доступных пользователю, свойств и методов компонента. Для того, чтобы наш компонент появился на форме необходимо описать метод создания компонента (конструктор), можно прописать и деструктор, но это не обязательно. Следует обратить внимание на то, что если вы хотите, чтобы какие-то свойства вашего компонента появились в Инспекторе Объектов (Object Inspector) вам необходимо описать эти свойства в директиве Published. Это делается так: property Имя_свойства (но помните здесь букву "F" уже не нужно писать), затем ставиться двоеточие ":" тип свойства, read процедура для чтения значения, write функция для записи значения;. Но похоже это все сильно запутано. Посмотрите, что нужно написать для нашего компонента и все поймете:

constructor Create(aowner:Tcomponent);override; //Конструктор
//Свойство Count

Итак все объявления сделаны и мы можем приступить к написанию непосредственно всех объявленных процедур.

Шаг 4. Пишем процедуры и функции.

Начнем с написания конструктора. Это делается примерно так:

constructor TCountBtn.Create(aowner:Tcomponent);
begin
inherited create(Aowner);
end;

Здесь в принципе понимать ничего не надо. Во всех своих компонентах я писал именно это (только класс компонента менял и все). Также сюда можно записывать любые действия, которые вы хотите сделать в самом начале работы компонента, то есть в момент установки компонента на форму. Например можно установить начальное значение нашего свойства Count. Но мы этого делать не будем.

Теперь мы напишем процедуру обработки щелчка мышкой по кнопке:

procedure Tcountbtn.Click;
begin
inherited click;
FCount:=FCount+1;
end;

"Inherited click" означает, что мы повторяем стандартные методы обработки щелчка мышью (зачем напрягаться и делать лишнюю работу:)).

У нас осталась последняя процедура ShowCount. Она может выглядеть примерно так:

procedure TCountBtn.ShowCount;
begin

end;

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

И если вы все поняли и сделали правильно, то у вас должно получится следующее:

unit CountBtn;

Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;

Type
TCountBtn = class(TButton)
private
{ Private declarations }
FCount:integer;
protected
{ Protected declarations }
procedure Click;override;
public
{ Public declarations }
procedure ShowCount;
published
{ Published declarations }
property Count:integer read FCount write FCount;

end;

Procedure Register;

Implementation

Procedure Register;
begin

end;


begin
inherited create(Aowner);
end;

Procedure Tcountbtn.Click;
begin
inherited click;
FCount:=FCount+1;
end;


begin
Showmessage("По кнопке "+ caption+" вы сделали: "+inttostr(FCount)+" клик(а/ов)");
end;
end.

Скорее сохраняйтесь, дабы не потерять случайным образом байты набранного кода:)).

Шаг 5. Устанавливаем компонент

Если вы сумели написать и понять, все то что здесь предложено, то установка компонента не должна вызвать у вас никаких проблем. Все здесь делается очень просто. В главном меню выберите пункт Component -> Install Component. перед вами открылось диалоговое окно Install Component. В нем вы увидите две закладки: Into exsisting Package и Into new Package. Вам предоставляется выбор установить ваш компонент в уже существующий пакет или в новый пакет соответственно. Мы выберем в уже существующий пакет.

В поле Unit File Name напишите имя вашего сохранненого модуля (естественно необходимо еще и указать путь к нему), а лучше воспользуйтесь кнопкой Browse и выберите ваш файл в открывшемся окне.

В Search Path ничего изменять не нужно, Делфьи сама за вас все туда добавит.

В поле Package File Name выберите имя пакета, в который будет установлен ваш компонент. Мы согласимся с предложенным по умолчанию пакетом.

Теперь нажимаем кнопочку Ok. И тут появиться предупреждение Package dclusr30.dpk will be rebuilt. Continue? Дельфи спрашивает: "Пакет такой-то будет изменен. Продолжить?". Конечно же надо ответить "Да". И если вы все сделали правильно, то появиться сообщение, что ваш компонент установлен. Что ж можно кричать Ура! Это ваш первый компонент.

Создание свойств своего типа

Теперь мы попробуем создать свойство нестандартного типа. Рассмотрим это на примере метки - TLabel. У этого компонента есть такое свойство: Alignment. Оно может принимать следующие значения: taLeftJustify, taCenter, taRightJustify. Приступаем к созданию свойства. Ничего интересного мне придумать не удалось, но тем не менее я вам покажу это на примере того свойства, которое я придумал. Оно очень простое и поможет вам разобраться. Свойство будет называться ShowType (тип TShowTp), в нашем компоненте оно будет отвечать за отображение свойства Count. Если пользователь установит свойство ShowType в Normal, то кнопка будет работать, как и работала. А если пользователь присвоит этому свойтсву значение CountToCaption, то количество кликов, будет отображаться на самой кнопке.

Для начале нам необходимо объявить новый тип. Описание типа нужно добавить после слова Type. Вот так это выглядело вначале:

type
TCountBtn = class(TButton)

Вот так это должно выглядеть:

TShowTp = (Normal, CountToCaption);

TCountBtn = class(TButton)

Здесь мы объявили новый тип TShowTp, который может принимать только два значения. Все значения, которые вы хотите добавить перечисляются через запятую.

Теперь нам понадобиться создать поле этого типа. Это мы уже умеем и делать и поэтому не должно вызвать никаких сложностей. В директиву Private напишите:

FShowType:TShowTp;

Мы создали поле ShowType, типа TShowTp.

Конечно же необходимо добавить это свойство в инспектор объектов:

property ShowType: TshowTp read FshowType write FShowType;

Ну и наконец, чтобы наш компонент реагировал на изменение этого свойства пользователем надо слегка изменить обработчик события OnClick. После небольшой модификации он может иметь примерно такой вид:

procedure Tcountbtn.Click;
begin
inherited click;
FCount:=Fcount+1;
if ShowType = Normal then
Caption:=Caption;


end;

Объясню что произошло. Вначале мы увеличиваем счетчик на единицу. Затем проверяем какое значение имеет свойство ShowType. Если Normal, то ничего не делаем, а если CountToCaption, то в надпись на кнопке выводим количество кликов. Не так уж и сложно как это могло показаться с первого раза.

Имплантируем таймер в компонент

Очень часто бывает, что вам необходимо вставить в компонент, какой-нибудь другой компонент, например, таймер. Как обычно будем рассматривать этот процесс на конкретном примере. Сделаем так, что через каждые 10 секунд значение счетчика кликов будет удваиваться. Для этого мы встроим таймер в нашу кнопку. Нам понадобиться сделать несколько несложных шагов.

После раздела uses, где описаны добавленные в программу модули, объявите переменную типа TTimer. Назовем ее Timer. Приведу небольшой участок кода:

unit CountBtn;

Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;

procedure OnTimer(Sender: TObject);

Поскольку наш таймер это не переменная, а компонент, его тоже надо создать, для этого в конструктор нашей кнопки напишем:

constructor TCountBtn.Create(aowner:Tcomponent);
begin
inherited create(Aowner);
Timer:=TTimer.Create(self);
Timer.Enabled:=true;
Timer.OnTimer:=OnTimer;
Timer.Interval:=10000;
end;

Здесь создается экземпляр нашего таймера и его свойству Iterval (измеряется в миллисекундах) присваивается значение 10000 (то есть 10 секунд если по простому).

Собственно осталось написать саму процедуру OnTimer. Я сделал это так:

procedure TCountBtn.OnTimer(Sender: TObject);
begin
FCount:=FCount*2;
end;

Вот примерно то, что у вас должно получиться в конце:

unit CountBtn;

Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;

Var Timer: TTimer;
type
TShowTp = (Normal, CountToCaption);
TCountBtn = class(TButton)

Private
{ Private declarations }

FCount:integer;
FShowType:TShowTp;
protected
{ Protected declarations }
procedure OnTimer(Sender: TObject);
procedure Click;override;
public
{ Public declarations }
procedure ShowCount;
published
{ Published declarations }
property Count:integer read FCount write FCount;
constructor Create(aowner:Tcomponent);override;
property ShowType: TshowTp read FshowType write FShowType;
end;

Procedure Register;

Implementation

Procedure Register;
begin
RegisterComponents("Mihan Components", );
end;

Constructor TCountBtn.Create(aowner:Tcomponent);
begin
inherited create(Aowner);
Timer:=TTimer.Create(self);
Timer.Enabled:=false;
Timer.OnTimer:=OnTimer;
Timer.Interval:=1000;
end;

Procedure Tcountbtn.Click;
begin
inherited click;
FCount:=Fcount+1;
Timer.Enabled:=true;
if ShowType = Normal then
Caption:=Caption;
if ShowType = CountToCaption then
Caption:="Count= "+inttostr(count);
end;

Procedure TCountBtn.ShowCount;
begin
Showmessage("По кнопке "+ caption+" вы сделали: "+inttostr(FCount)+" клик(а/ов)");
end;

Procedure TCountBtn.OnTimer(Sender: TObject);
begin
FCount:=FCount*2;
end;

Если у вас что-то не сработало, то в начале проверьте все ли у вас написано правильно. Затем проверьте может у вас не хватает какого-нибудь модуля в разделе Uses.

Переустановка компонента

Очень часто бывает необходимо переустановить ваш компонент. Если вы попробуете сделать это путем выбора Component->Install Component, то Дельфи вас честно предупредит о том, что пакет уже содержит модуль с таким именем. Перед вами открывается окно с содержимым пакета. В нем вы должны найти имя вашего компонента и удалить его (либо нажать кнопочку Remove). Теперь в пакете уже нет вашего компонента. Затем проделайте стандартную процедуру по установке компонента.

Удачи в программировании...

(С) Авторские права принадлежат Михаилу Христосенко! При размещении на других сайтах указание имени автора и адреса сайта (http://delphid.dax.ru) обязательно!

В среде Delphi программист работает с проектом – набором файлов, из которых Delphi создает приложение. Один проект соответствует одному приложению. Ряд файлов проекта Delphi формирует и модифицирует автоматически. Программист может добавлять в проект и собственные файлы (Pascal -модули, графические файлы, DLL –библиотеки, библиотеки компонент, ресурсы и т.д.).

В состав проекта обязательно входят следующие элементы :

· основной файл проекта, имеющий расширение.DPR (D elphi PR oject ). В проекте может существовать только один файл с таким расширением. Это небольшой текстовый файл на языке Object Pascal , который содержит ссылки на все формы проекта и инициализирует приложение;

· файлы всех форм проекта. Для каждой формы формируется пара одноименных файлов – файл Pascal -модуля с обычным расширением.PAS и файл ресурсов формы с расширением.DFM (D elphi F orM ). Любая форма проекта всегда должна иметь свою пару файлов модуль-ресурс. Обратное не обязательно, т.е. проект может включать в себя модули и файлы ресурсов не относящиеся ни к одной из форм приложения;

· файл ресурсов приложения (*.RES). В нем содержатся ресурсы приложения, не вошедшие в формы;

файл опций проекта (*.DOF – D elphi O ptions F ile ). В этом файле сохраняются значения директив и опций компилятора, настроек компоновщика, названия рабочих каталогов, параметры командной строки запуска приложения.

Пример программы

Перед началом работы над очередным проектом, прежде всего, следует создать для файлов будущего проекта отдельную папку (директорию). Это правило необходимо соблюдать всегда, иначе очень скоро файлы различных проектов так “перемешаются” в одном директории, что рассортировать их по проектам станет довольно сложно. Будем считать, в дальнейшем, что такая папка создана, назовем ее PO_EVM , это будет текущая папка проекта.

Запускаем Delphi . Если загрузка прошла успешно, то на экране монитора мы увидим то, что представлено на рис.1. В строке заголовка главного окна Delphi присутствует надпись Delphi 3 – Project1 . Это название нашего проекта и программы. В строке заголовка окна формы приложения написано Form1 . Если нажать клавишу F12 или щелкнуть мышью на кнопку Toggle
Form/Unit
(панель быстрого доступа) или выбрать пункт меню View/Toggle Form/Unit , то окно редактора кода переместится на передний план и мы увидим содержимое страницы Unit1 редактора, в которой представлен Pascal -код модуля Unit1 . Добавим в окно редактора кода еще одну страницу, в которой расположится код основного программы проекта. Для этого выберем пункт меню View/Project Source . Ниже представлено содержимое двух страниц редактора кода: Pascal-код главной программы и Pascal-код модуля главной формы проекта, соответственно.

Сохраним файлы проекта в созданном директории PO_EVM . Для этого нажмем кнопку Save all на панели быстрого доступа или выберем пункт меню File/Save Project As… . В появившемся стандартном Windows- окне сохранения файлов выберем папку PO_EVM и последовательно сохраним Pascal -код модуля формы и Pascal -код программы в файлах с именами IDE_Un1.pas и IDE_Pr.dpr соответственно.

program IDE_Pr;

IDE_Un1 in ‘IDE_Un1.pas’ {Form1};

Application.Initialize;

Application.CreateForm(TForm1, Form1);

Application.Run;

unit IDE_Un1;

Windows, Messages, SysUtils,

lasses, Graphics, Controls,

TForm1 = class(TForm)

{ Private declarations }

{ Public declarations }

Если сейчас посмотреть содержимое папки PO_EVM , то в ней будут находиться следующие файлы проекта: IDE_Pr.dof – файл опций проекта; IDE_Pr.dpr – основной файл проекта; IDE_Pr.res – файл ресурсов проекта; IDE_Un1.pas – файл Pascal-кода модуля формы; IDE_Un1.dfm – файл ресурсов формы.

Желательно изменить некоторые стандартные настройки среды, в частности для того, чтобы на экране отображался процесс компиляции и компоновки программы, а также, чтобы перед каждым запуском программы на исполнение автоматически сохранялись все модифицированные файлы проекта. Сделать это можно в диалоговом окне Environment Options… , которое можно вызвать из меню Tools/ Environment Options… . На страничке Preferences в разделе Desktop contens установить переключатель в положение Desktop only , в разделе Autosave options установить выключатели в пунктах Editor files и Desktop , а в разделе Compiling and Running установить выключатель Show compiler progress .

Простейшая программа в Delphi уже готова к исполнению. Нажав кнопку Run на панели быстрого доступа или клавишу F9 , можно наблюдать процессы компиляции и компоновки программы, после которых начнет исполняться наша программа. Визуально программа представлена на экране пустым окном со стандартной Windows- строкой заголовка, содержащей пиктограмму приложения, наименование формы и три кнопки управления окном. Выход из программы и возврат в среду Delphi осуществляется стандартным для Windows способом – комбинацией клавиш Alt-F4 или нажатием на кнопку закрытия приложения. Если сейчас просмотреть содержимое папки файлов проекта PO_EVM , то можно заметить, что в ней появились еще два файла: IDE_Un1.dcu и IDE_Pr.exe – откомпилированный файл модуля формы и загрузочный (исполняемый) файл приложения. Файл IDE_Pr.exe можно запускать на исполнение автономно, т.е. вне среды Delphi . После выхода из среды Delphi , в папке образуется еще один файл IDE_Pr.dsk – файл с индивидуальными пользовательскими настройками среды.

Приведем примерную последовательность действий программиста, который создает программу “Калькулятор +/- “. Это, с позволения сказать, приложение предназначено для выполнения операций сложения и вычитания вещественных чисел. При запуске окно (форма) программы должно выглядеть как на рис. 7.

На форме расположены три строки ввода/вывода (компоненты типа TEdit ) для ввода двух операндов и вывода результата; пять кнопок (четыре компоненты типа TButton и одна – TBitBtn ) – сброс, указание типа и результата операции (C , + , , = ), выхода из программы (Close); три надписи для обозначения операндов и результата (компоненты типа TLabel ); разделительный интерфейсный элемент для выделения поля вывода результат счета (компонент TBevel ).

В исходном состоянии, после запуска Delphi и сохранении двух файлов проекта с указанными именами, мы имеем пустую форму. Далее порядок построения интерфейсной части приложения был следующим (результаты ваших действий можно сверять с расположением компонентов на рис. 7):

1. Свойство формы Caption в инспекторе объектов изменяем со значения Form1 на строковое значение Калькулятор +/- . Изменение значения названия формы сразу заметно в строке заголовка формы;

2. На странице Standard палитры компонентов щелкаем левой кнопкой мыши на изображении компонента Label , затем перемещаем указатель мыши в район левого верхнего угла формы и щелкаем левой кнопкой там. В этом месте на форме появится изображение компонента Label с надписью Label1 . Изображение компонента выделяется по периметру шестью черными квадратиками – маркерами изменения размеров (размерные маркеры). Выделение маркерами означает, что данный компонент сейчас является активным. С помощью мыши стандартными Windows- приемами можно изменять размеры компонента, перемещать его по форме. Для активизации другого компонента формы необходимо просто щелкнуть на нем левой кнопкой мыши. Содержимое закладок инспектора объектов всегда соответствует активному компоненту, при активизации другого компонента, состав полей инспектора объектов автоматически меняется. Изменим свойство Caption компонента Label со значения Label1 на значение 1-ый операнд . Свойству Name этого компонента придадим значение lb_1 .

3. Действуя аналогично, расположим второй компонент-метку немного ниже первой, задав, соответственно, свойствам Caption и Name значения 2-ой операнд и lb_2 .

4. На той же странице Standard палитры компонентов выберем компонент Edit (строка редактирования) и поместим его на форме правее первой метки. Свойству Name присвоим значение ed_1 , а свойство Text сделаем пустым.

5. Действуя аналогично, расположим вторую строку редактирования правее второй метки, задав, соответственно, свойствам Text и Name значения пустой строки и ed_2 .

6. На странице Additional палитры компонентов выберем компонент Bevel и поместим его так, чтобы он изображал “итоговую” черту под второй меткой и второй строкой ввода. Свойство Name, равное Bevel1 , изменять не будем.

7. Под компонентом Bevel разместим еще одну пару “метка – строка ввода” для вывода результата вычислений. Свойствам Name присвоим значения lb_3 и ed_3 , свойству lb_3.Caption – значение Результат , а свойству Text компонента ed_3 – значение пустой строки.

8. Поместим еще одну метку для изображения текущей арифметической операции: (?, +, –) - операция не определена, операция сложения, операция вычитания. Расположим эту метку между двумя первыми метками, ближе к левым границам компонентов для ввода операндов (см. рис.7). Свойству Name присвоим значение lb_oper , а свойству Caption – значение ? . Установим также подсвойство Size в свойстве Font для этой метки, равным 14 ;

9. Подравняем компоненты. Стандартным Windows- приемом выделим компоненты – метки. Для этого, держа нажатой кнопку Shift , последовательно щелкая левой кнопкой мыши по компонентам-меткам, активизируем одновременно все три метки. Если теперь щелкнуть правой кнопкой мыши, то по законам Windows 95 должно появиться контекстное меню – оно и появляется. Выберем в нем пункт A lign… (выравнивание). Теперь на экране мы видим окно Alignment . Выберем на панели Horizontal пункт Left sides и нажмем кнопку Ok . В результате этого все три компонента – метки выровняются по левой границе самой левой компоненты. Аналогичными действиями подравняем и все три строки редактирования. Строки редактирования можно выровнять и по размерам, выделив их одновременно все три и выбрав в контекстном меню пункт Size… . “Тонкую” работу по изменению размеров и перемещению компонент выполняют обычно не мышью, а клавишами управления курсором при нажатых, соответственно, сдвиговых клавишах Shift и Ctrl . Эти действия можно производить не только с одним компонентом, но и с выделенной группой компонентов.

10. Теперь расставим на форме управляющие кнопки. Их у нас пять (см. рис.7). Первые четыре кнопки – кнопка сброса, кнопки операций (сложение (+) и вычитание (–)) и кнопка результата. Пятая кнопка – кнопка завершения работы программы. На странице Standard палитры компонентов выберем компонент Button (кнопка) и поместим его правее первой строки редактирования. Свойствам Caption и Name кнопки присвоим соответственно значения C и btn_Clear . Аналогичным образом располагаем и три другие кнопки на форме, назвав (свойство Name ) их btn_sum, btn_sub и btn_rez , с наименованиями (свойство Caption ) + , и = (см. рис.7). Выделив кнопки в группу, дважды щелкнем на составном свойстве Font в инспекторе объектов. В поле Size свойства Font зададим размер шрифта 14 пунктов. После установки этого значения размер символов на кнопках увеличится.

11. Пятая кнопка – кнопка завершения программы – выбрана со страницы Additional . Это первый по порядку компонент на этой странице – кнопка типа BitBtn (командная кнопка с надписью и пиктограммой). Расположив кнопку на показано на рис.7, выберем из списка значений свойства Kind значение bkClose . Этим выбором полностью определяются визуальные атрибуты и функциональное назначение кнопки.

12. В заключение процесса построения интерфейсной части программы уменьшим форму до размеров, приведенных на рис.7.

На этом заканчивается первый этап создания приложения – построения интерфейса. Необходимо отметить, что на любом этапе построения интерфейса можно в любой момент запустить программу на исполнение. В процессе выполнения вышеописанных шагов мы не написали ни одной строчки, ни одного Pascal-оператора. Все записи в тексте модуля формы приложения Delphi делает сама. К этому моменту в интерфейсной части модуля формы произошли изменения – добавились описания компонентов, помещенных нами в форму и стандартные модули Delphi – Buttons, StdCtrls, ExtCtrls.

Windows, Messages, SysUtils, Classes,

Graphics, Controls, Forms, Dialogs,

Buttons, StdCtrls, ExtCtrls;

TForm1 = class(TForm)

lb_Oper: TLabel;

btn_Clear: TButton;

btn_sum: TButton;

btn_sub: TButton;

btn_rez: TButton;

bb_Close: TBitBtn;

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

Сначала словесно оговорим то, что должно происходить при нажатии той или иной кнопки, в каких случаях и какого содержания сообщения должны появляться на экране:

1. Нажатие на кнопку “Очистить” (С ) - очистить все три строки редактирования и в качестве знака операции отобразить знак вопроса (?) ;

2. Нажатие на кнопку “Сложить” (+ ) - изменить изображение знака операции на знак плюс (+) ;

3. Нажатие на кнопку “Вычесть” () - изменить изображение знака операции на знак минус (–) ;

4. Нажатие на кнопку “Вычислить” (= ) - провести проверку на правильность данных в первых двух строках редактирования. Если данные правильные (числа), то провести соответствующую арифметическую операцию и вывести результат в строку вывода. Если обнаружена ошибка в исходных данных, то следует вывести сообщение об этом с указанием места ошибки.

Теперь переведём (транслируем) на Pascal-код каждый из вышеперечисленных пунктов. Каждый компонент имеет список событий (список приводится на второй странице (Events ) инспектора объектов), на которые он может реагировать (которые он может обрабатывать). Наша задача – написать код, который будет выполняться при возникновении того или иного события. Для кнопок в Delphi определены несколько обработчиков событий, нас будет интересовать обработчик события “Однократное нажатие на кнопку” (щелчок левой кнопкой мыши в момент нахождения указателя мыши над компонентом Button ). Этот обработчик называется OnClick . Каждый обработчик события оформляется в отдельную процедуру. Название этой процедуре формирует сама среда Delphi .

Напишем обработчик события однократного нажатия на кнопку “Очистить”. Для этого выделим на форме кнопку “Очистить” (С ). Активизируем страницу Events в окне инспектора объектов. Дважды щелкнем на пустом поле правого столбца рядом с надписью OnClick . После этого Delphi автоматически отображает окно редактора кода IDE_Un1 и помещает текстовый курсор для вставки текста внутри процедуры TForm1.btn_ClearClick:

procedure TForm1.btn_ClearClick(Sender: TObject);

как бы приглашая нас начать печатать с этого места Pascal -код этой процедуры. Обратите внимание на название процедуры, которое сформировала среда Delphi . Оно состоит из названия формы, на которой расположена компонента (кнопка), имени этой компоненты (btn_Clear) и названия обработчика события – Click . Следуя содержанию первого пункта нашего словесного алгоритма, вставим в тело процедуры следующие строки Pascal -кода:

lb_Oper.Caption:=’?’; {тип операции неопределен (метка – ?)}

ed_1.Text:=”; {очистить строку для ввода первого операнда}

ed_2.Text:=”; {очистить строку для ввода второго операнда}

ed_3.Text:=”; {очистить строку для вывода результата}

Действуя аналогично, сформируем обработчики события “Однократный щелчок левой кнопкой мыши на компоненте” для интерфейсных кнопок “Сложить” (+ ) и “Вычесть” ():

– для кнопки “Сложить” строка кода - lb_Oper.Caption:=’+’;

– для кнопки “Вычесть” строка кода - lb_Oper.Caption:=’-‘;

Обработчик события OnClick для кнопки “Вычислить” (= ) будет содержать следующий Pascal -код:

procedure TForm1.btn_rezClick(Sender: TObject);

Val(ed_1.Text,r1,i);

if i<>0 then begin

ShowMessage(‘Ошибка в первом операнде’);

Val(ed_2.Text,r2,i);

if i<>0 then begin

ShowMessage(‘Ошибка во втором операнде’);

case lb_oper.Caption of

‘+’ : ed_3.Text:=FloatToStr(r1+r2);

‘-‘ : ed_3.Text:=FloatToStr(r1-r2);

else ShowMessage(‘Не определен тип операции’);

В обработчике события TForm1.btn_rezClick введены две локальных вещественных переменных r1 и r2 для запоминания числовых значений двух операндов и целочисленная переменная i для использования в Pascal -процедуре Val преобразования строковой переменной в числовое представление. Этот обработчик реализует четвертый пункт словесного алгоритма работы программы. Сначала проверяется на правильность строка, введенных пользователем, символов первого операнда. Если это не число, то процедурой ShowMessage выводится соответствующее ситуации сообщение и по процедуре Exit заканчивается выполнение кода процедуры. В случае корректности данных переменная r1 примет числовое значение первого операнда. Аналогичным образом проверяется второй операнд и, если здесь все нормально, то переменная r2 примет числовое значение второго операнда.

Оператор Case реализует арифметическую операцию над переменными r1 и r2 в зависимости от того, какой символ (+ , , ? ) определяет значение свойства Caption метки lb_oper . Если знак арифметической операции не определен (у нас это символ ? ), то выдается соответствующее сообщение и операция не производится.

Следует заметить, что, как и положено по правилам Pascal , в интерфейсную часть модуля формы автоматически средой Delphi были добавлены заголовки процедур – обработчиков событий нажатий на клавиши:

procedure btn_sumClick(Sender: TObject);

procedure btn_ClearClick(Sender: TObject);

procedure btn_subClick(Sender: TObject);

procedure btn_rezClick(Sender: TObject);

На этом можно закончить программную реализацию задачи создания простейшего калькулятора, осуществляющего операции сложения и вычитания вещественных чисел. Отметим также, что наше приложение на 99% защищено от ошибок, связанных с операциями над некорректными исходными данными (а почему не 100% ?).

Ознакомившись с теорией предмета изучения, перейдем к практическому его освоению. В этой главе вы узнаете, из чего состоит Delphi, какие программы с ее помощью можно делать, и, собственно, создадите первую программу в среде Delphi!

Состав Delphi и требования к системе

Прежде, чем приступать к работе с какой-либо программой, было бы полезно ознакомиться с ее требованиями к компьютеру. Разумеется, требования у разных версий Delphi разнятся, постепенно повышаясь от версии к версии. В частности, в рассматриваемой нами Delphi 7 рекомендуется процессор не ниже Pentium II и не менее 256 Мбайт оперативной памяти. Более ранние версии требовали меньший объем памяти, однако для комфортной работы я в любом случае рекомендовал бы не менее 256 Мбайт, а для Delphi 7 и выше, да еще и под управлением ОС Windows XP, не помешало бы иметь 512 Мбайт ОЗУ.

Что касается требований к операционной системе, то хотя формально Delphi может работать на любой 32-разрядной версии Windows, я бы настоятельно рекомендовал использовать Windows из линии NT, т.е. Windows 2000 или XP. Дело в том, что Windows 9x, из-за своего 16-разрядного наследия, имеет серьезные ограничения на количество доступных системных ресурсов, вне зависимости от того, насколько мощный ПК вы используете. Кроме того, Windows 9x не может эффективно задействовать даже относительно большие - свыше 128 Мбайт - объемы оперативной памяти. Я уже не говорю о том, что в Windows 9x не поддерживаются ни многопоточность, ни набирающие в последнее время популярность двуядерные процессоры, а производители аппаратных компонентов ПК давно уже забросили оптимизацию драйверов для данного семейства ОС. Результатом всего этого является низкая производительность на современных компьютерах и вполне ощутимый риск "повесить" систему в процессе работы над сложным и ресурсоемким приложением.

Еще один важный вопрос - это монитор. Опять-таки, формально достаточно любого SVGA-монитора. Но работать в среде Delphi при разрешении экрана ниже, чем 1024 на 768 точек, крайне затруднительно: учтите, что вам постоянно надо видеть как элементы управления самой Delphi, так и собственное (разрабатываемое) приложение. Для комфортной работы я бы рекомендовал качественный 19" монитор с рабочим разрешением 1280 на 1024 точки. Причем, если это будет обычный монитор на ЭЛТ (или даже ЖК, но с аналоговым подключением), то вам понадобится еще и качественная видеокарта, способная обеспечить кристально четкую, без "замыливания" картинку. Для ЭЛТ-мониторов также важно обеспечивать поддержку указанного разрешения при частоте регенерации изображения не ниже 85 Гц.

ПРИМЕЧАНИЕ
Помните, что программирование - это напряженная работа с текстом. И если ваша связка "видеокарта-кабель-монитор" не может выдать четкий текст и (или) отсутствие видимого мерцания в нужном вам разрешении, то со временем вы рискуете испортить себе зрение.

Определившись с компьютером, перейдем к установке. В процессе установки про-грамма спросит вас, для каких версий тех или иных третьесторонних приложений следует устанавливать компоненты. Прежде всего, это версии MS Office, для одной из них вы сможете установить набор компонент, обеспечивающих взаимодействие между приложениями office и Delphi. Если вы устанавливаете старшую версию Del-phi (Client/Server, Enterprise, Architect), то вас спросят еще и о том, для каких версий баз данных следует установить компоненты. Наконец, в процессе установки, помимо самой Delphi будут установлено множество дополнительных программ, в основном, связанных с базами данных. Причем некоторые из них (например, сервер InterBase или виртуальная Java-машина) вообще устанавливаются отдельно, хотя и в процессе общего хода инсталляции.

По завершению процесса установки в программном меню Windows будет сформирована группа Borland Delphi, в которой, помимо самой Delphi, будут находиться ярлыки всех вспомогательных компонент среды. В частности, там будут находиться ярлыки для следующих программ:

  • Image editor - простой графический редактор для рисования иконок и курсоров. За время, прошедшее с момента последнего обновления (в 1996 году), морально устарел, но может пригодиться, если нет ничего другого;
  • WinSight - позволяет просматривать отладочную информацию в любых работающих приложениях;
  • BDE Administrator - позволяет настраивать базы данных;
  • Data Pump - позволяет переносить данных между БД;
  • Database Explorer или SQL Explorer - средство просмотра БД;
  • SQL Monitor (только старшие версии) - позволяет отслеживать обращения приложений к SQL-серверу.

Кроме того, в этой группе будет находиться подгруппа Help, а в ней, среди множества справочных файлов, - еще одна, с еще большим их количеством - MS SDK Help Files. Так вот, все эти файлы вам придется регулярно использовать, причем положение усугубляется не только их количеством и объемами, но и тем, что в русском варианте их не существует. Таким образом, знание английского языка будет вам хорошим подспорьем при изучении как Delphi, так и программирования вообще.

СОВЕТ
Если вы не знаете английского, но владеете немецким или французским, то вы можете установить версию Delphi на том языке, который знаете лучше. Русских версий Delphi, равно как и других серьезных средств разработки, нет, никогда не было, и, увы, даже не предвидится.

Таким образом, мы вкратце ознакомились с составом среды Delphi. Отдельные вспо-могательные приложения, при необходимости, мы еще рассмотрим, ну а сейчас пора приступать к изучению главной составляющей - самой среды Delphi.

Интегрированная среда разработки

Интегрированная среда разработки Delphi (Delphi IDE) является многооконной системой. Она включает в себя все необходимое для быстрой разработки Windows-приложений, и может гибко настраиваться.

Тем не менее, как и всякая другая программа, Delphi имеет некоторый стандартный, предусмотренный разработчиками вид, в котором она предстает вам при первом запуске. В таком "стандартном" варианте среда Delphi имеет 6 окон (рис. 2.1). Это: главное окно (Delphi 7 - Project1), окно дерева объектов (Object TreeView), окно инспектора объектов (Object Inspector), окно конструктора форм (Form1), а так же совмещенное окно редактора кода и проводника кода (на заднем плане, под Form1). При этом окно проводника пристыковано к левому краю окна редактора. Впрочем, ничего не мешает отсоединить проводник от редактора, или, наоборот, состыковать все окна, кроме главного и конструктора форм, в одном окне, или объединить их по какому-либо иному принципу.

Рис. 2.1. Вид Delphi 7 IDE по умолчанию

К вопросу об удобстве следует отметить, что предлагаемая разработчиками компоновка годится, в принципе, для любого экранного разрешения. Но если у вас имеется возможность установить разрешение экрана в значение 1280 на 1024 точки, то вы можете скомпоновать все кнопки главного окна в одной строке, а все освободившееся внизу место выделить для палитры компонентов (рис. 2.2).

Рис. 2.2. "Оптимизированный" вид главного окна Delphi

Такой шаг позволит иметь перед глазами гораздо большее количество категорий компонент, что положительно сказывается на продуктивности работы. В принципе, это можно сделать и при более низком разрешении, однако при этом частью кнопок на панелях инструментов придется пожертвовать.

  • Debug - отладка. Позволяет запустить программу (Run), приостановить ее выполнение (Pause), а так же выполнять построчное выполнение программы;
  • Standard - стандартные. Служит для таких операций, как сохранение, созда-ние, добавление и удаление файлов;
  • View - вид. Используется для быстрого нахождения форм и файлов проекта;
  • Desktops - рабочая среда. С помощью этих инструментов можно переклю-чаться между различными настройками рабочей среды Delphi;
  • Custom - произвольная. Изначально содержит одну-единственную кнопку - для вызова справки;
  • Component palette - палитра компонентов. Содержит все доступные для разработки приложений компоненты.

Отметим, что все инструментальные панели настраиваются: кнопки можно перемещать между панелями, добавлять на них новые, или же удалять. Для обычных панелей (Standard, View, Debug) это делается точно таким же образом, как во многих других современных Windows-приложениях (например, как в Word, т.е. при помощи окна настройки - Customize).

Что касается самой большой панели - палитры компонентов, то для ее настройки следует использовать специальное окном свойств палитры (рис. 2.3). Это окно доступно через пункт Configure Palette из меню Component. Однако учтите, что при настройке важно знать как предназначение компонент, так и понимать принципы их организации, поэтому максимум, что можно себе позволить для начала - это поменять местами группы, перетаскивая их в списке страниц (Pages).


Рис. 2.3. Настройка палитры компонентов требует знания VCL

ПРИМЕЧАНИЕ
Следует учитывать, что поскольку палитра компонентов является ничем иным, как визуальным представлением VCL, то ее вид и состав могут меняться в зависимости от того, какие модули подключены, устанавливались или нет дополнительные компоненты или их наборы, и т.д. В любом случае, в начале изучения Delphi, экспериментов в этой области лучше не производить.

Все компоненты сгруппированы по вкладкам, число и состав которых несколько разнятся в зависимости от версии и варианта поставки. Так, в Delphi 7 Enterprise имеется 33 вкладки, содержащие компоненты, принадлежащие к той или иной группе VCL (табл. 2.1).

Таблица 2.1. Страницы палитры компонент Delphi 7 Enterprise

Страница

Название

Описание

Стандартные

Основные элементы интерфейса приложений Windows (меню, кнопки, подписи и т.п.)

Дополнительные

Набор улучшенных элементов управления, имеющихся в VCL

32- разрядные Windows

Элементы интерфейса приложений, характерные для Windows 95 и последующих версий этой ОС

Системные

Элементы управления и доступа к системным 16 ункцииям Windows (таймер, OLE , DDE )

Доступ к данным

Стандартный набор компонент для доступа к БД

Элементы данных

Элементы пользовательского интерфейса для доступа к БД

Компоненты для доступа к БД при помощи SQL -драйвера dbExpres

Компоненты для взаимодействия с удаленный web -сервером через SOAP

Компоненты для взаимодействия с сервером через DCOM

Borland Database Engine

Компоненты для доступа к БД посредством BDE (классический вариант для простых БД)

Компоненты для взаимодействия с БД через ADO

Компоненты для прямого взаимодействия с БД InterBase

Администрирование InterBase

Компоненты для взаимодействия и управления сервером БД InterBase

Компоненты для взаимодействия с данными через XML

Компоненты для работы с данными через различные протоколы Интернета

Набор ActiveX -компонент для работы через Интернет

Набор компонент для обработки информации в БД

Стандартные и расширенные диалоговые окна

Компоненты пользовательского интерфейса, характерные для Windows 3.1

Несколько визуальных компонент, не являющихся официально поддерживаемыми

Несколько встраиваемых ActiveX- приложений

Rave Repo rts

Набор компонент для построения отчетов

Клиенты Indy

Набор компонент-клиентов для различных протоколов и служб Интернета

Серверы Indy

Набор компонент-серверов для различных протоколов и служб Интернета

Обработчики Indy

Набор компонент, позволяющих отлавливать сообщения от клиентов и серверов Indy

Indy i/o ha ndlers

Ввод-вывод Indy

Компоненты для отслеживания активности соединений других компонент Indy

Утилиты Indy

Набор вспомогательных компонент, полезных при разработке различных TCP -приложений

Содержит компонент, позволяющий создать управляющий сервер COM +

IW Standard , Data, Client Side, Control

Набор специальных кросс платформенных компонент для создания Web -приложений для любых Web -клиентов, включая КПК и смартфоны

MS Office Servers

Набор ActiveX -компонент для взаимодействия с приложениями Microsoft Office

Суммарно Delphi включает в себя сотни компонент, однако не стоит переживать по поводу огромного их количества: Delphi применяется во многих областях, и вряд ли хоть один разработчик в действительности использовал все доступные компоненты. Так что мы выделим наиболее полезные для нас группы, а именно: стандартные, дополнительные, 32-разрядные Windows, системные и диалоги. Этого набора будет более чем достаточно для начала изучения Delphi. Со временем мы ознакомимся так же с классическими компонентами для доступа к БД (Data Access и Data Controls), а так же с несколькими компонентами из богатой коллекции Indy. На этом введение в палитру компонент можно считать завершенным и перейти к дальнейшему ознакомления со средой, для чего перейдем к детальному исследованию главного окна, начав с его меню, которое состоит из 11 пунктов:

  • File - файл. Операции с файлами, вроде создать, открыть, сохранить;
  • Edit - правка. Операции редактирования, как стандартные для текстового процессора (отмена, копирование-вставка), так и специфические для редактирования разрабатываемых окон приложений (выравнивание, порядок со-здания и т.п.);
  • Search - поиск. Различные варианты поиска и замены;
  • View - вид. Переключение между различными окнами - как относящимися к IDE, так и к разрабатываемому приложению;
  • Project - проект. Все операции по работе с проектом, как то добавление и удаление файлов, настройки, сборка и компиляция;
  • Run - выполнить. Средства для отладки программ;
  • Component - компоненты. Средства для работы с компонентами, включая настройку палитры компонент;
  • Database - Данные. Некоторые средства для работы с БД;
  • Tools - сервис. Настройка параметров IDE, а так же вызов вспомогательных программ (Image editor и др.);
  • Windows - окно. Содержит список всех открытых в текущий момент окон и позволяет переключаться между ними (актуально, когда окон много и одни загораживают другие);
  • Help - справка.

Таким образом, мы уже исследовали все главное окно IDE Delphi. Что касается остальных окон, то их предназначение мы узнаем по ходу дальнейшего ознакомления со средой, а относительно их расположения, да и вообще необходимости в некоторых из них, то это - вопрос личных вкусов и специфики разрабатываемого приложения - общие рекомендации тут были бы неуместны.

Проекты в Delphi

Разработка приложений в Delphi означает работу с проектами. Иначе говоря, когда вы приступаете к разработке собственной программы в Delphi, первым делом создается проект - группа файлов, представляющих исходные данные (прежде всего, код) для приложения. Одни из этих файлов создаются во время разработки приложения (собственно программный код, включая файл проекта, и представленные в виде кода формы), другие же создаются автоматически при запуске программы. Таким образом, все файлы проекта подразделяются на следующие типы:

  • dpr - собственно файл проекта;
  • pas - модули приложения, содержащие код на Object Pascal;
  • dfm - модули приложения, содержащие информацию об окнах приложения;
  • res - файлы со встраиваемыми ресурсами приложения (например, иконками);
  • obj - файлы, содержащие готовый к компиляции объектный код;
  • cfg, dof, dsk - служебные файлы Delphi.

Основными составными частями проекта, помимо самого файла проекта (dpr), являются модули pas и dfm. При этом для каждого модуля окна (dfm) имеется собственный программный модуль (pas).

Чтобы лучше во всем этом разобраться, попробуем создать собственный проект в Delphi. Для этого достаточно запустить Delphi - в том случае, если вы не изменяли настроек, новый проект создастся автоматически. Но на всякий случай, мы все-таки создадим новый проект самостоятельно, для чего следует из меню File зайти в группу New и выбрать в ней пункт Application.

ВНИМАНИЕ
Чтобы постоянно не повторяться, в дальнейшем подобные последовательности действий мы будем обозначать следующим образом: File > New > Application.

В результате мы получим новый проект, полностью готовый к дальнейшему использованию (см. рис. 2.1). Более того, его уже на этом этапе можно выполнить! Для этого достаточно нажать на кнопку Run, находящуюся на панели инструментов отладки, или же выбрать пункт Run из одноименного меню (Run > Run), но лучше всего нажать на клавишу F9: для быстрой разработки приложений в среде Delphi знание хотя бы основных сочетаний "горячих клавиш" просто необходимо.

Итак, мы запустили приложение, правда, выглядеть оно будет довольно скучно: пустое окно с заголовком Form1 и стандартными кнопками управления окном (рис. 2.4). Но, по крайней мере, даже такое приложение обладает всей базовой функциональностью: его можно развернуть на весь экран, или наоборот, свернуть в панель задач, перемещать по экрану, изменять размеры, и, что самое главное - закрыть.


Рис. 2.4. Самое первое приложение в Дельфи

Теперь немного модернизируем свое приложение, заодно изучив еще одно важное окно среды Delphi - Object Inspector. Для этого вернитесь в рабочую среду Delphi, закрыв запущенное приложение, и щелкните по окну Form1, чтобы оно стало актив-ным. Это окно, как и любые другие окна, относящиеся непосредственно к разрабаты-ваемому приложению, называют формой. Теперь обратите внимание на окно инспек-тора объекта (рис. 2.5), по умолчанию оно расположено по левому краю экрана.


Рис. 2.5. Окно инспектора объектов

В его верхней части находится ниспадающий список, содержащий все элементы, интерфейса выбранной формы, в данном случае там будет только сама форма, отмеченная в виде имени объекта (Form1). Далее располагается список всех свойств объекта, доступных для изменения в процессе визуальной разработки.

ПРИМЕЧАНИЕ
Все свойства объектов в Delphi, доступные для изменения, делятся на run-time (времени выполнения) и на design-time (времени разработки). При этом первые можно изменять только во время работы программы, а вторые доступны уже во время визуального редактирования.

Попробуем заменить значение одного из свойств. Наиболее безопасным будет изменение такого свойства, как Caption - оно отвечает за текст, находящийся в заголовке окна. Для изменения значения этого свойства, щелкните по строке с ним и вместо "Form1" введите какой-либо собственный текст, например, "Мое первое приложение в Delphi". В данном случае вы сразу же увидите результат своей работы: заголовок окна формы изменится на новый.

Некоторые свойства меняются не путем непосредственного ввода значений, а путем выбора одного из заранее предусмотренных. В простейшем случае это может быть выбор ложь-истина (False или True), включающим или отключающим ту или иную опцию. Иногда списки бывают гораздо более объемными. Например, для выбора цвета предлагается множество цветов, включая системные. Например, свойство Color имеет в нашем случае значение clBtnFace, что означает цвет кнопки, установленный в настройках Windows. Мы можем изменить его на любой другой цвет, как системный (например, clCaptionText - цвет текста заголовка окна), так и на явный, например, clWhite (белый).

Можно заметить, что некоторые из свойств отмечены значком "+". Это означает, что такое свойство является составным, и если щелкнуть по значку, то раскроются строки, содержащие отдельные параметры. Например, можно раскрыть таким образом свойство BorderIcons и поменять значение параметра biMinimize с True на False. Тем самым мы изменим значение свойства, отвечающего за системные элементы управления окна таким образом, что функция разворачивания окна на весь экран будет недоступной.

Есть и такие свойства, для редактирования которых открывается отдельное окно. Например, тот же цвет можно определить не выбирая его из списка предусмотрен-ных вариантов, а открыв стандартное для Windows окно выбора цвета. Для этого достаточно сделать двойной щелчок мышкой по области списка цвета. В других случаях (например, для выбора свойств шрифта - Font) окно настроек можно вызвать, нажав на имеющуюся напротив таких свойств кнопку с многоточием.

Ну а пока что сведем воедино все измененные нами свойства формы Form1:

Caption: Мое первое приложение в Delphi Color: clWhite BorderIcons:

Последнее свойство - составное и такое его значение получается в результате установки таких его составляющих, как biSystemMenu и biMinimize в True, а biMaximize и biHelp - в False.

Часть из сделанных изменений - цвет окна и его заголовок - видна сразу же, в рабочей среде Delphi, т.е. на этапе разработки. А вот изменения в системных кнопках, хотя и могут быть сделаны на данном этапе, визуально себя не проявляют. Поэтому, чтобы увидеть сразу все произошедшие изменения, запустим приложение на выполнение, нажав клавишу F9, и вы увидите, что не только цвет и заголовок окна изменились, но и кнопка "развернуть" стала неактивной (рис. 2.6).


Рис. 2.6. Первое приложение после небольшой доработки

Таким образом, мы ознакомились с Object Inspector - одним из наиболее важных окон рабочей среды Delphi. Ну а чтобы завершить тему введения в проекты, попробуем сохранить наш проект на диске. Пусть это будет папка Project1, а сам проект мы назовем first. Для этого откройте диалог сохранения проекта (File Save project as) и выберите в нем нужную папку.

СОВЕТ
По умолчанию Delphi предлагает складывать все проекты в недра своей собственно директории в Program Files. Но было бы гораздо лучше, если бы вы создали папку в другом, легко доступном месте, и назвали ее понятным для себя названием. Например, это может быть папка Work на диске C:.

А теперь внимание! Если вы сохраняете проект в первый раз, то Delphi предложит вам сначала сохранить не файл проекта, а все несохраненные рабочие файлы. В данном случае это будет программный файл формы. По умолчанию Delphi предложит назвать его unit1.pas, но лучше сразу взять за правило давать осмысленные имена все рабочим файлам. В частности, раз это окно - главное (и единственное) в нашем приложении, то назовем его файл main.pas. Таким образом будут сохранено сразу 2 файла - программный pas и файл формы dfm.

ВНИМАНИЕ
Имена любых файлов проекта должны состоять только из латинских букв и цифр, при этом начинаться должны с буквы. Также в них недопустимы пробелы и любые специсмволы, кроме знака подчеркивания.

Только после сохранения всех составных частей, будет предложено сохранить собственно файл проекта. Назовем его "first". После сохранения можно, наконец-то скомпилировать исполняемый файл, нажав Ctrl+F9 (или Project Make), закрыть Delphi и посмотреть, что мы имеем в папке Project1. А в ней, как и было обещано, будет файл main.pas - программный код для формы, main.dfm - описание формы, first.dpr - сам проект, first.res - файл ресурсов проекта, main.dcu - подготовленный к компиляции модуль, и, разумеется, first.exe - исполняемый файл готового приложения. Так же вы обнаружите в нем все служебные файлы Delphi, в которых хранится дополнительная информация о проекте и настройках рабочей среды для него - файлы first.cfg, first.dof и first.dsk.

Чтобы теперь вернуться к работе над этим проектом, достаточно дважды щелкнуть по файлу first.dpr, в результате будет загружена и Delphi IDE, и этот проект в нее.

Типы проектов и депозитарий

Только что мы рассмотрели создание наиболее распространенного типа проекта - приложения Windows со стандартным графическим интерфейсом. Но на самом деле, возможности Delphi этим не ограничены, вы можете создавать приложения самого разнообразного характера, включая консольные (для текстового режима Windows), динамически подключаемые библиотеки (DLL), сервисы для Windows NT/2000/XP, межплатформенные приложения CLX (Delphi 6,7) или приложения для платформы Microsoft .NET (Delphi 8, 2005). Чтобы создать приложение определенного типа, следует из подменю File New выбрать пункт Other. Таким образом, откроется окно, позволяющее выбрать тип нового приложения или добавить какой-либо специфический модуль к существующему проекту (рис. 2.7).


Рис. 2.7. Выбор нового приложения или модуля в Delphi 7

Выбор вариантов тут весьма обширен, причем, помимо типовых модулей и классов приложений, присутствуют различные мастера, позволяющие упростить процесс создания того или иного модуля (Wizards), а так же специализированные стандартные формы вроде диалоговых окон или окна "О программе". Рассмотрим некоторые из них подробнее, для чего пройдемся по отдельным закладкам окна New Items.

Начнем с закладки New. На ней представлены наиболее часто востребованные, по мнению разработчиков, варианты. И действительно, тут можно найти стандартное графическое Windows-приложение (Application), форму (Form), программный модуль (Unit), текстовое приложение командной строки (Console Application), и другие варианты, как-то Data Module (полезен для разработки баз данных), DLL Wizard, Component и т.д.

На закладках Forms и Dialogs моно найти ряд стандартных диалоговых окон и даже мастер по разработке диалогового окна.

Закладка Projects дает возможность начать проект того или иного типа, или даже воспользоваться мастером для создания многооконного приложения.

Чтобы создать элемент управления ActiveX или приложение для COM+, следует обратиться к шаблонам на закладке ActiveX. Ну а прочие закладки, в том числе IntraWeb, WebSnap и т.д., позволяют создавать специализированные приложения соответствующего типа или модули к ним. Их количество и названия зависят от версии Delphi и варианта поставки.

Но на самом деле, данное окно, по большому счету, подобно палитре компонент, с тем лишь исключением, что если палитра компонент являет собой представление VCL, то окно New Items - во многом является отображением депозитария (Object Repository). В депозитарии хранятся заготовки форм и иных модулей, которые вы можете многократно использовать в своих проектах. При этом для того, чтобы поместить форму в депозитарий, достаточно воспользоваться ее контекстным меню и выбрать в нем пункт Add to Repository.

Прочие средства IDE

На текущий момент мы уже рассмотрели такие составные части, предоставляемые интегрированной средой разработки Delphi, как главное окно вместе с его меню, окном выбора модулей и палитрой компонентов, и инспектора объектов. Теперь обратимся к такой важной части, как окно редактора кода. Следует отметить, что до появления графических средств разработки, подобных Delphi, еще во времена MS-DOS и ранних версий Windows, IDE для программирования как раз и состояли из редактора кода да самого компилятора. Таким образом, редактор кода - это наиболее характерный и устоявшийся элемент в любой среде разработки приложений.

Применительно ко всем современным версиям Delphi, редактор кода имеет все стандартные возможности редактирования текста (вроде работы с буфером обмена), а так же ряд особенностей, характерных для редакторов кода, а именно:

  1. Редактор всегда работает с моноширинным шрифтом (т.е. все буквы имеют одинаковую ширину). Это необходимо, поскольку в противном случае было бы тяжело ориентироваться в коде программы;
  2. Моноширинный режим позволяет использовать такой метод, как колоночную разбивку. Иначе говоря, копировать и перемещать можно не только отдельные слова или строки, но и вырезать, копировать и вставлять прямоугольные фрагменты текста;
  3. Редактор постоянно отображает позицию курсора, т.е. в какой строке и колонке находится точка ввода;
  4. Отсутствие автоматического переноса строк. Поскольку в программировании каждый символ, включая обрыв строки, что-то значит, то чтобы программисты не гадали, где в коде конец строки, а где автоматический перенос, такого режима правки нет в принципе. К тому же это мешало бы ориентироваться в номерах строк;
  5. Подсветка синтаксиса выделяет ключевые слова и прочие специфические языковые конструкции;
  6. При перемещении по тексту стрелкой вправо по окончании текста в строке, курсор не переносится на сроку вниз, а продолжает перемещаться дальше;
  7. Вы можете устанавливать закладки, т.е. помечать место в тексте при помощи сочетания горячих клавиш и быстро перемещаться между ними;
  8. Также предусмотрены такие функции, как автоподстановка кода по ключевым фразам, автозавершение кода и т.д.

При всем этом следует отметить, что практически все функции редактора, включая правила подсветки, сочетания горячих клавиш, поведение курсора, автоподстановка и т.д., гибко настраиваются. Для этого следует открыть окно свойств редактора (Tools Editor options) и настроить параметры на свое усмотрение. Впрочем, если у вас еще не сложились какие-то предпочтения в работе с подобными редакторами, то можно этого и не делать - предлагаемые изначально настройки вполне удобны.

Что касается внешнего вида окна редактора, то в нем, при стандартных параметрах IDE, помимо области редактора кода имеется еще и проводник кода, упрощающего процесс навигации по файлу (рис. 2.8).


Рис. 2.8. Окно редактора кода с проводником и загруженным файлом новой формы

Обратите внимание на то, что весь программный код файла main.pas, показанный в этом окне, был создан автоматически, равно как и код для файла проекта - first.dpr. Иначе говоря, всю работу по созданию базовых блоков приложения интегрированная среда Delphi делает за вас.

Завершая тему окна редактора, отметим, что для того, чтобы загрузить в него какой-либо произвольный файл, следует воспользоваться главным меню (File Open). При открытии проекта файлы открытых форм загружаются в него автоматически, а чтобы загрузить в него иные файл проекта, используйте кнопку View Unit (сочетание горячих клавиш - Ctrl+F12) на инструментальной панели View. Если же требуется загрузить как исходный код, так и саму форму, то воспользуйтесь находящейся по соседству кнопкой View Form (Shift+F12).

Ну и последнее не рассмотренное нами окно - Object TreeView, или окно дерева объектов, служит для просмотра иерархии элементов управления (кнопок, переключателей и т.п.) относительно формы. Т.е., если проводник кода упрощает процесс поиска того или иного компонента в исходном коде программы, то дерево объектов поможет быстрее сориентироваться в элементах, находящихся на форме.

Создание приложения командной строки

Итак, мы уже ознакомились со всеми основными функциями IDE Delphi, и даже создали простейшее приложение для Windows. Однако целью данной части книги является все-таки изучения основы основ - языка Object Pascal. Поэтому для того, чтобы не отвлекаться по ходу его изучения на второстепенные (по отношению к самим языковым конструкциям) детали, рассмотрим вариант создания консольного приложения, т.е. фактически, программы для DOS. Не стоит думать, что это будет шагом назад, или что это давно морально устарело. На самом деле, абсолютно все правила языка действуют совершенно одинаково для любых программ, будь они под DOS, Windows, .NET, или Linux. Вместе с тем, отсутствие необходимости в параллельном изучении специфических для конкретной платформы особенностей (а уж тем более - в параллельном изучении такой обширной библиотеки, как VCL!) существенно упростит нашу задачу. Более того, консольные приложения в типичном случае могут состоять всего лишь из одного единственного файла, что так же упрощает понимание предмета изучения, коим на настоящий момент является сам язык программирования. Ну а после того, как будет выучен язык, применить его для создания полноценных Windows-приложений не составит труда, да и изучение VCL станет легче ввиду того, что будет ясно, что, как и почему в ней устроено.

После такого небольшого отступления, приступим к созданию первого консольного приложения в среде Delphi. Для этого откройте окно New Items (File New Other) и на закладке New дважды щелкните по значку Console Application. В результате откроется окно редактора с загруженным в него проектом (листинг 2.1).

Листинг 2.1. Заготовка приложения командной строки

Program Project1; {$APPTYPE CONSOLE} uses SysUtils; begin { TODO -oUser -cConsole Main: Insert code here } end.

Первой строкой идет название программы, в данном случае это Project1, затем Delphi вставило для себя указание, что это - приложение для командной строки, после чего следует ключевое слово "uses" и перечисление необходимых дополнительных файлов (sysutils), ну и после этого, со слова begin начинается собственно тело программы. Завершается любая программа в Pascal ключевым словом end с точкой. Между ключевыми словами begin и end, в фигурных скобках, вставлен автоматический комментарий, не влияющий на выполнение программы, так что при желании можно его удалить.

А теперь самостоятельно напишем первую программу в Delphi! По традиции, она у нас будет выводить фразу "Hello, World!". Для этого на том месте, где находился комментарий, напишем одну строчку кода:

Write(Hello, World!);

Все! Теперь можно сохранить и скомпилировать нашу программу. Для этого щелкните по кнопке Save или Save All на стандартной панели инструментов, в качестве пути к файлу укажите какой-либо каталог на вашем жестком диске (например, создайте папку HelloWorld на диске C:), а саму программу можно назвать hello. Таким образом, все наше приложение будет сохранено, а исходный код примет вид, показанный в листинге 2.2.

Листинг 2.2. Программа hello

Program hello; {$APPTYPE CONSOLE} uses SysUtils; begin write(Hello, World!); end.

Обратите внимание, что название изменилось автоматически. Теперь остается получить исполняемый (exe) файл, для чего скомпилируем программу, нажав Ctrl+F9. Теперь запустим программу. Поскольку она у нас рассчитана на режим командной строки, то для начала откроем командную строку (Пуск > Все программы > Стандартные > Командная строка в Windows XP, или Пуск > Программы > Стандартные > Сеанс MS-DOS в Windows 98). В командной строке вызовем нашу программу, не забыв указать полный путь к ней. Например, если вы сохранили проект в C:\HelloWorld, а саму программу назвали Hello, то и путь укажите соответствующий, т.е.:

C:\HelloWorld\hello.exe

Запустив программу (т.е. введя в командной строке путь и нажав Enter), вы сразу же увидите результат ее выполнения - она выведет фразу "Hello, World!", и завершится. Собственно говоря, именно по этой причине мы сначала открыли командную строку, а лишь затем запустили программу, поскольку непосредственный ее запуск (через Проводник Windows, или прямо из Delphi - по F9), привел бы к тому, что на экране просто мелькнул бы автоматически запущенный сеанс MS-DOS и сразу закрылся бы. Это объясняется тем, что программа завершает свою работу сразу после того, как будет достигнут ее конец, обозначенный как "end.", а это в нашем случае произойдет моментально после вывода текста. Но мы можем изменить такое ее поведение, добавив еще одну сроку кода непосредственно после "write(Hello, World!);", которая будет дожидаться момента, пока пользователь не нажмет клавишу Enter. Выглядеть она будет так:

Теперь можно запустить наше приложение прямо из среды Delphi, нажав F9. В результате можно будет наблюдать надпись "Hello, World!" на фоне черного окна автоматически запущенного сеанса консоли командной строки до тех пор, пока вы не нажмете Enter.

Исходный код программы вы найдете в папке Demo\Part1\HelloWorld на прилагаемом компакт-диске (или в архиве


© 2024
alerion-pw.ru - Про лекарственные препараты. Витамины. Кардиология. Аллергология. Инфекции