0.98M
Category: softwaresoftware

Панели инструментов и другие элементы интерфейса

1.

10.ПАНЕЛИ ИНСТРУМЕНТОВ И ДРУГИЕ ЭЛЕМЕНТЫ ИНТЕРФЕЙСА
Одним из характерных свойств многих Windows-приложений является
присутствие панелей инструментов вверху окна и строки состояния внизу.
10.1. РАЗНОВИДНОСТИ ПАНЕЛЕЙ
В программировании часто возникает необходимость группировки
нескольких компонентов. В Delphi панель можно рассматривать как элемент, позволяющий разделять клиентскую область фрейма на несколько
частей и группировать другие компоненты. Простейшая панель – компонент
Panel - представляет собой контейнер общего назначения. Часто он помещается в форму для того, чтобы располагать вставленные в него дочерние
компоненты вдоль одной из сторон окна независимо от изменения размеров
этого окна. Кроме того, этот компонент содержит внутреннюю и внешнюю
кромки, что позволяет создать эффекты «вдавленности» и «выпуклости».
Располагается компонент Рanel на странице Standart палитры компонентов.
В случае, когда компонентов, которые нужно расположить на панели,
много, в целях экономии пространства формы, используется панель с прокруткой ScrollBox. Если размещенные в ней компоненты выйдут за пределы
рабочей области, то по сторонам панели возникнут полосы прокрутки. Наиболее подходящей областью применения этого компонента является размещение в нем относительно длиных Edit, Memo, ComboBox и т.д. Компонент
ScrollBox располагается на странице Additional.
Для размещения разного рода служебной информации в окнах редактирования используется компонент StatusBar страницы WIN32. С ним связан
объект класса TStatusPanel, к которому относятся все панели компонента
StatusBar. Этот компонент находится на странице Win32.
На указанной странице палитры компонентов можно найти еще несколько видов панелей, а также компонент PageControl, представляющий
собой набор панелей с закладками. Эти панели относятся к классу TTabSheet
и перекрывают друг друга. Каждая панель выбирается связанной с ней закладкой и может содержать свой набор, помещенных в нее компонентов.
В этой главе рассмотрим особомый вид панелей – инструментальные.
К ним относятся панели ToolBar и CoolBar страницы WIN32 и компонент
ControlBar страницы Additional.
10.1.1. Компонент ToolBar
Компонент TToolBar представляет совой специальный контейнер для
создания инструментальных панелей. Главная отличительная черта TToolBar – его способность гибкого управления дочерними элементами, которые
он может группировать, выравнивать по размерам, располагать в несколько
рядов. Компонент может манипулировать любыми вставленными в него дочерними элементами, но все его возможности в полной мере проявляются
3

2.

только при совместном использовании со специально для него разработанным компонентом TToolButton (инструментальная кнопка). Поскольку этот
компонент разработан специально для TToolBar, его нет в палитре компонентов. Для того, чтобы вставить его в инструментальную панель нужно
щелкнуть правой кнопкой мыши на компоненте TToolBar и выборе NewButton. Если осуществить ту же последовательность действий, но вместо NewButton, выбрать NewSeparator, то в панель будет вставлен сепаратор – разновидность инструментальной кнопки, предназначенная для функционального
выделения на панели групп элементов. О том, что данная кнопка является
сепаратором, можно узнать из свойства Style.
Компонент TToolButton не имеет свойства, предназначенного для хранения картинки, однако TToolBar умеет использовать контейнер TimageList,
чтобы извлечь из него нужную картинку и поместить ее на инструментальную кнопку.
Свойство Buttons компонента TToolBar позволяет обратится к каждому
дочернему компоненту как к объекту класса TToolButton, имеющему такие
свойства (в этой и следующих таблицах не указаны свойства, присущие всем
компонентам Delphi). Эти свойства кнопок приведены в табл. 10.1.
Таблица 10.1
Property AllowAllUp: BooЕсли содержит True, синхронизирует
lean;
свое состояние с состоянием других кнопок
в той же группе: в любой момент времени
может быть нажата только одна кнопка
группы. Игнорируется, если Grouped=False.
Property Caption: String;
Содержит связанный с кнопкой текст,
который будет показан, если свойство
ShowCaptions компонента TtoolBar имеет
значение True.
Property Down: Boolean;
Определяет состояние кнопки: если содержит True, кнопка утоплена.
Property DropdownMenu:
Связывает вспомогательное меню с наTpopupMenu;
жатой кнопкой.
Property Grouped: Boolean;
Разрешает/запрещает учитывать свойство AllowAllUp.
Property ImageIndex: InteОпределяет индекс связанного кнопкой
ger;
изображения.
Property Interminate: BooЗапрещает/разрешает выбор кнопки.
lean;
4

3.

TtoolButtonStyle = (tbsButton, tbsCheck, tbsDropDoun,
tbsSeparator, tbsDivider);
Property
Style:TtoolButtonStyle;
Property Wrap: Boolean;
Продолжение табл. 10.1
Определяет стиль кнопки: tbsButton –
обычная кнопка; tbsCheck – западающая
кнопка (остается в нажатом положении; для
ее освобождения нужно щелкнуть по ней
еще раз); tbsDropDown – кнопка с символом
раскрывающегося списка; tbsSeparator –
разделитель (на месте этой кнопки будет
пустое иесто); tbsDivider – разделитель (в
работающей программе на месте этой кнопки будет вертикальная черта).
Если имеет значение True, кнопка завершает текущий ряд кнопок. Игнорируется, если свойство Wrapable компонента
TtoolBar имеет значение True.
Свойства самого компонента TtoolBar приведены в табл. 10.2.
Таблица 10.2
Property AutoSize: BooЕсли содержит True, высота компоненlean;
та будет автоматически согласовываться с
высотой кнопок.
Property ButtonCount: InСодержит количество вставленных в
teger;
инструментальную панель дочерних компонентов (не только кнопок TtoolButton).
Property ButtonHeight: InОпределяет высоту кнопок TtoolButteger;
ton.
Property DisabedImages:
Определяет контейнер для изображеTimageList;
ний запрещенных кнопок.
Property Flat: Boolean;
Если содержит True, панель и кнопки
на ней прозрачны для фона и вокруг
кнопки появляется граница, только когда
над ней располагается указатель мыши.
Property HotImages: TiОпределяет контейнер изображений
mageList;
для кнопок в момент, когда над кнопкой
распологается указатель мыши.
Property
Images:
TiОпределяет контейнер для изображеmageList;
ний кнопок в обычном состоянии.
Property Indent: Integer;
Определяет отступ в пикселях от левого края компонента для первого дочернего
элемента.
5

4.

Property List: Boolean;
Продолжение табл. 10.2
Если имеет значение True, изображение прижимается к левой границе кнопки,
а текст – к правой, в противном случае
текст выводится под изображением. Игнорируется, если ShowCaptions = False.
Содержит количество рядов кнопок.
Property RowCount: Integer;
Property ShowCaptions:
Разрешает/запрещает показ на кнопках
Boolean;
текста.
Property Wrapable: BooЗапрещает/разрешает
располагать
lean;
кнопки в нескольких рядах.
Для компонента определено событие OnResize, возникающее при изменении размеров компонента.
Внешний вид инструментальной панели, созданной на основе компонента ToolBar представлен на рис. 10.1.
Рис. 10.1. Пример использования компонента ToolBar
10.1.2. Компонент TCoolBar
Компонент TCoolBar предназначен для создания настраиваемых инструментальных панелей. Для каждого размещаемого на нем элемента эта
инструментальная панель создает объект класса TCoolBand (полоса), который может изменять свои размеры и положение в пределах границ компонента.
Центральным свойством компонента является Band – массив созданных в компоненте полос TCoolBand. Каждая полоса может иметь текст, пик6

5.

тограмму и произвольный управляющий элемент. В отличие от компонента
TToolBar или рассмотренного ниже TControlBar полоса в TCoolBar содержит только один интерфейсный элемент, но он может быть контейнером для
размещения нескольких компонентов. Размещенный на полосе компонент
окружен специальным окном TCoolBar и всегда стремится занять левый
верхний угол полосы, при этом остальные размеры полосы изменяются таким образом, чтобы полностью охватить элемент.Обращение к элементу
осуществляется через свойство компонента CoolBar.Bands. Далее в квадратных скобках указывается индекс полосы, то есть ее номер по порядку, начиная с нуля.
Свойства компонента TcoolBand сведены в табл. 10.3.
Таблица 10.3
Property
BitОпределяет изображение, которое будет
map:TBitmap;
циклически повторяться по всему пространству полосы.
Property
BorderОпределяет значение рамки у полосы:
Style:TBorderStyle;
bsNone – нет рамки; bsSingle – рамка толщиной в 1 пиксель.
Property Break:Boolean;
Если содержит True, то полоса располагается в новой строке, в противном случае – в
той же строке, что и предыдущая полоса.
Property
ConУказывает элемент, который содержит
trol:TWinControl;
полоса.
Property
FixedBackЗапрещает/разрешает периодическое поGround:Boolean;
вторение изображения Bitmap по всей поверхности полосы.
Property
FixedЗапрещает/разрешает изменение размеров
Size:Boolean;
полосы
Property
HorisontaПредписывает показывать полосу только
lOnly:Boolean;
для значения False свойства Vertical компонента – владельца ToolBar.
Property
ImageInСодержит индекс связанного с полосой
dex:Integer;
изображения
Property
MinОпределяет минимальное значение высоHeight:Integer;
ты полосы при изменении ее размеров
Property
MinОпределяет минимальное значение шириWidth:Integer;
ны полосы при изменении ее размеров
Property
ParentBitРазрешает/запрещает использовать значеmap:Boolean;
ние свойства Bitmap компонента – владельца
TCoolBar вместо собственного свойства Bitmap.
7

6.

Продолжение табл. 10.3
Property Text:String;
Содержит текст полосы.
Property
VisiЕсли содержит False, то полоса не видна
ble:Boolean;
на этапе прогона программы.
Property
Определяет ширину полосы в пикселях
Width:Boolean;
Свойства компонента TcoolBar рассмотрены в табл. 10.4.
Таблица 10.4
Property
AutoЕсли содержит True, высота компонента
Size:Boolean;
будет автоматически согласовываться с высотой полос.
Property
BandBorderОпределяет наличие рамок: bsNone – нет
Style:TBorderStyle;
рамки, bsSingle – каждая полоса имеет рамку
толщиной в 1 пиксель.
Property
Содержит список всех полос. Свойство
Bands:TCoolBands;
Items этого объекта открывает доступ к полосе по ее индексу.
Property
BitОпределяет изображение, которое будут
map:TBitmap;
использовать все полосы.
Property
FixedOrЗапрещает/разрешает перемещение поder:Boolean;
лос.
Property
FixedЗапрещает/разрешает изменение размера
Height:Boolean;
полос
Property
ImУказывает на контейнер для изображеages:TImageList;
ний, связанных с каждой полосой
Property
ShowЕсли содержит True, то на полосе покаText:Boolean;
зывается связанный с ней текст
Property
VertiЕсли содержит True, полосы располагаcal:Boolean;
ются по вертикали объекта.
Для этого компонента определены события OnChange:TNotifyEvent,
возникающее при изменении свойств Break, Index или Width у любой полосы и OnResize:TNotifyEvent, которое проявляется при изменении размеров
компонента. Внешний вид использования компонента – рис. 10.2.
8

7.

Рис. 10.2. Пример использования компонента CoolBar
10.1.3. Компонент TControlBar
Компонент служит удобным контейнером для размещения инструментальных панелей TtoolBar. Панель элементов может, как и компонент CoolBar, содержать в себе несколько управляющих элементов; при этом она предоставяет сходный пользовательский интерфейс – в ней также можноперетаскивать элементы и реорганизовывать панель во время выполнения.
Свойства компонента приведены в табл. 10.5.
Таблица 10.5
Property AutoDrag: BooРазрешает/запрещает
компонентам
lean;
ToolBar покидать границы ControlBar.
Property Picture: TPicСодержит изображение, которое, периоture;
дически повторяясь, создает фон компонента.
Property
RowSize:
Задает высоту одного ряда инструменTrowSize;
тальных панелей. Умалчиваемое знание 25 в
точности соответствует высоте одной панели, и в этом случае между рядами нет зазора.
Property RowSnap :
Если содержит True, «причаливаемая»
Boolean;
панель будет выравниваться по высоте ряда.
9

8.

Метод
Procedure StickControls; virtual;
Устанавливает все дочерние компоненты на их окончательные позиции
после «причаливания» или «отчаливания» очередной инструментальной панели. Его нужно перекрыть, если стандартное размещение панелей по каким-либо причинам вас не устраивает.
События компонента сведены в табл. 10.6.
Таблица 10.6
TbandInfoEvent = proceВозникает при перемещении панели
dure (Sender: TObject; Con- внутри компонента: Sender – компонент;
trol: TControl; var Inserts: Control – панель; Insets – зазор между стороTRect; var PreferredSize, нами компонента и панели; PreferredSize –
RowCount: Integer) of object; предпочтительная ширина панели; RowCount
Property OnBandInfo:
– количество рядов панелей.
TbandInfoEvent;
TbandMoveEvent = proВозникает при перемещении панели
cedure (Sender: TObject; Con- внутри компонента: Sender-компонент; Control: TControl; ARect: TRect) trol-панель; ARect-прямоугольник для разof object;
мещения панели.
Property OnBandMove:
TbandMoveEvent;
TbandPainEventn = proВозникает при необходимости прорисовcedure (Sender: TObject; Con- ки панели: Sender-компонент; Controltrol: TControl; Canvas: Tcon- панель;
vas; var ARect: TRect; var
Canvas-канва для прорисовки; ARectOptions: TBandPainOptions) прямоугольник
прорисовки;
Optionsof object;
определяет, какая часть панели нуждается в
прорисовке.
Property OnPaint: TnotiВозникает при необходимости прорисовfyEvent;
ки компонента.
Пример использования компонента ControlBar изображен на рис. 10.3.
10

9.

Рис. 10.3. Пример использования компонента ControlBar
10.1.4. Меню в панели компонентов
При программировании часто возникает необходимость в создании
всевозможных меню. Язык программирования Delphi позволяет наряду с
главным меню (компонент MainMenu) создавать меню, связанные с отдельными компонентами. В частности, таким меню может являться компонент
Popupmenu, прицепленный к какому – то компоненту. Для того, чтобы осуществить такое прикрепление, нужно в свойстве Popupmenu компонента
указать имя компонента-меню. Если эта операция произведена, то при нажатии правой клавиши мыши над компонентом будет возникать вспомогательное меню, свойства и сам процесс создание которого ничем ни отличаются
от основного.
Использование панелей, в частности инструментальных, позволяет
объединить несколько компонентов в группы, защитить компоненты от смещения при изменении размеров окна. Из рассмотренных панелей наиболее
удобной в использовании является панель СontrolBar, так как она позволяет
разместить компоненты различного типа, не теряя при этом своих свойств (в
отличие от панели ToolBar), и может содержать на одной полосе несколько
элементов, чего не может сделать CoolBar (если только эти элементы не объединены общей панелью).
10.2. СТРОКА СОСТОЯНИЯ
Визуальный компонент Строка Состояния (СС) — элемент, делающий приложение более привлекательным для возможных потребителей. Вообще говоря, не всем приложениям она одинаково необходима, но в некоторых оказывается чрезвычайно полезной. VCL-компонент StatusВаг, инкапсулирующий строку состояния Win32, значительно ускоряет ее создание.Строка состояния используется для многих целей. Наиболее часто ее
используют для вывода на экран информации об элементе меню, который в
11

10.

настоящее время выбран пользователем. Форма со строкой состояния приведена на рис. 10.4.
Рис. 10.4. Форма со строкой состояния
Компонент TStatusBar – это ряд панелей, обычно располагающихся в низу Формы и показывающий информацию о приложении,
как только оно запускается. Каждая панель представлена как объект
TStatusPanel, занесенный в список свойства Panels. Свойство SimplePanel используется для переключения Строки Состояния между
режимами Одиночной Панели и Множества Панелей.
Строка Состояния обычно занимает нижнюю часть окна и показывает текст. Хотя можно использовать Delphi’s Panel для создания строки состояния, легче использовать Windows StatusBar. Можно вообще подразделить СС на несколько составных текстовых зон. Свойство Align компонента
StatusBar по умолчанию установлено как alBottom, которое задает местонахождение и размер.
Для создания «панелей» в компоненте StatusBar надо использовать
свойство Panels и Panels editor. Пока панель выбрана в открытом Panels editor, можно установить ширину панели и другие ее свойства.
Перечислим в табл.10.7 сначала основные свойства компонента
StatusВаr.
Свойство
AutoHint:
Panels
Таблица 10.7
Описание
Автоматически выводит в строке состояния подсказку, когда курсор проходит над любым компонентом с установленным свойством Hint.
Используется в строках состояния с несколькими
панелями. Определяет Панели в СС. Это свойство –
множество объектов TstatusPanel. Во время разработки
можно добавлять, удалять или изменять Панели посредством Panels editor. Чтобы его открыть, надо выбрать свойство Panels в Object Inspector и затем нажать
кнопку (…).
12

11.

SimplePanel
SimpleText
SizeGrip
UseSystemFont
Продолжение табл. 10.7
Определяет, показывает ли СС Одиночную Панель
или Множество Панелей. Если это свойство установлено как True, то СС содержит одну Панель, показывающую текст в SimpleText, а если как False, то СС
содержит отдельные Панели для каждого раздела.
Чтобы переопределить это свойство во время выполнения приложения, надо делать это программным способом.
Содержит текст простой панели строки состояния.
Определяет, будет ли строка состояния иметь захват изменения размера окна в правом нижнем углу.
Захват изменения размера — это область, за которую
пользователь может перетаскивать угол окна, меняя
его размер. Отсутствие захвата не означает, что размер
окна нельзя изменить, но его наличие упрощает эту
операцию. Захват не будет нарисован, если TstatusBar
не используется в TcustomForm со свойством BorderStyle, определенным как bsSizeable или bsSizeToolWin.
Если свойство Align установлено как alBottom, alRight,
или alClient, захват не будет работать. Если свойство
Alignment последней Панели в СС установлено как
taRightJustify, захват будет задвигать ее текст.
Если True, всегда используется системный шрифт,
вне зависимости от установок свойства Font. Особенно
полезно, если используются экранные темы пакета
Plus!.
Табл. 10.8 содержит дополнительные свойства компонента StatusBar.
Таблица 10.8
Свойство
Описание
Height
HelpContext
Left
Parent
PopupMenu
Определяет высоту СС.
Это свойство используется для связывания индекса
в справочном файле с СС.
Определяет х-координату СС.
Указатель родительского объекта.
Определяет контекстное (всплывающее) меню,
отображаемое при нажатии правой кнопки мыши.
13

12.

Top
Visible
Width
Продолжение табл. 10.8
Определяет y-координату СС.
При чтении указывает, является ли СС в настоящее
время видимым. При записи значения в Visible СС
может быть сделан видимым или скрытым.
Определяет ширину СС.
10.2.1. Свойства строки состояния
На более важных свойствах остановимся несколько подробнее.
10.2.1.1. Свойство Name
Свойство Name имеет для компонентов жизненно важное значение.
Delphi создает указатель на компонент и использует свойство Name в качестве имени переменной.
Delphi использует значение свойства Name также для образования
имен обработчиков событий. Допустим, нам надо обрабатывать событие
OnClick компонента StatusBar. Обычно мы дважды щелкаем в столбце Value
рядом с событием OnClick, чтобы Delphi генерировала соответствующий
обработчик. Delphi будет использовать для этой функции имя по умолчанию, исходя из значения свойства Name и имени обрабатываемого события.
Можно изменять свойство Name в любое время, но только при условии, что вы делаете это через инспектор объектов. Когда при разработке
программы мы изменяем свойство Name некоторого компонента, Delphi
просматривает весь созданный ранее код и изменяет имя указателя, а также
имена всех функций-обработчиков событий.
При изменении свойства Name компонента Delphi внесет соответствующие изменения в код, генерируемый автоматически, но оставит без изменения наш текст. О коде надо заботиться самим. Вообще говоря, свойство
Name следует устанавливать при первоначальном размещении компонента
на форме и в дальнейшем его не трогать. Конечно, нет никаких препятствий
к тому, чтобы поменять имя позднее, но это может потребовать излишних
затрат вашего труда.
Ни в коем случае нельзя изменять свойство Name во время выполнения программы и изменять вручную имя компонента (то имя, которое
Delphi присваивает указателю на компонент) или имена обработчиков событий в окне редактора кода. Если вы выполните любое из этих действий, то
Delphi потеряет контроль над компонентом, и результат, мягко говоря, будет
14

13.

неудовлетворительным. Возможно, вам даже не удастся загрузить форму.
Единственный безопасный способ изменения свойства Name компонента —
использовать для этой цели инспектор объектов.
Для каждого компонента, помещаемого на форму, Delphi устанавливает значение свойства Name по умолчанию. Если вы, например, размещаете
компонент StatusBar, то Delphi присвоит свойству Name значение StatusBar1.
Если вы поместите на форму второй компонент StatusBar, он получит имя
StatusBar2 и т. д. Вам следует как можно скорее давать компонентам осмысленные имена, чтобы избежать впоследствии путаницы и лишней работы.
10.2.1.2. Свойство Color
Свойство Color определяет цвет фона компонента (цвет текста устанавливается свойством Font). Хотя использование свойства Color очень просто, здесь есть свои особенности, о которых следует сказать.
Порядок работы со свойством Color в инспекторе объектов в некотором смысле уникален. Если щелкнуть в столбце Value, то мы увидим
кнопку со стрелкой вниз, указывающую на возможность выбора цвета из
списка. Но кроме этой возможности, есть еще одна. Если щелкнуть дважды
в том же столбце Value, то на экране появится диалог выбора цвета. В этом
диалоге вы можете выбрать один из предопределенных цветов или создать
ваши собственныe цвета. Та же самая диалоговая панель Color будет отображаться при использовании в приложении компонента ColorDialog.
Когда вы нажмете кнопку со стрелкой, то в появившемся окне увидите две группы значений. Первая группа цветов начинается с clBlack и заканчивается clwhite. Это предопределенные цвета Delphi; в списке представлены наиболее употребительные из них. Чтобы выбрать один из перечисленных цветов, просто щелкните на нем в списке. Если вас не устраивает ни
один предложенный цвет, вы можете вызвать диалоговую панель Color, как
говорилось выше.
Вторая группа цветов в списке начинается с цвета clScrollBar. Эта
группа содержит системные цвета Windows. Если вы используете цвета из
этого списка, ваше приложение будет автоматически менять цвета при изменении цветовой схемы Windows. Если вы хотите, чтобы ваше приложение
придерживалось системной цветовой схемы, выбранной пользователем системы, вы должны выбирать цвета только из этой части списка.
10.2.1.3. Курсоры
Свойство Cursor определяет вид курсора мыши во время его перемещения через СС. Для некоторых компонентов Windows автоматически
изменяет курсор. Например, Windows изменяет курсор на вертикальный
штрих «I», когда он расположен над компонентами Edit, Memo или RichEdit
15

14.

(это - лишь некоторые). Если мы хотим оставить управление курсором за
Windows, то не надо изменять значение этого свойства, установленное по
умолчанию — crDefault. Если у нас есть специализированные СС, то мы
можем определить для них и специальный курсор. Когда курсор мыши окажется над этим компонентом, Windows изменит вид курсора на заданный
нами.
Часто требуется менять курсор во время выполнения программы.
Длительный процесс, например, может быть обозначен для пользователя
курсором в виде песочных часов. Затем мы должны придать курсору
первоначальный вид. Следующий фрагмент кода демонстрирует, как это
можно сделать:
var
OldCursor : TCursor;
begin
OldCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
{некоторая длительная операция}
Screen.Cursor := OldCursor;
end;
Этот код гарантирует, что курсор, первоначально использованный в
приложении, будет восстановлен правильно.
Другое свойство, DragCursor, определяет курсор, который используется,
когда при операции drag-and-drop курсор проходит над СС, поддерживающей эту операцию.
10.2.1.4. Свойство Enabled
Доступ к СС можно разрешить или запретить, используя свойство
Enabled. Когда СС недоступна, она не может получить фокус ввода (щелчок
на таком объекте не дает никакого эффекта). Для обозначения такого компонента обычно применяется некоторый визуальный эффект. Свойство Enabled — булева типа и может принимать только два значения: True, если
компонент доступен, и False в противном случае. Разрешение и запрещение
доступа к окнам (не забывайте, что компоненты оконного типа также являются окнами) — это механизм, обеспечиваемый самой системой Windows.
Хотя доступ к СС может быть запрещен на этапе проектирования,
операция разрешения/запрещения доступа обычно выполняется во время
работы программы.
Чтобы запретить доступ к компоненту во время выполнения программы, нужно присвоить значение False его свойству Enabled, а чтобы сде16

15.

лать его доступным, это свойство должно получить значение True. Следующий фрагмент кода включает или выключает пункт меню в зависимости от
некоторого условия:
if CanSave then
FileSave.Enabled := True
else
FileSave.Enabled := False;
Этот процесс часто называется разрешением команд и является важной
частью профессиональных программ для Windows.
10.2.1.5. Свойство Font
Свойство Font (шрифт) — одно из основных свойств и, следовательно, должно быть рассмотрено, хотя о нем и не требуется много говорить. Свойство Font — экземпляр класса TFont и имеет собственные свойства. Мы можем определить свойства для Font, дважды щелкнув на имени
шрифта в инспекторе объектов (после этого узел Font раскроется, и мы увидим список его вложенных свойств), или вызвав диалоговую панель Font.
Свойство Color определяет цвет шрифта, а свойство Name позволяет
нам выбрать желаемую гарнитуру.
Свойства Height (высота) и Size (размер) класса TFont заслуживают
специального упоминания:
Свойство Height используется для определения высоты шрифта в
пикселах.
Свойство Size определяет кегль шрифта в пунктах.
Когда мы изменяем одно из этих свойств, другое изменяется автоматически. Шрифт может быть пропорциональным или фиксированной ширины:
1) Большинство шрифтов являются пропорциональными. Это означает, что для изображения каждого символа отводится столько места, сколько действительно необходимо. Например, для изображения символа М в
верхнем регистре требуется намного больше места, чем для символа i в
нижнем регистре. Пропорциональными являются такие шрифты, как Times
New Roman, Arial и Bookman.
2) У шрифта фиксированной ширины (их часто называют моноширинными), наоборот, под все символы отводится одинаковое пространство
по горизонтали. Такие шрифты удобно использовать в редакторах кода (как
это сделано в редакторе кода Delphi) или в любых других окнах, где жела17

16.

тельно, чтобы шрифт имел фиксированный шаг. Вероятно, наиболее употребительный из таких шрифтов — это Courier New, хотя во многих приложениях Windows применяется шрифт Fixedsys. Моноширинные шрифты
труднее читать, поэтому они редко используются для чего-либо, кроме программного кода.
Теоретически, свойство Pitch может использоваться для принудительной замены пропорционального шрифта на моноширинный и наоборот.
Но проблема состоит в том, что Windows в этом случае может изменить гарнитуру шрифта, и вы не можете точно сказать, что получится в результате.
Гораздо надежнее точно выбирать шрифт, который нам требуется, чем полагаться на свойство Pitch.
Наконец, свойство Style (стиль) класса TFont может использоваться
для установки полужирного, курсивного, подчеркнутого или перечеркнутого шрифта. Эти стили не исключают друг друга, так что вы можете смешивать их по своему выбору.
Для изменения свойств шрифта мы можете использовать инспектор
объектов, однако диалог Font имеет одно преимущество: в нем можно видеть, как будет изменяться шрифт по мере выбора вами различных установок. Чтобы просто изменить, например, свойство Style или size, надо использовать инспектор объектов. Но если мы занимаемся подбором нужного
шрифта, то для этого лучше подойдет диалоговая панель Font.
10.2.1.6. Подсказки
Свойство Hint задает текст подсказки для компонента. Текст подсказки состоит из двух частей. Первая часть иногда называется краткой подсказкой. Именно этот текст выводится, когда пользователь задерживает курсор над компонентом. Всплывающее окно, в котором отображается текст
подсказки, называется всплывающей подсказкой (ToolTip).
Вторую часть текста подсказки называют длинной подсказкой.
Длинная подсказка — это необязательный текст, который выводится в строке состояния, когда пользователь устанавливает курсор мыши на компоненте. Тексты короткой и длинной подсказок отделяются друг от друга символом «|». Например, чтобы определить как короткую, так и длинную подсказки для кнопки File Open, надо ввести следующий текст:
Открыть файл|Открыть файл для редактирования
Чтобы выводились краткие подсказки, надо установить для свойства showHint объекта Application значение True (значение по умолчанию) и
18

17.

присвоить это же значение свойству ShowHint компонента.
Мы можем задать только короткую подсказку, только длинную или
оба варианта. Символ «|» служит указателем на то, какую подсказку вы вводите. Если вы не используете этот символ, то введенный текст будет использоваться как для короткой, так и для длинной подсказки.
10.2.1.7. Свойства ParentColor, ParentBiDiMode, ParentFont и ParentShowHint
Свойства ParentColor, ParentBiDiMode, ParentFont И ParentShowHint
работают одинаковым образом, поэтому будем говорить о них одновременно. Когда эти свойства имеют значение True, СС наследует свойства Color,
BiDiMode, Font и ShowHint от своего родителя.
10.2.1.8. Свойство Tag
Свойство Tag представляет собой переменную размером в 4 байта,
зарезервированную для нашего использования. Мы можем использовать
свойство Tag для хранения любых данных, нужных для работы вашего компонента. Это может быть указатель на другой класс, индексное значение или
что-то еще. Использование свойства Tag, вероятно, должно рассматриваться
при углубленном изучении программирования.
10.2.2. Основные события
Как и в случае свойств и методов, среди событий имеются такие,
которые инициируются наиболее часто. Компоненты представляют большое
количество возможных элементов управления Windows, и каждый компонент имеет свои индивидуальные особенности. События, специфические для
форм, здесь не рассматриваются.
Перечислим наиболее часто используемые события в табл.10.9.
19

18.

Событие
OnClick
Таблица 10.9
Описание
Происходит при щелчке на СС любой кнопки
мыши.
OnDblClick
OnDrawPanel
Происходит при двойном щелчке на СС.
Событие OnDrawPanel имеет место, когда Панель
Статуса должна быть перерисована, например когда
пользователь изменяет размеры СС. Параметр Rect
дает новые размеры и положение Панели Статуса.
OnDrawPanel имеет место, только если свойство Style
Панели Статуса установлено как psOwnerDraw.
OnHint
Имеет место перед тем, как показывается хинт
СС. Запишите код для события OnHint, чтобы определить текст хинта.
Событие возникает, когда на СС нажимается
кнопка мыши. Параметры, передаваемые обработчику события, содержат информацию о том, какая
кнопка была нажата и какие специальные клавиши
были при этом удерживались (Alt, Shift или Ctrl), а
также координаты х и у курсора мыши в момент нажатия.
Происходит при перемещении курсора мыши через элемент управления.
Событие возникает при отпускании кнопки мыши
на элементе управления, если перед этим кнопка была нажата на этом же элементе.
OnMouseDown
OnMouseMove
OnMouseUp
10.2.3. Основные методы
Некоторые из методов, перечисленных в табл. 10.10, достойны отдельного внимания.
20

19.

Таблица 10.10
Метод
Описание
Broadcast
Используется для отправки сообщений.
ExecuteAction
Указывает действия для СС. ExecuteAction вызывает DoHint. Если DoHint и AutoHint возвращают
True, то ExecuteAction показывает текущую подсказку приложения в первой Панели СС.
ContainsControl
Возвращает True, если СС является дочерним
для другого компонента или формы.
Create
Создает (с Холстами и Панелями) и инициализирует компонент TstatusBar.
FlipChildren
Меняет Панели местами – слева направо и наоборот.
Hide
Скрывает СС. После этого компонент может
быть снова отображен.
Invalidate
Запрашивает перерисовку СС. Компонент будет
перерисован Windows при первой же возможности.
Destroy
Уничтожает компонент TstatusBar и освобождает его память.
DoHint возвращает значение текущей процедуры демонстрации подсказки (была ли демонстрация).
Запрашивает немедленную перерисовку. Стирание фона СС перед этим не производится.
DoHint
Repaint
SetBounds
Позволяет вам задать свойства Top, Left, Width
и Height одновременно. Это удобнее, чем определять их по отдельности.
SetFocus
Устанавливает фокус ввода на СС и делает этот
компонент активным.
Update
Вызывает немедленную принудительную СС.
Обычно для этого следует использовать методы Refresh или Repaint.
21

20.

10.2.4. Простая или составная?
Строка состояния может быть простой или составной. Простая строка
состояния имеет единственную панель, которая занимает всю строку. Если
мы хотим создать простую строку, надо установить для свойства SimplePanel значение Тгие. Свойство SimplePanel действует как переключатель.
мы можем переключаться между простой или составной строкой состояния
во время выполнения программы, устанавливая SimplePanel равным соответственно True ИЛИ False.
Рис. 10.5 Простая строка состояния
На рис.10.5 видно, что хинты (подсказки) у кнопки и в Строке Состояния (простой) отличаются. Это достигается способом задания подсказки
с символом “|”, описанным выше.
Составная строка состояния имеет несколько панелей. Если вы
решили использовать составную строку, то можете настроить ее панели в
редакторе панелей строки состояния, который вызывается двойным щелчком в столбце Value свойства Panels. Чтобы добавить панель, щелкнем на
кнопке Add. Для удаления панели щелкните на кнопке Delete. Чтобы отредактировать существующую панель, выберите ее и измените свойства в инспекторе объектов.
Отдельные панели составной строки состояния являются экземплярами класса TstatusPanel.
Назначение большинства свойств ясно из названий, но два из них
22

21.

требуют некоторых пояснений. Свойство Text содержит текст, который будет отображен в панели. Это свойство может также использоваться для изменения текста панели во время выполнения программы. Установка текста
строки состояния рассматривается несколько позже; нам не нужно вводить
текст в панель на этапе разработки, если мы собираемся менять его по ходу
программы.
Свойство Style может иметь значения psText или psOwnerDraw. Если для Style установлено значение psText, поведение панели достаточно
очевидно. Текст выравнивается в зависимости от значения свойства Alignment. Если для Style установлено значение psOwnerDraw, то создание текста
или изображения для вывода на панель является полностью нашим делом.
Свойства панели Width, Bevel и Alignment говорят сами за себя.
Результат изменений, сделанных нами в строке состояния с помощью редактора панелей, можно сразу увидеть в конструкторе форм. Расположим редактор панелей так, чтобы во время работы в нем мы могли видеть
строку состояния. Каждое внесенное изменение будет отражено в конструкторе форм.
Когда мы закончим добавлять панели в строку состояния, нажмем
ОК, чтобы вернуться в конструктор форм.
Когда мы модифицируем свойство Panels компонента StatusBar,
конструктор форм автоматически устанавливает свойство SimplePanel в состояние False, предполагая, что нам не нужна простая строка состояния, если мы используем несколько панелей.
10.2.5. Изменение текста в строке состояния
Существуют два способа изменить текст в строке состояния:
1) Вручную модифицировать свойство SimpleText (для простых
строк) или свойство Text отдельной панели (для составных).
2) Разрешить VCL автоматически выводить текст, установив свойство AutoHint строки состояния равным True.
Ручное изменение текста в строке состояния выполняется очень
просто, особенно если мы имеем дело с простой строкой. Когда свойство
SimplePanel имеет значение True, мы просто устанавливаем в качестве значения свойства SimpleText тот текст, который должен выводиться в строку
состояния:
StatusBar.SimpleText := ‘This shows up in the …’;
Изменить текст в составной строке состояния немного сложнее. Если мы хотим изменить текст в первой панели составной строки, то должны
написать код следующего вида:
23

22.

StatusBar.Panels.Items[0].Text := ‘StatusBar Text’;
Свойство Panels компонента StatusBar имеет свойство Items, которое
представляет собой массив панелей строки состояния. Установка свойства
Text элемента массива изменяет текст соответствующей панели. Как видно,
данный массив имеет базовый индекс 0, т. е. первая панель в строке состояния — это элемент массива с индексом 0.
Автоматический вывод подсказок в строке состояния не требует
особых пояснений. Все, что нужно сделать — это установить True в свойстве AutoHint. Все остальное, как и предполагает имя свойства, будет происходить автоматически.
Даже при использовании автоматических подсказок можно вручную
изменить текст строки состояния. Нам ничто не мешает это сделать, но
нельзя забывать, что текст будет переписан, как только курсор мыши пройдет над компонентом, имеющим подсказку.
Внешний вид составной строки состояния показан на рис. 10.6.
Рис. 10.6. Составная строка состояния
10.2.6 Специальные панели строки состояния
24

23.

Панель может быть либо текстовой (psText), либо нарисованной пользователем (psOwnerDraw). Если для панели установлен стиль psOwnerDraw, то
ответственность за все, что будет отображено в этой панели, ложится на нас.
Маловероятно, что мы решимся на это только ради того, чтобы выводить в
специальную панель обычный текст. Такая панель обычно нужна для вывода в строку состояния какого-либо значка или битовой матрицы. Независимо от того, что будет нарисовано на панели, последовательность ее создания
останется той же:
1) Установить для свойства Style панели значение psOwnerDraw (обычно
через редактор панелей строки состояния).
2) Написать обработчик события OnDrawPanel.
Ясно, что здесь-то и начинается настоящая работа. Объявление обработчика события OnDrawPanel выглядит следующим образом:
Procedure TForm1StatusBar1DrawPanel(StatusBar
Panel : TstatusPanel; const Rect : TRect);
:
TStatusBar;
Параметр StatusBar является указателем на строку состояния. Как правило, у нас уже есть указатель на строку состояния (свойство Name компонента StatusBar), так что от этого параметра не так много пользы. Свойство
Panel является указателем на конкретную панель, которую необходимо нарисовать в данный момент. Мы можем использовать этот параметр, чтобы
определить, какая панель должна быть выведена, если наша строка состояния имеет более одной специальной панели. Параметр Rect содержит размер
и положение панели. Этот параметр важен, так как фактически он сообщает
нам точные размеры области рисования.
Обработчик события OnDrawPanel вызывается один раз для каждой
панели, свойство Style которой имеет значение psOwnerDraw. Если нам
нужно рисовать только на одной панели, то реально необходим лишь параметр Rect. Если же мы выводим изображения на несколько панелей, то сначала нам нужно определить, на какой панели рисовать, и только потом начинать вывод изображения.
Листинг содержит обработчик события OnDrawPanel.
10.2.7.Листинг.демонстрационнойl программы StatBar.
procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar;
Panel: TStatusPanel; const Rect: TRect);
var
R : TRect;
25

24.

Icon : Hicon;
begin
with StatusBar1.Canvas do begin
{Создание временного объекта TRect. Параметр Rect является}
{константой, поэтому мы не можем его изменять. }
R := Rect;
{Проверка: является ли панель 2 той панелью, которую нужно}
{нарисовать. Если да, вывод значка и текста на панель.}
if Panel.Index = 2 then begin
{ Изменение цвета текста на белый }
Font.Color := clWhite;
{Установка режима прозрачного фона так, чтобы белый текст был}
{виден под серым текстом и текст выглядел вдавленным.}
Brush.Style := bsClear;
{Вывод текста на панель}
TextRect(R,Rect.left+25,3,StatusBar1.Panels[2].Text);
{Изменение цвета на серый, поскольку мы собираемся нарисовать}
{в данный момент серый текст}
Font.Color := clGray;
{Вывод текста на панель}
TextRect(R,Rect.left+23,3,StatusBar1.Panels[2].Text);
{Загрузка одного из стандартных значков Windows. Здесь}
{проще использовать API, чем VCL. }
Icon := LoadIcon(0, IDI_HAND) ;
{Вывод значка и сжатие его до размера 15 х 15 пиксел.}
{Центровка значка в панели. }
DrawIconEx(Handle, Rect.Left+3, 3,
Icon, 15, 15, 0, 0, DI_NORMAL) ;
end;
end;
end;
Как объясняется в комментариях, объемный эффект достигается следующим образом: сначала текст рисуется белым цветом, а затем еще раз серым цветом с небольшим сдвигом. В результате текст выглядит выдавленным на поверхности панели. Отображение значка осуществляется с помощью функции API Windows DrawIconEx. Экранная форма приложения представлена на рис. 10.7.
26

25.

Рис. 10.7. Форма с составной строкой состояния и рисованием
Работа с пользовательскими панелями строки состояния поначалу потребует некоторых усилий. Можно программировать в течение длительного
времени и ни разу не использовать эти панели. Но если когда-нибудь они
понадобятся, то мы теперь знаем, что эта задача является вполне разрешимой.
27

26.

11. МНОГОСТРАНИЧНЫЕ ФОРМЫ
Часто возникает ситуация, когда вам надо отобразить в форме много
информации или разместить большое количество визуальных компонентов.
Тогда лучше использовать несколько страниц. Ситуация – как с записной
книжкой: на каждой странице освещается своя тема, для быстрого поиска
нужной темы есть закладки.
Для создания многостраничных приложений в Delphi имеются два
управляющих элемента:
• Компонент PageControl имеет вкладки и страницы, сходные с панелями. Поскольку каждой вкладке соответствует своя страница,
на разных страницах можно размещать разные компоненты.
• Компонент TabControl имеет только вкладки; он не содержит
страниц, на которых можно было бы хроанить информацию. Вам
придется использовать один или несколько компонентов для эмуляции смены текущей страницы.
• Существует еще один компонент – TabSheet, который представляет собой одну страницу компонента PageControl.
11.1. TTABCONTROL - НАБОР ЗАКЛАДОК
Рис.11.1. Расположение компонента TabControl в палитре компонентов
Компонент TTabControl изображен на рис. 11.2 и представляет собой контейнер с закладками. Свойство Tabs определяет названия и количество закладок. Событие OnChange возникает при выборе новой закладки и
позволяет управлять содержимым окна компонента. Для примера на рис. 1
показано использование этого компонента.
28

27.

Рис. 11.2. Вид компонента TabControl
Свойства этого компонента приведены в табл. 11.1.
Таблица 11.1
Property DisplayRect: Определяет рабочую зону компонента, предTrect;
назначенную для размещения других компонентов. Клиентская часть компонента содержит зону закладок и рабочую зону.
Property
HotTrack: Если содержит True, навание закладки автоBoolean;
матически выделяется цветом при перемещении над ней указателя мыши.
Property
MultiLine: Разрешает расположение закладок в неBoolean;
сколько рядов. Если содержит False, и закладки не умещаются в границах компонентов, в зону закладок автоматически вставляются кнопки прокрутки.
Property
ScrollOp- Разрешает (запрещает) перемещение неакposite:
тивных рядов закладок на противоположную
Boolean;
сторону компонента. Учитывается, если количество рядов больше двух.
29

28.

Продолжение табл. 11.1
TabHeight: Определяет высоту каждой закладки в пикселях. Если содержит 0, высота закладок выбирается автоматически в зависимости от
выбранного шрифта.
Property
TabIndex: Определяет индекс выбранной закладки или
Integer;
содержит –1, если ни одна закладка не выбрана. Индексация начинается с 0.
Ttab
Position
= Определяет положение зоны закладок отно(tpTop, tpBottom);
сительно рабочей зоны компонента (tpTop –
Property TabPosition: вверху, tpBottom – внизу).
TtabPosition
Property
Tabs: Определяет надписи на закладках и их колиTstrings;
чество. Чтобы добавить или удалить закладку, нужно добавить ее надпись к списку Tabs
или удалить надпись из списка.
Property
TabWidth: Определяет ширину каждой закладки в пикSmallint;
селях. Если содержит 0, ширина каждой закладки выбирается индивидуально в зависимости от длины ее надписи.
Property
Smallint;
Помимо события OnChange, возникающего после выбора новой закладки, для компонента определено также событие OnChanging, которое
возникает перед сменой закладки:
tуре TTabChangingEvent = procedure (Sender: TObject;
var AllowChange: Boolean) of object;
property OnChanging: TTabChangingEvent;
Обработчик события может запретить выбор закладки, вернув в параметре AllowChange значение False.
11.2. TPAGECONTROL - НАБОР СТРАНИЦ С ЗАКЛАДКАМИ
Компонент TPageControl, расположение которого в палитре компонентов показано на рис.11.3, внешне практически ничем не отличается от
компонента TTabControl. Пример компонента PageControl с девятью страницами приведен на рис. 11.4.
30

29.

Рис. 11.3. Расположение компонента PageControl в палитре компонентов
Рис. 11.4. Пример компонента PageControl
Но внутренняя структура этого компонента иная: TPageControl в
отличие от TTabControl может содержать несколько перекрывающих друг
друга панелей класса TTabSheet. Каж дая панель выбирается связанной с ней
закладкой и может содержать свой набор помещенных на нее компонентов.
Чтобы на этапе конструирования добавить новую панель или выбрать ранее вставленную, щелкните по компоненту правой кнопкой мыши
выберите New Page (новая панель), Next Page (следующая панель) или Previous Page (предыдущая панель). Смена панелей идет циклически после показа последней показывается первая и наоборот.
Помимо свойств HotTrack, MultiLine, ScrollOpposite, TabHeight, Position и TabWidth, которые аналогичны одноименным свойств TTabControl,
компонент имеет специфичные свойства, которые приведены в табл. 11.2.
31

30.

Таблица 11.2
Property ActivePage: Содержит ссылку на активную панель. УстаTTAbSheet
новка нового значения ActivePage размещает
соответствующую панель поверх остальных.
Для выбора новой панели следует использовать методы SelectNextPage и FindNextPage.
Property
PageCount: Содержит количество панелей (только для
Integer
чтения).
Property
Возвращает ссылку на панель по ее индексу
Pages[Index:
Inte- (только для чтения).
ger]: TTabSheet;
Методы компонента сведены в табл. 11.3.
Таблица 11.3
Ищет следующую панель: CurPage –
текущая панель; GoForward – содержит
True, если поиск идет от первой панели к
последней; CheckTabVisible – содержит
True, если из поиска исключаются панели
с признаком TabVisible=False. Возвращает ссылку на найденную панель. Если
CurPage не принадлежит компоненту,
возвращает ссылку на первую или последнюю панель в зависимости от параметра GoForward.
Procedure
SeДелает активной следующую панель.
lectNextPage
(GoFor- Если GoForward=True, активизируется
ward: Boolean);
следующая панель, в противном случае –
предыдущая.
Function
FindNextPage
(CurPage:
TtabSheet; GoForward,
CheckTabVisible: Boolean): TtabSheet;
11.3. TSCROLLBOX - ПАНЕЛЬ С ПРОКРУТКОЙ
Компонент класса TScrollBox, показанный на рис. 11.5 служит контейнером для размещения других компонентов.
32

31.

Рис. 11.5. Пример компонента ScrollBox
Его отличительная особенность - возможность прокрутки и, следовательно, экономия пространства формы при необходимости размещения на
ней большого количества управляющих элементов. Но современные программные продукты относительно редко используют такого рода компоненты, отдавая предпочтение многолистным блокнотам там с закладками. Наиболее походящей областью применения компонентов является размещение
на них относительно длинных ТЕdit, TComboBox, ТМето и т.п.
Использование компонента не отличается сложностью: надо положить его на форму и размещать затем на нем другие компоненты. Если очередной компонент выйдет за пределы рабочей области TScrollBox, по сторонам контейнера возникнут полосы прокрутки (Рис. 11.5).
Однако, если свойство AutoScroll компонента содержит False, полосы прокрутки не появятся, и компонент будет отсекать «лишние» части
своих дочерних компонентов. Еще одним важным свойством компонента
является AutoSize: если это свойство имеет значение True, размеры компонента будут автоматически изменяться так, чтобы все части дочерних компонентов были в его рабочей зоне, даже если для этого придется увеличить
размеры внешнего контейнера (формы). С помощью свойств HorzScrollBar и
VertScrollBar программист может управлять свойствами каждой из полос
прокрутки в отдельности.
33

32.

12. ОКНА ДИАЛОГА И МНОГОСТРАНИЧНЫЕ ФОРМЫ
Программы, описанные до сего момента, состояли из одной формы.
Несмотря на то, что можно создавать полноценные приложения с одной
формой и набором компонентов, обычно используют несколько форм. Как
правило, приложение имеет главное окно, несколько плавающих (перемещаемых) панелей инструментов и множество окон диалога, которые могут
быть вызваны с помощью команд меню или посредством нажатия соответствующей кнопки. Более сложные приложения могут иметь структуру MDI
– основное окно со множеством дочерних окон внутри его рабочей области.
Создание приложения MDI будет обсуждаться в главе ююююююююю
Когда вы пишете программу, большого различия между окном диалога и формой нет, за исключением рамки и других элементов пользовательского интерфейса, которые можно настраивать.
Окно диалога соответствует концепции модального (modal) окна, то
есть окна, которое, получив фокус ввода, сохраняет его до тех пор, пока не
будет закрыто. Это справедливо для окон сообщений и (обычно) для окон
диалога. Однако можно использовать и немодальные (modless) окна. Использование одной из двух функций (Show или ShowModal) для отображения вторичной формы определяет ее поведение (немодальное или модальное). Комбинируя эти принципы, можно создавать вторичные формы любого типа.
12.1. СОЗДАНИЕ ВТОРИЧНОЙ ФОРМЫ В ПРОГРАММЕ
Чтобы добавить вторичную форму в приложение, можно просто
щелкнуть на кнопке New Form панели инструментов Delphi или использовать команду меню File|New Form. Альтернативой является следующий порядок действий: выбрать команду File|New, перейти на вкладку Forms или
Dialogs и выбрать один из имеющихся там шаблонов форм или мастеров
форм.
Если в проекте имеются хотя бы две формы, вы можете использовать кнопки Select Form или Select Unit на панели инструментов, чтобы переключаться между ними во время проектирования. Можно так же определить, какая форма будет главной и какие формы должны быть автоматически созданны при запуске программы, используя вкладку Forms в окне диалога Project Options. Эта информация будет отражена в исходном коде проекта ( по умолчанию в нем создаются все формы).
Подготовив вторичную форму, вы можете установить ее свойство
Visible в True, и тогда при запуске программы будут созданы обе формы.
Как правило, вторичные формы приложения после создания оставляют невидимыми, а отображают их, вызвав метод Show (или установив свойство
Visible во время выполнения). Если вы используете функцию Show, то вто34

33.

рая форма будет отображена как немодальная, то есть вы сможете, не закрывая ее, вернуться в первую форму. Для того чтобы закрыть вторую форму, можно либо воспользоваться ее системным меню, либо вызвать какимто образом ее метод Close.
При создании модальных окон (ShowModal) сложностей не возникает.
12.2. МНОГООБРАЗИЕ ОКОН СООБЩЕНИЙ
Окна сообщений – это еще один набор стандартных окон диалога.
Приведем основные процедуры и функции Delphi, которые можно использовать для отображения простых окон диалога.
Функция MessageDlg отображает настраиваемое окно сообщения с одной или несколькими кнопками и, как правило, с одной из стандартных пиктограмм.
Функция MessageDlgPos – почти то же самое, что и
MessageDlg. Различие состоит в том, что окно сообщения отображается в определенном месте, а не в центре экрана.
Процедура ShowMessage отображает простейшее окно сообщения, с названием проложения в качестве заголовка и с
единственной кнопкой OK. Процедура ShowMessageFmt – это
вариант ShowMessage, имеющий такие же параметры, как функция Format. При этом функция Format вызывается внутри
ShowMessage для форматирования строки сообщения.
Процедура ShowMessagePos делает то же самое, только окно
сообщения появляется в определенном месте экрана.
Функция InputBox также предлагает пользователю ввести
строку. При этом задаются заголовок окна, строка запроса и результирующая строка по умолчанию.
Функция InputQuery также предлагает пользователю ввести
строку. Единственное отличие от функции InputBox состоит в
синтаксисе. Введенная строка возвращается как var- параметр, а
результатом работы InputQuery является значение типа Boolean,
которое говорит о том, какая кнопка была нажата: OK или
Cancel.
Функции MessageDlg и MessageDlgPos отображают различные
типы окон сообщения в зависимости от значения второго параметра,
имеющего тип TmsgDlgType:
Type
TmsgDlgType = (mtWarning, mtError, mtInformation, mtConfiguration, mtCustom);
35

34.

Каждый тип окон сообщения имеет собственную пиктограмму
(желтый восклтцательный знак, красный знак “стоп”, синяя буква
“i”, зеленый знак вопроса и отсутствие картинки соответственно).
Эти окна сообщения могут иметь одну или несколько кнопок, виды
которых перечислены в следующем множестве:
Type
TMsgDlgBtn = (mbYes, mbNo, mbOk, mbCancel, mbAbort,
mbRetray, mbIgnore, mbAll,
mbHelp);
TmsgDlgButtons = set of TMsgDlgBtn;
12.2.1. Демонстрация различных вариантов окна сообщени
Для демонстрации различных вариантов окна сообщения создадим
приложение, в котором есть возможность задать множество всевозможных
параметров (для этого используются всевозможные переключатели, флажки,
поля ввода, поля со счетчиками ), прежде чем нажать одну из кнопок, которые отображают окно сообщения. Форма примера показана на рис. 12.2, а
окно MessageDlg – на рис. 12.1
рис. 12.1 Окно сообщения
36

35.

Рис. 12.2. Главная форма примера
Общая структура программы такова. У формы есть два поля, в которых хранятся текущие значения параметров:
private
{ Private declarations }
MsgDlgType: TMsgDlgType;
MsgButtons: TMsgDlgButtons;
procedure TForm1.FormCreate(Sender: TObject);
begin
MsgDlgType := mtWarning;
MsgButtons := [mbOk];
end;
Когда пользователь включает какой-нибудь переключатель, сразу
принимаются соответствующие установки.
procedure TForm1.ButtonMessageDlgClick(Sender: TObject);
begin
if CheckHelp.Checked then
Include (MsgButtons, mbHelp);
37

36.

MessageDlg (Edit1.Text, MsgDlgType, MsgButtons, 0);
end;
procedure TForm1.RadioWarningClick(Sender: TObject);
begin
MsgDlgType := mtWarning;
end;
procedure TForm1.RadioErrorClick(Sender: TObject);
begin
MsgDlgType := mtError;
end;
procedure TForm1.RadioInformationClick(Sender: TObject);
begin
MsgDlgType := mtInformation;
end;
procedure TForm1.RadioConfirmationClick(Sender: TObject);
begin
MsgDlgType := mtConfirmation;
end;
procedure TForm1.RadioCustomClick(Sender: TObject);
begin
MsgDlgType := mtCustom;
end;
procedure TForm1.RadioOKClick(Sender: TObject);
begin
MsgButtons := [mbOk];
end;
procedure TForm1.RadioOKCancelClick(Sender: TObject);
begin
MsgButtons := mbOkCancel;
end;
procedure TForm1.RadioYesNoClick(Sender: TObject);
begin
MsgButtons := [mbYes, mbNo];
end;
38

37.

procedure TForm1.RadioYesNoCancelClick(Sender: TObject);
begin
MsgButtons := mbYesNoCancel;
end;
procedure TForm1.ButtonMsgDlgPosClick(Sender: TObject);
begin
if CheckHelp.Checked then
Include (MsgButtons, mbHelp);
MessageDlgPos (Edit1.Text, MsgDlgType, MsgButtons,
0, SpinX.Value, SpinY.Value);
end;
procedure TForm1.ButtonShowMessageClick(Sender: TObject);
begin
ShowMessage (Edit1.Text);
end;
procedure TForm1.ButtonShowMessagePosClick(Sender: TObject);
begin
ShowMessagePos (Edit1.Text, SpinX.Value, SpinY.Value);
end;
procedure TForm1.ButtonInputBoxClick(Sender: TObject);
begin
EditValue.Text := InputBox (EditCaption.Text,
EditPrompt.Text, EditValue.Text);
end;
procedure TForm1.ButtonInputQueryClick(Sender: TObject);
var
Text: String;
begin
Text := EditValue.Text;
if InputQuery (EditCaption.Text, EditPrompt.Text, Text) then
EditValue.Text := Text;
end;
procedure TForm1.ButtonQuitClick(Sender: TObject);
begin
Close;
39

38.

end;
end.
12.2. СТАНДАРТНЫЕ ДИАЛОГИ WINDOWS
В составе Windows входит ряд типовых диалоговых окон, таких как
окно выбора загружаемого файла, окно выбора шрифта, окно для настройки
принтера и т. п. В Delphi реализованы классы, объекты которых дают программисту удобные способы создания и использования таких окон.
Работа со стандартными диалогами осуществляется в три этапа:
1.Помещение в форму соответствующего компонента и настройка его
свойств.
2.Вызов стандартного для диалогов метода Execute, который создаёт и
показывает на экране диалоговое окно. Вызов этого метода обычно располагается внутри обработчика какого-либо события (выбора опции меню, нажатия инструментальной кнопки и т. п.). Окно
диалога является модальным окном, поэтому сразу после обращения к Execute дальнейшее выполнение программы приостанавливается до тех пор, пока пользователь не закроет окно. Execute – логическая функция, она возвращает True, если результат диалога с
пользователем был успешным.
3.Анализ результата Execute.
12.2.1. Диалоги открытия и сохранения файлов (TOpenDialog
TSaveDialog)
Эти компоненты имеют идентичные свойства и поэтому рассматриваются вместе.
Свойство FileName: String содержит маршрут поиска и выбранный файл
при успешном завершении диалога. Программа может использовать это
свойство для доступа к файлу с целью читать из него данные (TOpenDialog)
или записывать в него (TSaveDialog). Пользователь может ввести произвольное имя и, следовательно, указать несуществующий файл. Для записи
это не имеет значения, но при чтении отсутствие файла может привести к
краху программы.
Свойство Filler: String используется для фильтрации (отбора) файлов,
показываемых в диалоговом окне. Это свойство можно устанавливать с помощью специального редактора или программно. Для доступа к редактору
достаточно щелкнуть по кнопке в строке Filter окна Инспектора Объектов.
При программном вводе фильтры задаются одной длинной строкой, в которой символы “|” служат для разделения фильтров друг от друга, а также для
разделения описания фильтруемых файлов от соответствующей маски выбора. Например, оператор
40

39.

OpenDialog1.Filter := 'Текстовые файлы|*.txt|Файлы Паскаля|*.pas' ;
задает две маски - для отбора файлов с расширениями PAS и TXT.
Установить начальный каталог позволяет свойство InitialDir:
String. Например:
OpenDialogI.InitialDir:= ' с: 'program files\borland\delphi 3\sourсе' ;
С помощью свойства DefaultExt: Siring[3] формируется полное имя
файла, если при ручном вводе пользователь не указал расширение. В этом
случае к имени файла прибавляется разделительная точка и содержимое этого свойства.
Настройка диалога может варьироваться с помощью свойства
TOpenOption = (of Readonly, ofOverwrirePrompt, ofHideReadOnly, ofNoChangeDir, ofShowKelp, ofNoValidate, of AllowMuItiSelect, ofExtensionDifferen, ofPathMustExist, ofFileMustExist, ofCreatePrompt, ofShareAware, ofNoReadOnlyReturn,
ofNoTestFileCreate, ofNoNetworkButton, ofNoLongNames,
ofOldStyleDialog, ofNoDereferenceLinks);
TOpenOptions = set of TOpenOption;
property Options: TOpenOptions;
Описание значений этого свойства приведены в табл. 12.1.
Таблица 12.1
OfReadOnly
Устанавливает переключатель Только для
чтения.
OfOverwritePrompt
Требует согласие пользователя при записи в
существующий файл.
OfHideReadOnly
Прячет переключатель Только для чтения.
OfNoChangeDir
Запрещает смену каталога.
OfShowHelp
Включает в окно кнопку Help.
OfNoValidate
Запрещает автоматическую проверку правильности набираемых в имени файла символов.
OfAllowMultiSelect
Разрешает множественный выбор файлов.
OfExtensionDifferПри завершении диалога наличие этого значеent
ния в свойстве Options говорит о том, что
пользователь ввел расширение, отличающееся oт умалчиваемого.
OfPathMustExist
Разрешает указывать файлы только из существующих каталогов.
OfFileMustExist
Разрешает указывать только существующие
файлы.
41

40.

OfCreatePrompt
OfShareAware
OfNoReadOnlyReturn
OfNoTestFileCreate
OfNoNetworkButton
OfNoLongNames
OfOldStyleDialog
Окончание табл. 12.1
Tpeбует подтверждения для создания несуществующего файла.
Разрешает выбирать файлы, используемые
другими параллельно выполняемыми программами.
Запрещает выбор файлов, имеющих атрибут
Только для чтения
Запрещает прочерку доступности сетевого или
локального диска.
Запрещает вставку кнопки для создания сетевого
Запрещает использование длинных имен файлов.
Создает диалог в стиле Windows З.х
Если разрешен множественный выбор, доступ к выбранным именам
можно получить в свойстве Files: Strings
Окно диалога Open представлено на рис. 12.3.
Рис. 12.3. Окно Open диалога
.
42

41.

12.2.2.Пример использования TopenDialog
Помешаем в форму кнопку Button1 и окно Memo1 + компонент
TOpenDialog:
procedure TForm1.Button1Click(Sender: TObject);
var
s:String;
F:TextFile;
begin //настраиваем диалог на отбор текстовых файлов
OpenDialog1.Filter:='Текстовые файлы|*.txt|Файлы Паскаля|*.pas';
if OpenDialog1.Execute and FileExists(OpenDialog1.FileName) then
begin
AssignFile(F, OpenDialog1.FileName);
Reset(F);
Memo1.Lines.clear; //очищаем редактор
while not EOF(F) do //заполняем его
begin
Readln(F,S);
Memo1.Lines.Add(S)
end;
CloseFile(F)
end;
end.
Filter : String – используется для фильтрации (отбора) файлов, показываемых в диалоговом окне. Это свойство можно задавать с помощью специального редактора на этапе конструирования формы или при работе программы (например OpenDialog.Filter:= ’Текстовые файлы|*.txt|Файлы Паскаля|*.pas’ задаёт две маски отбора файлов по расширению).
InitialDir : String – начальный каталог.
DefaultExt : String[3] – расширение имени файла по умолчанию (используется, если пользователь набрал имя файла без расширения).
Существуют специализированные разновидности этих диалогов для
работы с графическими файлами – TOpenPictureDialog и TSavePictureDialog.
Они отличаются от обычных наличием стандартных фильтров для выбора
графических файлов (с расширениями BMP, ICO, WMF, EMF) и панелями
для предварительного просмотра выбранного файла.
12.2.3. Диалог выбора шрифта(TFontDialog)
Компонент TFontDialog создаёт и обслуживает стандартное окно выбора шрифта
Свойство
TFontDialogDevice = (fdScrenn, fdPrinter, fdBoth);
Property Device: TFontDialogDevice;
43

42.

Определяет тип устройства(экран, принтер или и то и другое).
12.2.4. Диалог выбора цвета (TColorDialog)
Компонент создаёт и обслуживает стандартное диалоговое окно выбора
цвета.
Свойства компонента:
Color: TColor – содержит выбранный цвет;
CustomColors:TStrings – содержит до 16 цветов, определённых пользователем. Каждая строка имеет следующий формат: ColorX=HHHHHH, где X –
буква от A до P, определяющая номер цвета, HHHHHH – шестнадцатеричное представление цвета в формате RGB.
Options: TColorDialogOptions; TColorDialogOption= (cdFullOpen, cdPreventFullOpen,
cdShowHelp,cdSolidColor,cdAnyColor);
TColorDialogOptions=set of TColorDialogOption – определяет настройку окна: cdFullOpen –
показывать с развёрнутым окном выбора цвета пользователя; cdPreventFullOption – запретить показ окна выбора цвета пользователя; cdShowHelp –
включить в окно кнопку Help; cdSolidColr - выбирать ближайший сплошной
цвет; cdAnyColor – разрешить выбор несплошных цветов.
Также существуют следующие (реже используемые) стандартные диалоги:
TPrintDialog – создаёт стандартное диалоговое окно для выбора параметров печати;
TPrinterSetupDialog – создаёт окно настройки параметров принтера;
TFindDialog – это диалоговое окно используется для поиска фрагмента
текста;
TReplaceDialog – создаёт и обслуживает окно поиска и замены текстового фрагмента.
44

43.

13. ОСНОВЫ ОРГАНИЗАЦИИ MDI
Многооконный интерфейс (от английского Multiple Document Interface MDI) – это стандарт пользовательского интерфейса для приложений Windows, который определяет способ работы одновременно с несколькими открытыми документами. Документом может быть (не обязательно) содержимое некоторого файла на диске, например текстового файла, файла электронной таблицы и т. д.
Program Manager и File Manager являются примерами программ с
пользовательским интерфейсом MDI. В Program Manager вы можете одновременно управлять множеством программных групп, каждая из которых
является документом. В программе File Manager документом является окно
каталогов.
Перечислим основные принципы построения MDI-приложений в системе Windows:
• все MDI-приложения имеют главное окно, называемое обрамляющим окном MDI или окном рамки (frame window);
• внутри обрамляющего окна располагаются дочерние окна MDI, содержащие документы. Если документ связан с файлом на диске, то его заголовок обычно содержит путь к этому файлу. С одним документом можно
работать в нескольких дочерних окнах MDI. В этом случае в заголовке окна
вместе с именем документом может отображаться порядковый номер окна
(например, minmdi.pas:1, minmdi.pas:2);
• дочерние окна не видны за границами обрамляющего окна. При передвижении обрамляющего окна дочерние окна перемещаются вместе с ним.
Минимизация и максимизация обрамляющего окна не изменяют размеров его
дочерних окон, содержащих документы. Однако если дочернее окно максимизировано, то оно всегда занимает всю область обрамляющего окна. Минимизированные дочерние окна отображаются внутри обрамляющего окна как
пиктограммы;
• в каждый момент времени только одно дочернее окно может быть
активным. Активное дочернее окно помечается так же, как и окно рамки –
цветовым выделением нерабочих областей окна. При переключении на другое приложение Windows запоминает, какое дочернее окно было активным, и
при возврате в приложение восстанавливается его активность;
• в отличие от программ с интерфейсом, ориентированным на один
документ, MDI-приложение должно иметь меню, которое принадлежит
управляющему окну. Дочерние окна MDI не могут иметь своего меню.
Управление всеми документами осуществляется из одного меню окна рамки;
• меню окна рамки должна включать подменю управления дочерними
окнами. Это подменю обычно называется Windows и содержит такие команды как Сascade (Каскад), Tile (Мозаика), Arrange icons (Скомпоновать пикто45

44.

граммы),Close all (Закрыть всё). Windows автоматически добавляет заголовок
каждого открытого документа в конец меню дочерних окон. Текущее активное окно помечается в этом списке «птичкой». Windows может отображать в
меню Window до 9 названий документов. Если одновременно открыто более
9 документов, тоWindow добавляет в конец списка открытых окон команду
More Window ….При её выборе на экране появляется окно диалога с заголовком Select Window ,с помощью которого пользователь может активизировать
любой из документов;
• Системное меню дочернего окна MDI содержит обычные команды
управления окном, но выбираются они с помощью клавиши Ctrl, а не Alt.
Например, чтобы закрыть докумет, нужно нажать клавиши Ctrl+F4.
Обычно MDI-приложения состоят минимум из двух форм — родительской и дочерней. Свойство родительской формы FormStyle установлено
равным fsMDIForm. Для дочерней формы установите стиль fsMDIChild.
Родительская форма служит контейнером, содержащим дочерние
формы, которые заключены в клиентскую область и могут перемещаться,
изменять размеры, минимизироваться или максимизироваться. В вашем
приложении могут быть дочерние формы разных типов, например одна —
для обработки изображений, а другая — для работы с текстом.
13.1. СОЗДАНИЕ ФОРМ
В MDI-приложении, как правило, требуется выводить несколько экземпляров классов формы. Поскольку каждая форма представляет собой
объект, она должна быть создана перед использованием и освобождена, когда в ней больше не нуждаются. Delphi может делать это автоматически, а
может предоставить эту работу вам.
13.1.1. Автоматическое создание форм
По умолчанию при запуске приложения Delphi автоматически создает
по одному экземпляру каждого класса форм в проекте и освобождает их при
завершении программы. Автоматическое создание обрабатывается генерируемым Delphi кодом в трех местах.
Первое — раздел интерфейса в файле модуля формы.
type
TForm1 = class(TForm)
private
{Закрытые объявления.}
public
{Открытые объявления.}
end;
В данном фрагменте кода объявляется класс TForm1.
Вторым является место, в котором описывается переменная класса.
var Form1: TForm1;
Здесь описана переменная Form1, указывающая на экземпляр класса
46

45.

TForm1 и доступная из любого модуля. Обычно она используется во время
работы программы для управления формой.
Третье место находится в исходном тексте проекта, доступ к которому можно получить с помощью меню View/ Project Source. Этот код выглядит как:
Application.CreateForm(TForm1, Form1);
Процесс удаления форм обрабатывается с помощью концепции владельцев объектов: когда объект уничтожается, автоматически уничтожаются
все объекты, которыми он владеет. Созданная описанным образом форма
принадлежит объекту Application и уничтожается при закрытии приложения.
13.1.2. Динамическое создание форм
Хотя автоматическое создание форм полезно при разработке SDIприложений, при создании MDI-приложении оно, как правило, неприемлемо.
Для создания нового экземпляра формы используйте конструктор
Create класса формы. Приведенный ниже код создает новый экземпляр
TForm1 во время работы программы и устанавливает его свойство Caption
равным 'New Form'.
Form1:= TForm1.Create(Application);
Form1.Caption:= 'New Form';
Конструктор Create получает от вас в качестве параметра потомка
TComponent, который и будет владельцем вашей формы. Обычно в качестве
владельца выступает Application, чтобы все формы были автоматически закрыты по окончании работы приложения. Вы можете также передать параметр Nil, создав форму без владельца (или владеющую собой — как вам
больше нравится), но тогда закрывать и уничтожать ее придется вам. В случае возникновения необрабатываемой ошибки такая форма останется в памяти, что не говорит о высоком профессионализме программиста...
В приведенном ниже коде Form1 указывает только на последнюю
созданную форму. Если вам это не нравится, воспользуйтесь приведенным
ниже кодом — возможно, он более точно отвечает вашим запросам:
with TFormI.Create(Application) do
Caption:= 'New Form';
Совет: При разработке MDI-приложения метод Show не нужен, так
как Delphi автоматически показывает все вновь созданные дочерние MDIформы. В случае SDI-приложения вы обязаны использовать метод Show.
Даже при динамическом создании форм Delphi попытается навязать
вам свои услуги по созданию экземпляра каждой формы. Чтобы отказаться
от них, воспользуйтесь диалоговым окном Project Options, изображенным на
47

46.

рис. 13.1, и удалите классы форм из списка Auto-create forms.
Рис. 13.1. Диалоговое окно Project Options позволяет установить опции для текущего проекта
Если вы захотите получить доступ к отдельному дочернему экземпляру класса, используйте свойство MDIChildren, описываемое в следующем
разделе.
13.2. MDI-СВОЙСТВА TFORM
Объект TForm имеет несколько свойств, специфичных для MDIприложений.
13.2.1. ActiveMDIChild
Это свойство возвращает дочерний объект TForm, имеющий в текущее время фокус ввода. Оно полезно, когда родительская форма содержит
панель инструментов или меню, команды которых распространяются на открытую дочернюю форму.
Например, представим, что проект использует дочернюю форму,
содержащую элемент TMemo, названный memDailyNotes. Имя класса этой
48

47.

дочерней формы— TfrmMDIChild. Родительская форма содержит кнопку
Clear в панели инструментов, которая удаляет содержимое memDailyNotes в
активной дочерней форме. Вот как это реализуется.
procedure TfrmMDIParent.spbtnClearClick(Sender: TObject);
begin
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).memDailyNotes.Clear;
end;
В первой строке проверяется, равен ли ActiveMDIChild значению Nil,
так как в этом случае обращение к объекту вызовет исключительную ситуацию.
Совет: ActiveMDIChild равен Nil, если нет открытых дочерних форм
или свойство FormStyle не равно fsMDIForm.
Поскольку ActiveMDIChild возвращает объект TForm, компилятор не
имеет доступа к memDailyNotes — объекту TfrmMDIChild. Вторая строка
проверят соответствие типов, т.е. действительно ли ActiveMDIChild указывает на объект TfrmMDIChild.
Третья строка выполняет преобразование типа и вызывает метод Clear
компонента memDailyNotes.
13.2.2. MDIChildren и MDIChildCount
Свойство MDIChildren является массивом объектов TForm, предоставляющих доступ к созданным дочерним формам. MDIChildCount возвращает количество элементов в массиве MDIChildren.
Обычно это свойство используется при выполнении какого-либо действия над всеми открытыми дочерними формами. Вот код сворачивания
всех дочерних форм командой Minimize All.
procedure TFormI.mnuMinimizeAllClick(Sender: TObject);
var
iCount: Integers;
begin
for iCount:=MDIChildCount-1 downto 0 do
MDIChildren[iCount].WindowState:= wsMinimized;
end;
Если вы будете сворачивать окна в порядке возрастания элементов
массива, цикл будет работать некорректно, так как после сворачивания каждого окна массив MDIChildren обновляется и пересортировывается, и вы
можете пропустить некоторые элементы.
49

48.

13.2.3. TileMode
Это — свойство перечислимого типа, определяющее, как родительская форма размещает дочерние при вызове метода Tile. Используются значения tbHorizontal (по умолчанию) и tbVertical для размещения форм по горизонтали и вертикали.
13.2.4. WindowMenu
Профессиональные MDI-приложения позволяют активизировать необходимое дочернее окно, выбрав его из списка в меню. Свойство
WindowMenu определяет объект TMenuItem, который Delphi будет использовать для вывода списка доступных дочерних форм.
Для вывода списка TMenuItem должно быть меню верхнего уровня.
Это меню имеет свойство Caption, равное swindow.
13.3. MDI-СОБЫТИЯ TFORM
В MDI-приложении событие OnActivate запускается только при переключении между дочерними формами. Если фокус ввода передается из не
MDI-формы в MDI-форму, генерируется событие OnActivate родительской
формы, хотя ее свойство Active никогда и не устанавливается равным True.
Эта странность на самом деле строго логична: ведь, если бы OnActivate генерировался только для дочерних форм, не было бы никакой возможности
узнать о переходе фокуса ввода от другого приложения.
13.4. MDI-МЕТОДЫ TFORM
Специфичные для MDI-форм методы перечислены ниже.
Arrangelcons выстраивает пиктограммы минимизированных дочерних
форм в нижней части родительской формы.
Cascade располагает дочерние формы каскадом, так что видны все их
заголовки.
Next и Previous переходит от одной дочерней формы к другой, как
будто вы нажали <Ctrl+Tab или <Ctrl+Shift+Tab.
Tile выстраивает дочерние формы так, что они не перекрываются.
13.5. ПРИМЕР MDI-ПРИЛОЖЕНИЯ
Для демонстрации MDI создадим простую программу просмотра изображения.
13.5.1. Создание интерфейса
Интерфейс MDI-приложения очень похож на интерфейс SDIприложения, но каждое изображение выводится в отдельной, а не в главной
форме. Выполните следующие действия для создания родительской формы.
1. Выберите команду File/New Application, и появится пустое приложение.
2. Установите следующие свойства.
50

49.

Свойство
Значение
Caption:
Image
Viewer
FormStyle:
fsMDIForm
Name:
frmMDIParent
ShowHint: True
3. Поместите компонент TPanel в форму. Установите следующие
его свойства.
Свойство
Значение
Align
alTop
Caption
4. Поместите три компонента TSpeedButton в TPanel и назовите их
spbtnLoad, spbtnStretch и spbtnCenter. Установите следующие их свойства.
Свойство
Значение
spbtnLoad.Hint
Load
spbtnLoad.Left
8
spbtnLoad.Top
8
spbtnStretch.AllowAlIUp
True
spbtnStretch.Grouplndex
1
spbtnStretch.Hint
Stretch
spbtnStretch.Left
48
spbtnStretch.Top
8
spbtnCenter.AllowAlIUp
True
spbtnCenter.Grouplndex
2
spbtnCenter.HintCenter
spbtnCenter.Left80
spbtnCenter.Top8
Свойства Glyph установите :
Свойство
Значение
spbtnLoad.Glyph
FLDROPEN.BMP
spbtnStretch.Glyph
FONTSIZE.BMP
spbtnCenter.Glyph
PICTURE.BMP
5. Добавьте в форму компонент TOpenDialog и установите следующие его свойства.
Свойство
Значение
Filter
Bitmaps
(*.bmp)]*.bmp
Name
opndlgLoad
Options
[ofPathMustExist,ofFileMustExist]
Теперь создадим дочернюю форму.
1. Выберите из меню File/New Form, и появится пустая форма.
2. Установите следующие ее свойства.
51

50.

Свойство
Значение
FormStyle
fsMDIChild
NamefrmMDIChild
Position poDefaultPosOnly
3. Поместите компонент TImage во вновь созданную форму и установите его следующие свойства.
Свойство
Значение
AlignalClient
Name imgMain
Удалите дочернюю форму из списка автоматически создаваемых
форм следующим образом.
1. Выберите команду Project/ Options, и появится диалоговое окно
Project Options, показанное на рис. 1.
2. Выберите frmMDIChild в списке Auto-create forms.
3. Щелкните на кнопке. Форма frmMDIChild при этом будет перенесена в список Available forms.
4. Щелкните на кнопке ОК.
Теперь самое время сохранить проект, выбрав команду File/Save
Project As. Сохраните Unit1 как MDIParent, а проект — как EgMDIApp.
13.5.2. Написание кода
Создав интерфейс, перейдем к написанию исходного текста приложения, который будет очень похож на код для SDI-приложения.
Сначала загрузим изображение. Введите следующий код в обработчик события OnClick компонента spbtnLoad.
procedure TfrmMDIParent.spbtnLoadClick(Sender: TObject);
begin
if opndlgLoad.Execute then
with TfrmMDIChild.Create(Application) do
begin
Caption:= opndlgLoad.FileName;
imgMain.Picture.LoadFromFile(opndlgLoad.FileName);
ClientWidth:= imgMain.Picture.Width;
ClientHeight:= imgMain.Picture.Height;
end;
end;
После запуска диалогового окна создается новый экземпляр дочерней
формы и загружается файл изображения. После загрузки размеры дочерней
формы изменяются так, чтобы можно было видеть все изображение.
Еще пара штрихов— и приложение заработает, как и предусматривалось. Поскольку модуль ссылается на тип TfrmMDIChild, находящийся в
модуле MDIChild, после строки implementation следует добавить еще одну
52

51.

строку:
uses MDIChild;
Теперь можно приступить к компиляции и запуску приложения. Однако заметьте, что, когда вы щелкаете на кнопке Close, дочерняя форма не
закрывается, а сворачивается в пиктограмму. Чтобы заставить ее закрыться,
следует добавить в код обработчика OnClose класса TfrmMDIChild маленькую деталь— изменить свойство Action:
Action:= caFree;
Компоненты TSpeedButton Stretch и Center выполняют функции растягивания изображения и выравнивания по центру. Для этого их обработчики события OnClick следует прописать следующим образом:
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild 15 TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).imgMain.Stretch:=
spbthStretch.Down;
и
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).imgMain.Center:= spbthCenter.Down;
Остается последняя проблема — состояния кнопок Stretch и Center
одинаковы для всех дочерних форм Для решения этой задачи добавьте в обработчик события OnActivate класса TfrmMDIChild строки.
frmMDIParent.spbtnStretch.Down:=
imgMain.Stretch;
frmMDIParent.spbtnCenter.Down:= imgMain.Center;
И, наконец, самый последний из последних штрихов— в модуле
MDIChild добавьте после строки implementation строку.
uses MDIParent;
Компилируйте, запускайте и смотрите. MDI-приложение создано!
ПРЕДОСТЕРЕЖЕНИЕ: В этом примере присвоение нового значения свойству Down класса TSpeedButton вызывало событие Оn-click. Будьте
осторожны при написании кода обработчика события, который генерирует
новое событие путем присвоения значения свойству, ведь при этом можно
создать бесконечную рекурсию.
53

52.

14.РАБОТА С ФАЙЛАМИ В DELPHI
Под файлом понимается именованная область внешней памяти компьютера.
Любой файл имеет три характерные особенности. Во-первых, у него
есть имя, что дает возможность программе работать одновременно с несколькими файлами. Во-вторых, он содержит компоненты одного типа. Типом компонентов может быть любой тип Object Pascal, кроме файлов.
Иными словами, нельзя создать “файл файлов”. В-третьих, длина вновь
создаваемого файла никак не оговаривается при его объявлении и ограничивается только емкостью устройств внешней памяти.
Файловый тип или переменную файлового типа можно задать одним из
трех способов:
<имя> = File of <тип>;
<имя> = TextFile;
<имя> = File;
Здесь <имя> - имя файлового типа; File, of - зарезервированные слова
(файл, из); TextFile - имя стандартного типа текстовых файлов; <тип> - любой тип Object Pascal, кроме файлов.
В зависимости от способа объявления можно выделить три файлов:
• типизированные файлы (задаются предложением File of...);
• текстовые файлы (определяются типом TextFile),
• нетипизированные файлы (определяются типом File).
14.1. ДОСТУП К ФАЙЛАМ
Файлы становятся доступны программе только после выполнения особой процедуры открытия файла.
Файловая переменная связывается с именем файла в результате обращения к стандартной процедуре AssignFile:
AssignFile (<ф.п.>, <имя файла>);
Здесь <ф.п.> - файловая переменная;<имя файла> - текстовое выражение, содержащее имя файла.
Инициировать файл означает указать для этого файла направление передачи данных. В Object Pascal можно открыть файл для чтения, для записи
информации, а также для чтения и записи одновременно.
Для чтения файл инициируется с помощью стандартной процедуры Reset:
54

53.

Reset (<ф.п.>) ;
Здесь <ф.п.> - файловая переменная, связанная ранее процедурой
AsignFile с уже существующим файлом.
В Object Pascal разрешается обращаться к типизированным файлам,
открытым процедурой Reset (т.е. для чтения информации), с помощью процедуры Write (т.е. для записи информации). Такая возможность позволяет
обновлять ранее созданные типизированные файлы и при необходимости
расширять их. Для текстовых файлов, открытых процедурой Reset, нельзя
использовать процедуру Write или WriteLn. Стандартная процедура
Rewrite (<ф.п.>);
инициирует запись информации в файл, связанный с файловой переменной <ф.п.>. Процедурой Rewrite нельзя инициировать запись информации в ранее существовавший дисковый файл: при выполнении этой
процедуры старый файл (если он был) уничтожается и никаких, сообщений
об этом в программу не передается.
Стандартная процедура
Append (<ф.п.>)
инициирует запись в ранее существовавший текстовый файл для его
расширения. Процедура Append применима только к текстовым файлам.
14.2. ПРОЦЕДУРЫ И ФУНКЦИИ ДЛЯ РАБОТЫ С ФАЙЛАМИ
Табл.14.1. содержит основные процедуры и функции для работы с файлами.
55

54.

Таблица 14.1
Подпрограммы для работы с файлами
Function AssignFile
Связывает файловую переменную F с именем
(var F; FileName; файла File-Name.
String);
Function
ChDir
Изменяет текущий каталог: Path - строковое
(Path: String) ;
выражение, содержащее путь к устанавливаемому
по умолчанию каталогу.
Function CloseЗакрывает файл, однако связь файловой переFile (var F);
менной Fc именем файла, установленная ранее
процепурой AssignFile, сохраняется. При создании
нового или расширении старого файла процедура
обеспечивает сохранение в файле всех новых записей и регистрацию файла в каталоге. Функции процедуры CloseFile выполняются автоматически по
отношению ко всем открытым файлам при нормальном завершении программы. Поскольку связь
файла с файловой переменной сохраняется, файл
можно повторно открыть без дополнительного использования процедуры AssignFile
Function DiskВозвращает объем в байтах свободного проFree (D: Byte): странства на указанном диске: D - номер диска (0 –
LongInt;
устройство по умолчанию, 1 – диск /1,2- диск В и
т.д.). Функция возвращает значение -1, если указан
номер несуществующего диска.
Function. DiskВозвращает объем в байтах полного пространSpace (D: Byte): ства на указанном диске: D - номер диска (0 – устLongint;
ройство по умолчанию, 1 – диск А , 2 - диск В и
т.д.)
. Функция возвращает значение –1, если укачан
номер несуществующего диска.
Function EOF
Тестирует конец файла и возвращает True, если
(var F): Boolean;
файловый указатель стоит в конце файла. При записи это означает, что очередной компонент будет
добавлен в конец файла, при чтении • что файл исчерпан.
Function Erase
Уничтожает файл F. Перед выполнением про(var F);
цедуры необходимо закрыть файл.
56

55.

Продолжение табл. 14.1
Function FileExПроверяет существование файла с именем (и,
ists (const File- возможно, маршрутом доступа) FileName и возName: string): Boo- вращает True, если файл существует.
lean;
Function FindОсвобождает память, выделенную для поиска
Close (var F: Tsear- файлов функциями FindFirst/FindNext.
chRec) ;
Function FindFirst (const Path:
String; Attr: Integer;
var F: TsearchRec):
Integer;
Возвращает атрибуты первого из файлов, зарегистрированных в указанном каталоге: Path - маршрут поиска и маска выбора файлов; Attr – атрибуты выбираемых файлов: F – переменная типа
TsearchRec, в которой будет возвращено имя первого выбранного файла.
Function FindNext
Возвращает в переменой F имя следующего
(var
файла в каталоге. Переменная F должна предвариF: TsearchRec): In- тельно инициироваться обращением к функции
teger;
FindFirst.
Function Flush
Очищает внутренний буфер файла и, таким об(var F) ;
разом, гарантирует сохранность всех последних
изменений файла на диске.
Function GetDir (D:
Возвращает имя текущего каталога (каталога по
Byte; var S; String); умолчанию): D - номер устройства (0 – устройство
по умолчанию, I - диск А, 2 - диск В и т.д.); S - переменная типа String, в которой возвращается путь
к текущему каталогу на указанном диске.
Function IOReВозвращает условный признак последней опеsult: Integer;
рации ввода-вывода.
Function MkDir
Создает новый каталог на указанном диске: Dir
(Dir: String);
маршрУ'1" поиска каталога. Последним именем в
маршруте, т.е. именем вновь создаваемого каталога
не может быть имя уже существующего каталога.
Function
ReПереименовывает файл F; NewName – строкоname (var F; New- вое выражение, содержащее новое имя файла. ПеName; String);
ред выполнением процедуры необходимо закрыть
файл.
Открывает
существующий файл. RecSize имеет
Function Reset
смысл
только
для нетипизированных файлов и ука(var F: File [; Recзывает размер блока данных.
Size: Word]);
57

56.

Function
Rewrite(var F: File [;
Recsize: Word]);
Function
RmDir(Dir: String);
Окончание табл. 14.1
Создает новый файл. RecSize имеет смысл только для нетипизированных файлов и указывает размер блока данных.
Удаляет каталог Dir. Удаляемый каталог должен
быть пустым, т.е. не содержать файлов или имен
каталогов нижнего уровня.
14.3. ТЕКСТОВЫЕ ФАЙЛЫ
Текстовые файлы связываются с файловыми переменными, принадлежащими стандартному типу TextFile. Текстовые файлы предназначены
для хранения текстовой информации.
Текстовый файл трактуется в Object Pascal как совокупность строк переменной длины. Доступ к каждой строке возможен лишь последовательно,
начиная с первой. При создании текстового файла в конце каждой строки
ставится специальный признак EOLN (End Of LiNe - конец строки), а в конце
всего файла - признак EOF {End Of File - конец файла).
Для доступа к записям применяются процедуры Read, ReadLn, Write,
WriteLn. Они отличаются возможностью обращения к ним с переменным
числом фактических параметров, в качестве которых могут использоваться
символы, строки и числа. Первым параметром в любой из перечисленных
процедур должна стоять файловая переменная. Обращение осуществляется
к дисковому файлу, связанному с переменной F процедурой AssignFile
Процедуры для работы с текстовыми файлами приведены в табл. 14.2.
Таблица 14.2
Function Eoln (var
Тестирует маркер конца строки и возвращаF: TextFile): Boolean; ет True, если конец строки достигнут.
Function Read (var
Читает из текстового файла последовательF: TextFile; VI [, V2, ность символьных представлений переменных
… , Vn]);
V, типа Char, String, а также любого целого или
вещественного типа, игнорируя признаки
EOLN.
Function
Читает из текстового файла последовательReadLn
(var
F: ность символьных представлений переменных
TextFile; [V1 [,V2, … V, типа Char, String, а также любого целого или
, Vn]]);
вещественного типа с учетом границ строк.
58

57.

Продолжение табл.14.2
Function F: Text):
Пропускает все пробелы, знаки табуляции и
SeekEof (var F: маркеры конца строки EOLN до маркера конца
файла EOF или до первого значащего символа и
text): Boolean;
возвращает True, если маркер EOF обнаружен.
Function 5eekEoln
Пропускает все пробелы и знаки табуляции
(var F: Text): Boo- до маркера конца строки EOLN или до первого
lean;
значащего символа и возвращает True, если
маркер обнаружен.
Function
Write
Записывает символьные представления пе(var F: Text; P1[, P2, ременных V, в текстовый файл;
... , Pn] );
Function WriteLn
Записывает символьные представления пе(var F: Text; [P1 [, P2, ременных Vi и признак конца строки EOLN в
… , Pn ]] );
текстовый файл.
14.4. ТИПИЗИРОВАННЫЕ ФАЙЛЫ
Длина любого компонента типизированного файла строго постоянна,
что дает возможность организовать прямой доступ к каждому из них (т.е.
доступ к компоненту по его порядковому номеру),
Перед первым обращением к процедурам ввода-вывода указатель файла стоит в его начале и указывает на первый компонент с номером 0. После
каждого чтения или записи указатель сдвигается к следующему компоненту
файла. Переменные в списках ввода-вывода должны иметь тот же тип, что и
компоненты файла. Если этих переменных в списке несколько, указатель
будет смещаться после каждой операции обмена данными между переменными и дисковым файлом.
Основные процедуры для работы с типизированными файлами приведены в табл.14.3.
59

58.

Таблица 14.3
Function
Read Читает данные из типизированного файла F: V, - пе(var Р, V1, … , Vn); ременные такого же типа, что и компоненты файла.
Function
Write Записывает данные в типизированный файл F: V, (var F, VI, … , Vn);
переменные такого же типа, что и компоненты файла.
Function
Seek Смещает указатель файла F к требуемому компонен(var F; M: LongInt);
ту: N- номер компонента файла (первый компонент
файла имеет номер 0).
Function FileSize Возвращает количество компонентов файла. Что(var F): LongInt;
бы переместить указатель в конец типизированного файла, можно написать:
Seek (FileVar, FileSize(FileVar)) ;
Function FilePos Возвращает текущую позицию в файле, т.е. номер
(var F): LongInt;
компонента,
Который будет обрабатываться следующей операцией ввода-вывода.
14.5. НЕТИПИЗИРОВАННЫЕ ФАЙЛЫ
Нетипизированные файлы объявляются как файловые переменные типа
File и отличаются тем, что для них не указан тип компонентов. Отсутствие
типа делает" эти файлы, с одной стороны, совместимыми с любыми другими
файлами, а с другой - позволяет организовать высокоскоростной обмен данными между диском и памятью.
При инициации нетипизированного файла процедурами Reset или Rewrite можно указать длину записи нетипизированного файла в байтах. Например, так:
Var
F: File;
begin

AssignFile (F,’my-file.dat');
Reset (f, 512);

60

59.

end;
Object Pascal не накладывает каких-либо ограничений на длину записи
нетипизированного файла, за исключением требования положительности и
ограничения максимальной длины 2 Гбайт.
При работе с нетипизировашными файлами могут применяться все
процедуры и функции, доступные типизированным файлам, за исключением
Read и Write, которые заменяются соответственно высокоскоростными процедурами BlockRead и BlockWrite:
Function BlockRead (var F: File; var Buf; Count: Integer [; var
AmtTransferred: Integer]);
Function BlockWrite(var F: F-ile; var Buf; Count: Integer [; var
AmtTransferred: Integer]);
Здесь Buf - буфер: имя переменной, которая будет участвовать в обмене
данными с дисками; Count - количество записей, которые
должны быть прочитаны или записаны за одно обращение к диску;
AmtTransferred - необязательный параметр, содержащий при выходе из процедуры количество фактически обработанных записей.
14.6. СРЕДСТВА WINDOWS ДЛЯ РАБОТЫ С ФАЙЛАМИ
Операционная система Windows имеет собственные средства работы с
файлами, которые становятся доступны программе Delphi после ссылки на
модуль Windows. Поскольку файловые средства Object Pascal реализуют подавляющее большинство программных запросов, в табл.14.4 приводится
лишь краткая информация о назначении соответствующих API-функций. За
подробной информацией обращайтесь к справочной службе в файлах
WIN32.HLP или WIN32S.HLP. Для версии 3.0 эти файлы расположены в подкаталоге HELP каталога размещения Delphi, для версий 2.х - в подкаталоге
BIN .
AreFileApisANSI
Таблица 14.4
Определяет, будут ли файловые операции использовать кодовую страницу ANSI.
СopyFile
Копирует содержимое одного файла в другой.
СreateDirectory
Создает новый каталог на диске.
61

60.

СreateDirectoryEx
Продолжение табл. 14.4
Создает новый каталог на диске.
СreateFile
Создает новый или открывает существующий
файл.
CreateIoCompietionPort
Связывает асинхронный ввод/вывод с файлом,
что дает возможность получить извещение о завершении асинхронной операции.
DefineDosDevice
Определяет, переопределяет или уничтожает определение логического устройства MS-DOS.
DeleteFile
Уничтожает файл.
FileIOCompleСвязывает асинхронный ввод/выводе подпроtionRoutihe
граммой для слежения за окончанием асинхронных
операций.
FindClose
Освобождает память, выделенную функциям
FindFirstFile – FindNextFile.
FindCloseChangeNotification
Освобождает память, выделенную функциям
Find-FirstChangeNolification – FindNextChangeNotification.
FindFirstChangeNotification
Требует от Windows известить программу об изменении состояния каталога.
FindFirstFile
FindHextChangeNotification
Ищет первый файл из группы файлов.
Требует от Windows известить программу об очередном изменении состояния каталога.
62

61.

Продолжение табл. 14.4
FindNextFile
FlushFileBuffers
GetBinaryType
GetCurrentDirectory
Ищет следующий файл.
Очищает файловый буфер.
Определяет, является ли файл исполняемым и,
если является, возвращает его тип.
Возвращает умалчиваемый каталог.
Get Disk Free
Возвращает свободное дисковое пространство в
Space
байтах.
GetDriveType
Возвращает тип диска (сменный, удаленный и
т.п.).
GetFileAttributes
Возвращает атрибуты файла.
GetFileInformationByHandle
Возвращает системную информацию о файле.
GetFileSize
Возвращает размер файла в байтах.
GetFileType
Возвращает тип файла.
GetFullPathName
По короткому имени файла в формате MS-DOS
возвращает его полное имя в формате Windows.
GetLogicalDrives
Возвращает битовую 32-разрядную маску, определяющую текущий диск.
63

62.

GetLogicalDriveStrings
Продолжение табл. 14.4
Возвращает список всех дисков, зарегистрированных в Windows.
GetQueuedCompletion-Status
Требует от Windows выполнения асинхронного
ввода/вывода и приостанавливает работу программы до завершения операций.
GetShortPathName
Возвращает короткое имя файла в формате MSDOS.
GetTempFileName
Возвращает уникальное имя файла для временного хранения данных.
GetTempPath
Возвращает маршрут поиска каталога, предназначенного для хранения временно используемых
файлов.
Get
Volume
Возвращает информацию о файловой подсистеме
Information
в целом и о указанном каталоге.
LockFile
Защищает файл от доступа к нему из других программ.
LockFileEx
Устанавливает способ использования файла другими программами.
Move FILe
Переименовывает файл или каталог (с подкаталогами).
MoveFileEx
Переименовывает файл.
OpenFile
Открывает существующий файл.
Query
Device
DOS
Получает информацию об именах дисков (устройств). Используемых в MS-DOS.
64

63.

Продолжение табл. 14.4
ReadFile
Читает данные из файла.
ReadFileEx
Реализует асинхронное чтение данных из файла.
Remove Directorу
SearchPath
SetCurrentDirectory
SetEndOrFile
SetFileApisToANSI
SetFileApisToOEM
SetFileAttnbutes
SetFilePointer
SetHandleCount
Удаляет пустой каталог.
Ищет файл в заданном каталоге (каталогах).
Устанавливает умалчиваемый каталог.
Перемещает файловый указатель в конец файла.
Предписывает Windows использовать кодовую
страницу ANSI при файловых операциях.
Предписывает Windows использовать кодовую
страницу MS-DOS при файловых операциях.
Устанавливает атрибуты файла.
Перемещает файловый указатель на нужную позицию.
Устанавливает количество файлов, одновременно используемых программой.
SetVolumeLa-
Устанавливает новую метку тома (носителя информации).
UnlockFile
Снимает с файла защиту, установленную функцией LockFile.
bel
65

64.

UnlochFileEx
Окончание табл. 14.4
Снимает с файла защиту, установленную
функцией LockFileEx.
WriteFile
Записывает данные в файл.
WriteFileEx
Реализует асинхронную запись в файл.
14.7. РАБОТА С ФАЙЛОВОЙ СИСТЕМОЙ.
Зачастую возможностей стандартных, диалогов (компоненты TOpenDialog TSaveDialog) недостаточно для реализации замыслов программиста.
Во многих современных коммерческих приложениях перед открытием файла есть возможность получить его характеристики и предварительно просмотреть содержимое. Чтобы дать разработчикам доступ к таким функциям,
в библиотеку, VCL были включены по отдельности и все составные части
стандартного диалога: списки имен дисков, каталогов, файлов и фильтров
расширений. Если установить между ними взаимные ссылки, то они будут
работать вместе, как TOpenDialog, безо всякого дополнительного программирования. Вместе с тем можно описать и специфическую реакцию на изменения этих списков.
Кроме того, в эту группу компонентов включен TDirectory Outline —
пример настройки компонента TOutline на конкретное приложение. Он отображает файловую структуру в виде дерева и также может работать в связке
с остальными компонентами этого раздела.
14.7.1. TDriveComboBox
Иерархия компонента:
TObject→TPersistent→TComponent→ TControl→TWinControl→TCustomComboBox→
→TDriveComboBox
Компонент TDriveComboBox представляет собой список выбора с именами доступных дисков. Совместно с компонентами TDirectoryLislBox,
TFillerComboBox и TFileListBox может использоваться для создания диалоговых окон доступа к файлам. В Windows 95/NT все функции компонента
реализуются стандартным диалоговым окном TOpenDialog.
Свойства компонента приведены в табл. 14.5.
66

65.

Таблица 14.5
Property
DirList: Содержит ссылку на объект TdirectoryLislBox, в коTdirectoryListBox;
тором отображается структура файлов на диске.
Property
Char;
Drive: Содержит имя текущего диска.
TtextCase = (tcLow- Определяет отображение буквы диска:
erCase,
tcUpper- TcLowerCase - отображать строчной буквой;
Case) ;
TcUpperCase - отображать заглавной буквой.
Property TextCase:
TtextCase;
Для компонента определено событие
Property OnChange: TNotifyEvent;
возникающее при любом изменении выбора в окне компонента. Изменение текущего диска, как правило, должно повлечь за собой изменения в соответствующих списках каталогов и файлов. Для этого в обработчике события
Property OnChange: TNotifyEvent;
нужно предусмотреть соответствующий код, например:
procedure TFormI.DriveComboBoxIChange(Sender: TObject) ;
begin
DirectoryListBoxl.Drive:= DriveComboBoxl.Drive;
end;
Событие:
Property OnDropDown: TNotifyEvent;
связанно с раскрытием списка.
14.7.2. TDirectoryListBox
Иерархия компонента:
TObject→TPerBistent→TCoinponenfc→TConfcrol→TWinControl→
→TCustoinListBox→TDirectoryListBox
Компонент TDirectory List Box представляет собой панель с именами
каталогов. Совместно с компонентами TdriveComboBox, TFillerComboBox и
TFifeLislBox может использоваться для создания диалоговых окон доступа к
файлам. В Windows 95/NT все функции компонента реализуются стандартным диалоговым окном ТОреп Dialog.
67

66.

Свойства компонента объединены в табл. 14.6.
Таблица 14.6
Property
Case- Содержит True. если файловая система чувствительна
Sensitive: Boolean;
к высоте букв.
Property
tory: string;
Direc- Содержит имя каталога.
Property
bel; TLabel;
DirLa- Указывает связанный с компонентом объект-метку, в
котором отображается полный путь к текущему каталогу.
Property
Char;
Drive: Содержит имя диска.
Property FileList: Указывает связанный с компонентом объект
TfileListBox;
TFileLlslBox, в котором отображается содержимое каталога.
Property
Pre- Содержит True, если файловая система не чувствиserveCase: Boolean; тельна к высоте букв.
Методы компонента представлены в табл. 14.7.
Таблица 14.7
Function
DisplayПреобразует буквы строки S к строчCase(conat S: String): String; ным с учетом языкового драйвера, если ни
свойство CaseSensilive. ни свойство PreserveCase не содержит True.
Function FileCompareСравнивает строки А и В с учетом
Text (const А, В: String): In- свойства CaseSensiIive.
teger;
68

67.

Окончаниен табл. 14.7
Function
GetItemPath
Возвращает путь к дочернему каталогу
(Index : Integer): string;
по его индексу.
Procedure OpenCurrent;
Открывает текущий каталог.
Procedure Update;
Обновляет текущий каталог.
Для компонента определено событие
property OnChange; TNotifyEvent; .
возникающее при любом изменении выбора в окне компонента.
14.7.3. TFileListBox
Иерархия компонента:
TObject→TPersist:ent→TComponent→TControl→TWinControl→
TCustoinListBox→ TfileLisfBox
Компонент TFileListBox представляет собой панель с именами файлов.
Совместно с компонентами TDriveComboBox, TFillerComboBox и TDireclory List Box может использоваться для создания диалоговых окон доступа
к файлам. В Windows 95/NT все функции компонента реализуются стандартным диалоговым окном TOpenDiahg.
Свойства компонента приведены в табл 14.8.
Таблица 14.8
Property Directory:
string;
Property Drive: Char;
Определяет каталог размещения файлов.
Определяет диск размещения файлов.
Property FileEdit: Tedit;
Property
string;
Объект-редактор для ввода имени файла
вручную,
FileName:
Введенное или выбранное имя файла.
69

68.

TfileAttr
=
(ftReadOnly, ftHidden,
ftSystem,
ftVolumeID,
ftDirectory,
ftArchive
ftNormal);
TflleType = set of
TfileAttr;
Property
FileType:
TfileType;
Окончание табл. 14.8
Определяет типы элементов, показываемых
в окне компонента: ftReadOnly - файлы только
для чтения, ftHidden - скрытые файлы, ftSystem
–системные файлы; ftVolumelD - метки носителей: ftDirectory – каталоги; ftArchive - архивные файлы; ftNormal – обычные файлы.
Property Mask: string;
Определяет маску выбора файлов.
Property
Boolean;
MultiSelect:
Разрешает/запрещает множественный выбор файлов.
Property
Boolean;
ShowGlyphs:
Если содержит True. Рядом с именами файлов показываются пиктограммы типа файла.
Методы компонента сведены в табл. 14.9.
Таблица 14.9
Procedure ApplyFilePath Заменяет значения свойств Drive, Directory,
(const
FileName и Musk на те, что содержатся в
Procedure Update;
Обновляет содержимое окна.
Для компонента определено событие
property OnChange: TNotifyEvent;
возникающее при любом изменении выбора в окне компонента.
14.7.4. TFilterComboBox
Иерархия компонента:
TObject→TPersistent→Component→TControl→TWinControl→
TCustomCoinboBox→→TfilterComboBox
70

69.

Компонент TFilterComboBox представляет собой список выбора с
расширениями файлов. Совместно с компонентами TDirectoryListBox,
TDriveComboBox и TFileListBox может использоваться для создания диалоговых окон доступа к файлам. В Windows 95/NT все функции компонента
реализуются стандартным диалоговым окном TOpenDialog.
Табл. 14.10 содержит свойства компонента.
Таблица 14.10
Property
TfileListBox;
FileList:
Property Filter: string;
Property Mask: string;
Property Text: TCaption;
Указывает связанный с компонентом
объект для просмотра файлов.
Содержит фильтр в виде поясняющего
Содержит текущую маску выбора файСодержит поясняющий текст фильтра.
Для компонента определено событие
property OnChange: TNotifyEvent;
возникающее при любом изменении выбора в окне компонент;
также событие.
property OnDropDown: TNotifyEvent;
связанное с раскрытием списка.
71

70.

15. СОЗДАНИЕ СОБСТВЕННОГО КОМПОНЕНТА DELPHI
15.1. НАЧАЛО СОЗДАНИЯ И УСТАНОВКА КОМПОНЕНТА
Создание новых компонентов дает, конечно, неизмеримо больше
возможностей, чем построение шаблонов имеющихся компонентов. При
создании компонентов, наследующих каким-либо имеющимся в Delphi компонентам, вы можете добавить новые свойства, в том числе и отображаемые
в Инспекторе Объектов, добавить новые события и т.п. Однако, создание
новых компонентов — это непростой процесс, требующий хорошего понимания тонкостей наследования и хорошего знания свойств, методов и событий родительских компонентов. Некоторые основы этого будут рассмотрены
ниже.
Поставим перед собой сравнительно простую задачу: создать окно
редактирования, в котором по желанию во время проектирования и во время
выполнения можно будет разрешать ввод только цифр (например, если
предполагается, что пользователь должен вводить целое число), запрещать
ввод цифр (например , при вводе пользователем фамилии, имени и отчества)
или разрешать ввод любых символов. Кроме того предусмотрим очистку содержимого окна и свойство, показывающее, был ли модифицирован пользователем текст с момента последней очистки. В момент очистки определим
генерацию соответствующего события , которое пользователь при желании
может обрабатывать.
Построим наш компонент как наследника класса TEdit и назовем
наш новый класс TEditLetNum. В компонент, помимо свойств, обычных
для TEdit, желательно добавить два новых свойства: EnableNum и EnableLet. Тип обоих свойств - boolean. Первое из них разрешает или запрещает ввод цифр, а второе разрешает ввод запрещает ввод каких-либо символов,
кроме цифр. Таким образом, если EnableNum = true и EnableLet = true, то
это будет обычное окно редактирования. Если EnableNum = true, a EnableLet = false, получим окно, в котором можно вводить только цифры. Если EnableNum = false, a EnableLet = true, то в окно, запрещено вводить
цифры. Ну а ситуацию, когда EnabIeNum = false и EnableLet = false, надо
запретить, поскольку в такое окно ничего ввести невозможно.
Предусмотрим в компоненте метод Clear — очистку текста в окне и
свойство Modified , которое будет показывать, был ли модифицирован текст
с момента последней очистки. В момент очистки будем генерировать событие OnClear.
Компоненты в Delphi компилируются в пакеты. Поэтому, если вы
еще не создали пакет, в который хотите компилировать ваш новый компонент, то можете начать с его создания (впрочем, это можно сделать и позднее). Для создания нового пакета:
72

71.

1. Выполните команду File | New и в диалоговом окне New Items на
странице New выберите пиктограмму Package — пакет. Вам будет задан вопрос об имени файла и его описании. После этого вы попадете в окно Диспетчера Пакетов (Package Manager), которое в Delphi 5 выглядит так, как показано на рис. 15.1. В этом окне Contains — содержимое пакета, a Requires —
список других пакетов, требующихся для поддержки вашего.
2. Можете сразу сохранить пакет, выполнив команду File | Save As
или выбрав аналогичную команду Save из меню, всплывающего при щелчке
правой кнопкой мыши.
Рис. 15.1. Пустое окно Диспетчера Пакетов (Package Manager) в Delphi 5,
готовое для внесения нового компонента
3. Щелкнув на кнопке Add (добавить), вы попадете в окно, позволяющее вам включить в пакет модуль (Add Unit), компонент (New Component) или ActiveX (Import ActiveX). В данном случае вам надо включить в
пакет свой новый компонент. Для этого вы открываете соответствующую
страницу, которая имеет вид, представленный на рис. 15.2. Укажите в этом
окне родительский тип (выберите TEdit из выпадающего списка Ancestor
type), имя нового класса в окне Class Name (для нашего примера — TEditLetNum) cтpaницу в библиотеке компонентов (Palete Page), на которой хотите разместить пиктограмму вашего нового компонента. Можете указать
новую страницу и она будет создана. Проверьте также путь и имя модуля
вновь создаваемого компонента (окно Unit file name).
4. Щелкните на ОК и вы вернетесь в окно Диспетчера Пакетов,
но в нем уже появится имя вашего компонента. А если вы заранее создали файл ресурса компонента .dcr с его новой пиктограммой, то Диспет73

72.

чер Пакетов включит в пакет и этот файл.
5. Щелкните на кнопке Install (установка) и компонент будет установлен на указанной вами странице библиотеки компонентов. Можете
открыть эту страницу и увидеть его там. Выполнив в окне Диспетчера
Пакетов двойной щелчок на имени файла компонента, вы можете перейти в окно редактирования и увидеть, что в нем появилась заготовка модуля вашего компонента. Сохраните ее в файле (File | Save).
6. Чтобы скомпилировать модуль вашего компонента, можно
щелкнуть в окне Диспетчера Пакетов на кнопке Compile (компиляция).
Но в данном случае модуль уже скомпилирован во время его установки.
При выходе из Диспетчера Пакетов вам будет задан вопрос о сохранении информации в файле пакета (расширение этого файла .dpk). Ответьте
на вопрос утвердительно.
Рис. 15.2. Окно ввода информации о включаемом в пакет компоненте
Возможно и другое начало проектирования нового компонента.
1. Выполните команду Component | New Component и попадете в
почти такое же, как описано выше, окно New Component, представленное
на рис. 3.
2. Занеся в него необходимую информацию, щелкните на кнопке
Install... (установка) и перед вами появится диалоговое окно (рис. 4) с
двумя закладками:
Into existing package (устанавливать в существующий пакет) и Into
74

73.

new package (устанавливать в новый пакет). Выберите файл пакета из существующих или, лучше, укажите имя нового файла и строку его описания на
странице Into new package (рис. 4). Вам будет задан вопрос: File ... will be
built then installed. Continue? (Файл ... будет сначала построен, а потом установлен. Продолжать?). Ответьте на заданный вопрос утвердительно и файл
будет установлен в пакет, зарегистрирован на указанной странице в библиотеке, а его модуль появится в окне редактирования. На экране появится рассмотренное ранее окно Диспетчера пакетов (рис.15. 1).
Рис. 15.3. Окно задания информации о новом компоненте
Рис.15. 4. Окно ввода информации о новом пакете
75

74.

Мы рассмотрели пути создания новых пакетов и включения в них
новых компонентов. По умолчанию пиктограмма вашего компонента на соответствующей странице библиотеки будет взята тождественной пиктограмме родительского типа. А если вы заранее создали новую пиктограмму,
то именно ею вы сможете любоваться в палитре компонентов на указанной
вами странице.
В дальнейших сеансах работы с Delphi вы можете входить в окно
Диспетчера Пакетов, выполняя команду File | Reopen или File | Open. В последнем случае в диалоговом окне Open (открыть) установите шаблон типа
файлов Delphi package source (*.dpk) и найдите файл вашего пакета. Двойной
щелчок на имени компонента в окне Диспетчера Пакетов загрузит его модуль в Редактор Кода.
Если вы захотите удалить какой-нибудь модуль из пакета, это можно сделать в окне Диспетчера Пакетов, выделив нужный модуль и щелкнув
на кнопке Remove.
Удалить сам зарегистрированный пакет можно следующим образом:
1. Выполните команду Project | Options из главного меню и выберите
страницу Packages.
2. На этой странице щелкните на пакете, который вы хотите удалить, и затем щелкните на Remove.
15.2. АНАЛИЗ КЛАССА НОВОГО КОМПОНЕНТА
15.2.1. Структура класса компонента
Заготовка модуля компонента, созданная в результате указанных ранее
действий, имеет следующий вид:
unit EditLetNum;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TEditLetNum = class(TEdit)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
76

75.

{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents( 'MyComponents', [TEditLetNum]) ;
end;
end.
Собственно говоря, в этой заготовке пока только каркас класса будущего модуля и внесена одна процедура — Register, которая регистрирует компонент на заданной странице библиотеки.
Рассмотрим коротко описание класса. Вы видите в нем разделы private,
protected, public и published. Они определяют четыре варианта доступа к
переменным, процедурам и функциям:
Private (закрытые)
Процедуры и функции, определенные таким образом,
доступны только в пределах данного модуля.
Protected (защищенные) Процедуры и функции, определенные таким образом, доступны в классах потомков.
Public (открытые)
Эти процедуры и функции доступны везде.
Published (опубликованные) Процедуры и функции доступны везде и
имеют связь со средой разработки Delphi, обеспечивающую вывод на экран
в Инспекторе Объектов страниц информации о свойствах и событиях.
Вспомним определение объекта (компонент — это объект) как совокупности свойств, методов и обработчиков событий. Причем свойства — это
совокупность полей данных и методов их чтения и записи. Вспомним также
принцип скрытия информации. Исходя из этого, разработчик компонента
должен продумать, в какие разделы вставить вводимые им поля данных,
свойства и методы.
15.2.2. Свойства
Поля данных всегда должны быть защищены от несанкционированного
доступа. Поэтому их целесообразно определять в Private — закрытом разделе класса. В редких случаях их можно помещать в Protected — защищенном разделе класса, чтобы возможные потомки данного класса имели к ним
доступ. Традиционно идентификаторы полей совпадают с именами соответствующих свойств, но с добавлением в качестве префикса символа 'F'. Таким образом, в нашем примере вы можете занести в раздел Private объявле77

76.

ния трех необходимых нам полей данных:
private
{ Private declarations }
FEnableNum:boolean;
FEnableLet:boolean;
FModified:boolean ;
Теперь надо объявить свойства — методы чтения и записи этих полей.
Свойство объявляется оператором вида:
property <имя>:<тип> read <имя поля или метода чтения>
write <имя поля или метода записи>
<директивы запоминания>;
Если в разделах read или write записано имя поля, значит предполагается прямое чтение или запись данных.
Если в разделе read записано имя метода чтения, то чтение будет осуществляться только функцией с этим именем. Функция чтения — это функция
без параметра, возвращающая значение того типа, который объявлен для
свойства. Имя функции чтения принято начинать с префикса Get, после которого следует имя свойства.
Если в разделе write записано имя метода записи, то запись будет осуществляться только процедурой с этим именем. Процедура записи — это
процедура с одним параметром того типа, который объявлен для свойства.
Имя процедуры записи принято начинать с префикса Set, после которого
следует имя свойства.
Если раздел write отсутствует в объявлении свойства, значит это свойство только для чтения и пользователь не может задавать его значение.
Директивы запоминания определяют, как надо сохранять значения
свойств при сохранении пользователем файла формы .dfm. Чаще всего используется директива
default <значение по умолчанию>
Она не задает начальные условия. Это дело конструктора. Директива
просто говорит, что если пользователь в процессе проектирования не изменил значение свойства по умолчанию, то сохранять значение свойства не
надо.
Итак, для нашего примера объявления свойств могут иметь вид:
public
{ Public declarations }
property Modified:boolean read FModified default true;
published
78

77.

{ Published declarations }
property EnableNum:boolean read FEnableNum write SetEnableNum
default true;
property EnableLet:boolean read FEnableLet write SetEnableLet default true;
Объявление свойства Modified помещается в раздел public, поскольку
это свойство должно быть доступно только во время выполнения. Свойства
EnableNum и EnableLet помещаются в раздел published, так как они должны отображаться в Инспекторе Объектов во время проектирования.
Свойства EnableNum и EnableLet имеют прямой доступ к полям для
чтения. Но для записи они имеют методы SetEnableNum и SetEnableLet соответственно. Это связано с тем, что при записи свойств надо проверять, не
окажутся ли значения обоих этих свойств равными false. Подобное задание
значений надо предотвращать, поскольку в этом случае в окно редактирования вообще ничего нельзя будет ввести.
Свойство Modified вообще не имеет метода записи, поскольку оно
предназначено только для чтения.
Указанные в объявлениях методы записи могут быть реализованы простыми процедурами, объявления которых помещаются в private — закрытый раздел класса, а их реализация, приведенная ниже, помещается в раздел
модуля implementation — реализация.
Для того, чтобы задать свойствам начальные значения, надо еще объявить и написать конструктор. В итоге в данный момент модуль компонента
может иметь вид:
unit EditLetNum;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TEditLetNum = class(TEdit)
private
{ Private declarations }
FEnableNum:boolean ;
FEnableLet:boolean;
FModified:boolean ;
protected
{ Protected declarations }
79

78.

procedure SetEnableNum(Value:boolean); {Процедура записи}
procedure SetEnableLet(Value:boolean); {Процедура записи)
public
{ Public declarations }
property Modified:boolean read FModified default true;
constructor create(AOwner:TComponent);override; {Конструктор}
published
{ Published declarations }
property EnableNum:boolean read FEnableNum write SetEnableNum default true;
property EnableLet:boolean read FEnableLet write SetEnableLet
default true;
end;
procedure Register;
implementation
procedure TEditLetNum.SetEnableNum(Value:boolean) ;
begin
FEnableNum := Value; {Присваивание значения
FEnableNum}
полю
{ Если значения FEnableNum и FEnableLet = false, то полю FEnableLet
присваивается true }
if (not Value) then if (not FEnableLet) then FEnableLet := true;
end;
procedure TEditLetNum.SetEnableLet(Value:boolean) ;
begin
FEnableLet := Value; {Присваивание значения полю FEnableLet}
{ Если значения FEnableNum и FEnableLet = false, то полю FEnabieNum
присваивается true }
if (not Value) then if (not FEnableNum) then FEnableNum := true;
end;
procedure Register;
begin
RegisterComponents('MyComponents', [TEditLetNum]) ;
end;
constructor TEditLetNum.create(AOwner:TComponent);
begin
80

79.

inherited create(AOwner); {Вызов конструктора класса родителя}
FEnableNum := True;
FEnableLet := True;
FModified := False;
end;
end.
Процедуры, реализующие методы записи, присваивают полю переданное
значения Value и в случае, если передано значение false, проверяют значение другого поля. Если и другое поле имеет значение false, то оно исправляется на true.
Объявления процедур записи включены в раздел protected. Это означает,
что они закрыты для внешнего пользователя, но доступны для возможных
потомков вашего класса.
Конструктор объявлен в открытом разделе класса public и имеет стандартное имя — create. Указанная после объявления конструктора директива
override говорит о том, что производится переопределение конструктора
класса-родителя. В реализации конструктора первый оператор
inherited create(AOwner);{Вызов конструктора класса родителя}
обеспечивает вызов конструктора родительского класса, который и выполняет основную работу по созданию объекта. Ключевое слово inherited
показывает, что вызывается именно метод родительского класса. Последующие операторы конструктора просто задают начальные значения новым
свойствам, которые вы добавили в компонент.
Обратите внимание, что в реализации всех процедур к имени процедуры
добавляется в начале имя класса.
Теперь давайте построим тестовое приложение для отладки установленного компонента. Хотя он еще не до конца создан, кое-что уже можно увидеть.
Откройте, если вы его закрыли. Диспетчер Пакетов, выполнив команду
File | Open, установив в диалоговом окне Open шаблон типа файлов Delphi
package source (*.dpk) и найдя файл вашего пакета. В открывшемся окне
Диспетчера Пакетов сделайте щелчок на имени вашего компонента и его
модуль загрузится в окно Редактора Кода. Введите в него указанные выше
добавления. После этого скомпилируйте модуль, щелкнув на кнопке Compile в Диспетчере Пакетов.
Откройте новый проект и внесите в него с соответствующей страницы
ваш новый компонент. Взгляните на его свойства в Инспекторе объектов.
81

80.

Вы найдете там добавленные вами свойства EnableNum и EnableLet. Оба
свойства имеют по умолчанию заданные в конструкторе значения true. Попробуйте изменить оба значения на false. Это вам не удастся сделать, так как
сработают написанные вами методы записи.
Свойство Modified в Инспекторе объектов вы не увидите, так как это
свойство может использоваться только во время выполнения.
15.2.3 Методы
Методы включаются в открытый раздел класса — раздел public, поскольку иначе их нельзя было бы использовать. Собственно один метод —
Create, вы уже написали, причем переопределили соответствующий метод
родительского класса. Теперь вам нужно написать метод Clear, очищающий
содержимое окна редактирования и устанавливающий значение поля
FModified равным false. Генерировать событие OnClear мы пока не будем.
При записи метода Clear, как и в методе Create, вы можете воспользоваться
переопределением аналогичного метода родительского компонента. В этом
случае объявление и реализация метода Clear может иметь вид:
public
{ Public declarations }
procedure Clear; override;
implementation
procedure TEditLetNum.Clear;
begin
inherited clear; {Вызов родительского метода}
FModified := false;
end;
Впрочем, в данном случае вы могли бы и не обращаться к родительскому методу. В этом случае можно было бы исключить директиву
override в объявлении метода и вызов родительского метода. Тогда приведенный выше текст мог бы иметь вид:
public
{ Public declarations }
procedure Clear;
implementation
procedure TEditLetNum.Clear;
begin
Text := ' ';
FModified := false;
82

81.

end;
Теперь запишем главную процедуру, ради которой мы и создавали свой
компонент: процедуру, разрешающую или запрещающую ввод символов того или иного типа. Для этого нам надо анализировать вводимый пользователем символ. Это можно делать при обработке события OnKeyPress. Значит
нам надо переопределить стандартный обработчик этого события в родительском компоненте TEdit. Стандартные обработчики имеют то же имя,
что и события, но без префикса On. To есть обработчик события
OnKeyPress имеет имя Keypress. Передаваемые в стандартный обработчик
параметры те же, что вы можете видеть в заготовке процедуры обработки
события, если щелкните на этом событии в Инспекторе Объектов, но без параметра Sender.
Например, щелкнув в Инспекторе Объектов на событии OnKeyPress
любого компонента, вы увидите, что в процедуру обработки передаются параметры:
(Sender: TObject; var Key: Char)
Значит в создаваемый нами обработчик и при вызове родительского обработчика надо использовать только один параметр: var Key: Char.
Таким образом, введение в модуль компонента требуемого нам обработчика может свестись к включению в раздел protected объявления:
procedure Keypress(var Key: Char);override;
и написанию в разделе implementation реализации процедуры:
procedure TEditLetNum.Keypress(var Key: Char);
begin
if (not FEnableNum) and (key in ['0'..'9']) then key := #0;
if (not FEnableLet) and not (key in ['0'..'9']) then key := #0;
if (key < > #0) then FModified := true;
inherited Keypress(Key);
end;
Эта процедура заменяет недопустимые символы нулевыми, если символ
допустимый, то задается значение true полю свойства FModified и затем
вызывает метод KeyPress родительского класса.
Можно скомпилировать и протестировать полученный компонент. Для
этого расположим на форме свой компонент EditLetNum, кнопку Button,
задав на ней надпись (Caption) Clear, и метку Label. В обработчике события
OnKeyUp компонента EditLetNum напишем оператор:
if EditLetNum1.Modified
then Label1.Caption := 'Modified = true' else Label1.Caption := 'Modified = false';
Он обеспечит отображение на экране состояние свойства Modified. Аналогичный оператор напишем в обработчике события OnShow формы, чтобы
83

82.

отобразить на экране начальное состояние свойства Modified. В обработчике события кнопки OnClick напишем:
EditLetNum1.Clear;
FormShow(Sender);
Конечно, можно вместо обращения к уже написанному обработчику
FormShow повторить все тот же оператор отображения на экране состояния
Modified. Но использовать уже написанный обработчик короче.
15.2.4. События
В нашем примере требуется ввести событие OnClear, происходящее в
момент очистки окна методом Clear. В Delphi событие — это просто специальное свойство, являющееся указателем функции. Тип обобщенного указателя на функцию, которой передается один параметр типа TComponent
(обычно Self), — TNotifyEvent. Подобный тип используется в Delphi для
событий типа OnClick и многих других, которые передают в обработчик
только один параметр — Sender: TObject. Подойдет этот тип и нам для события OnClear.
В этом случае объявления нашего события могут иметь вид:
private
{ Private declarations }
FClear:TNotifyEvent; {Поле события OnClear}
published
{ Published declarations }
property OnClear:TNotifyEvent read FClear write FClear;
Остается только вызвать в нужный момент обработчик события пользователя, если пользователь его предусмотрел. Проверка, имеется ли обработчик пользователя, осуществляется функцией assigned, которая возвращает
true, если пользователь предусмотрел свой обработчик. В нашем случае эта
проверка и вызов обработчика пользователя осуществляется добавлением в
процедуру метода Clear оператора:
if assigned(FClear) then OnClear(Self);
который вызывает обработчик пользователя OnClear.
Откомпилируйте компонент, выделите его на форме тестового приложения и посмотрите страницу событий в Инспекторе Объектов. Вы увидите,
что в списке его событий появилось событие OnClear. Дважды щелкните на
его правом окне и вы увидите в тексте модуля заготовку для обработчика
этого события:
procedure TForm1.EditLetNum1Clear(Sender: TObject) ;
84

83.

begin
end;
Внесите в этот обработчик какой-нибудь оператор, который бы отображал на экране факт свершения этого события, например:
ShowMessage('Событие OnShow') ;
Теперь компонент и тестовое приложение завершены. Результирующий
код модуля компонента может иметь вид:
unit EditLetNum;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TEditLetNum = class(TEdit)
private
{ Private declarations }
FClear:TNotifyEvent; {Поле события OnClear}
FEnableNum:boolean;
FEnableLet:boolean;
FModified:boolean;
protected
{ Protected declarations }
procedure SetEnableNuiti(Value:boolean) ;
procedure SetEnableLet(Value:boolean) ;
procedure Keypress(var Key: Char);override;
public
{ Public declarations }
property Modified:boolean read FModified default true;
constructor create(AOwner:TComponent);override;
procedure Clear;override;
published
{ Published declarations }
property OnClear:TNotifyEvent read Fclear write FClear; {событие}
property EnableNum:boolean read FEnableNum write SetEnableNum default true;
property EnableLet:boolean read FenableLet write SetEnableLet
default true
end;
procedure Register;
85

84.

implementation
procedure TEditLetNum. SetEnableNum (Value : boolean) ;
begin
FEnableNum := Value;
if (not Value) then if (not FEnableLet) then FEnableLet := true;
end;
procedure TEditLetNum.SetEnableLet(Value:boolean) ;
begin
FEnableLet := Value;
if (not Value)
then if (not FEnableNum) then FEnableNum := true;
end;
procedure Register;
begin
RegisterComponents('MyComponents', [TEditLetNum]) ;
end;
constructor TEditLetNum. create (AOwner:TComponent) ;
begin
inherited create(AOwner) ;
FEnableNum := True;
FEnableLet := True;
FModified := False;
end;
procedure TEditLetNum.Keypress(var Key: Char);
begin
if (not FEnableNum) and (key in ['0'..'9']) then key := #0;
if (not FEnableLet) and not (key in ['0'..'9']) then key := #0;
if (key <> #0) then FModified := true;
inherited Keypress(Key);
end;
procedure TEditLetNum. Clear;
begin
{Вызов обработчика пользователя}
if assigned(FClear) then OnClear(Self);
{Вызов родительского' метода}
inherited clear;
FModified := false;
end;
86

85.

end.
Мы рассмотрели простейший вариант задания события типа TNotifyEvent. Попробуем несколько усложнить это событие. Пусть мы будем передавать в это событие параметр CanCIear, который по умолчанию равен
true, что будет означать разрешение очистить текст окна редактирования.
Но предоставим пользователю возможность в своем обработчике события
задать этому параметру значение false, что будет означать отказ от очистки.
В данном случае нам надо объявить новый тип события:
TClearFunc = procedure(Sender:TObject; var CanClear: boolean) of
object;
Это объявление типа должно помещаться в разделе type, например, перед предложением
TEditLetNum = class(TEdit)
Тогда в объявлениях свойства и его поля надо ссылаться на этот тип,
следующим образом изменив соответствующие операторы:
FClear: TClearFunc; {Поле события OnClear}
property OnClear:TClearFunc read FClear write FClear; {событие}
Осталось изменить метод Clear так, чтобы в нем учитывался новый параметр CanClear:
procedure TEditLetNum.Clear;
var CanClear:boolean;
begin
CanClear := true;
{Вызов обработчика пользователя}
if assigned(FClear) then OnClear(Self,CanClear);
if not CanClear then exit; {Выход, если CanClear=false}
{Вызов родительского метода}
inherited clear;
FModified := false;
end;
Теперь надо изменить тестирующее приложение. Возможный вид нового тестирующего приложения представлен на рис. 15.5. В нем добавлено три
индикатора типа СheckBox, которые указывают допустимость ввода цифр,
букв и допустимость очистки (назовем их CBNum, CBLet и CBClear соответственно).
87

86.

Рис. 15. 5 Тестовое приложение вашего нового компонента.
Обработчик события OnClick кнопки надо изменить по сравнению с
прежним приложением, добавив в него анализ того, установлен флажок в
индикаторе CBClear, или нет (анализ свойства Checked). Но тут можно
столкнуться с трудностью, если тестовое приложение делать не заново, а
изменяя предыдущее. По сравнению с прошлым вариантом компонента в
функцию обработчика добавился параметр. Поэтому прежний обработчик
события OnClear будет выдавать вам синтаксические ошибки. Надо или
уничтожить его и написать новый, или вручную исправить заголовки в объявлении обработчика и в его реализации, которая может иметь вид:
procedure TForm1.EditLetNumlClear(Sender: TObject; var CanClear: Boolean);
begin
CanClear := CBClear.Checked;
ShowMessage('Событие OnShow') ;
EditLetNum1.SetFocus;
end;
В этом обработчике значение параметра CanClear, разрешающего или
запрещающего очистку, задается в зависимости от того, установлен или нет
индикатор CBClear.
Обработчик события OnCIick индикатора CBNum может иметь вид:
EditLetNum1.EnableNum:=CBNum. Checked;
CBLet.Checked:=EditLetNum1.EnableLet ;
EditLetNum1.SetFocus;
88

87.

Первый оператор этого обработчика устанавливает значение параметра
EnableNum в зависимости от состояния индикатора CBNum. Второй оператор устанавливает состояние индикатора CBLet равным значению параметра EnableLet. Это надо, поскольку если, например, сбрасывается на false
значение параметра EnableNum, а значение параметра EnableLet в этот момент тоже было равно false, то компонент EditLetNumI установит значение
EnableLet равным true. И надо, чтобы это новое значение отобразилось в
индикаторе CBLet.
Аналогично может выглядеть обработчик события OnCIick индикатора
CBLet:
EditLetNum1.EnableLet:=CBLet.Checked;
CBNum.Checked:=EditLetNum1.EnableNum;
EditLetNum1.SetFocus;
Вот и все. Необходимо только согласовать исходные значения параметров EnableNum и EnableLet с исходными состояниями индикаторов
CBNum и CBLet. Если, например, было установлено CBNum в true, a
CBLet в false, то индикатор CBNum должен быть включен (свойство
Checked = true), а индикатор CBLet — выключен.
89

88.

СПИСОК ЛИТЕРАТУРЫ
1.
2.
Фаронов В.В. Delphi 5. Учебный курс. - М.: "Нолидж", 2000. 400 с.
Культин Н. Программирование на Object Pascal Delphi 5. СПб.: BHV Санкт-Петербург, 2000. 464 с.
3. Эндрю Возневич. Delphi. Освой самостоятельно: Пер. с англ. М.: Восточная Книжная Компания, 1996. 736 с.
4. Турбо Паскаль 7.0. Киев: Издательская группа BHV, 1998. 448 с.
5. Шилдт Г. Самоучитель С++, 3-е издание: Пер. с англ. СПб.: BHV Санкт-Петербург, 1998. 688 с.
6. Сергиевский М.В., Шалашов А.В. Турбо Паскаль 7.0: Язык, среда программирования. М.: Машиностроение, 1994. 254 с.
7. Канту М. Delphi 2 для Windows 95/NТ. Полный курс. В 2 т. Т. 1: Пер. с
англ. М.: Малип, 1997. 400 с.
8. Дарахвелидзе П.Г., Марков Е.П. Delphi 4. – Спб.:БХВ – Санкт – Петербург,1999
9. Кент Рейсдорф. Освой самостоятельно Delphi 4. М., ЗАО «Издательство
БИНОМ» Лаборатория Базовых Знаний, 1999.
10. Кен Хендерсон. Delphi 3 и системы Клиент-Сервер. Руководство разработчика. М.-Киев, «Диалектика», 1997.
11. Архангельский. Программирование в Delphi 5.-М.: «Нолидж», 2000.
90

89.

ОГЛАВЛЕНИЕ
10.ПАНЕЛИ ИНСТРУМЕНТОВ И ДРУГИЕ ЭЛЕМЕНТЫ
ИНТЕРФЕЙСА..................................................................................................... 3
10.1. РАЗНОВИДНОСТИ
ПАНЕЛЕЙ .................................................................. 3
10.1.1. Компонент ToolBar...................................................................... 3
10.1.2. Компонент TCoolBar ................................................................... 6
10.1.3. Компонент TControlBar............................................................... 9
10.1.4. Меню в панели компонентов ..................................................... 11
10.2. СТРОКА СОСТОЯНИЯ............................................................................ 11
10.2.1. Свойства строки состояния..................................................... 14
10.2.2. Основные события ..................................................................... 19
10.2.3. Основные методы ...................................................................... 20
10.2.4. Простая или составная?........................................................... 22
10.2.5. Изменение текста в строке состояния................................... 23
10.2.6 Специальные панели строки состояния.................................... 24
10.2.7.Листинг.демонстрационнойl программы StatBar.................... 25
11. МНОГОСТРАНИЧНЫЕ ФОРМЫ ..................................................... 28
11.1. TTABCONTROL - НАБОР ЗАКЛАДОК ..................................................... 28
11.2. TPAGECONTROL - НАБОР СТРАНИЦ С ЗАКЛАДКАМИ ........................... 30
11.3. TSCROLLBOX - ПАНЕЛЬ С ПРОКРУТКОЙ .............................................. 32
12. ОКНА ДИАЛОГА И МНОГОСТРАНИЧНЫЕ ФОРМЫ ............... 34
12.1. СОЗДАНИЕ ВТОРИЧНОЙ ФОРМЫ В ПРОГРАММЕ ................................... 34
12.2. МНОГООБРАЗИЕ ОКОН СООБЩЕНИЙ ................................................... 35
12.2.1. Демонстрация различных вариантов окна сообщени............. 36
12.2. СТАНДАРТНЫЕ ДИАЛОГИ WINDOWS ................................................... 40
12.2.1. Диалоги открытия и сохранения файлов (TOpenDialog
91

90.

TSaveDialog).................................................................................................. 40
12.2.2.Пример использования TopenDialog .......................................... 43
12.2.3. Диалог выбора шрифта(TFontDialog)...................................... 43
12.2.4. Диалог выбора цвета (TColorDialog) ....................................... 44
13. ОСНОВЫ ОРГАНИЗАЦИИ MDI........................................................ 45
13.1. СОЗДАНИЕ ФОРМ ................................................................................. 46
13.1.1. Автоматическое создание форм .............................................. 46
13.1.2. Динамическое создание форм ................................................... 47
13.2. MDI-СВОЙСТВА TFORM ...................................................................... 48
13.2.1. ActiveMDIChild............................................................................ 48
13.2.2. MDIChildren и MDIChildCount .................................................. 49
13.2.3. TileMode....................................................................................... 50
13.2.4. WindowMenu................................................................................ 50
13.3. MDI-СОБЫТИЯ TFORM ........................................................................ 50
13.4. MDI-МЕТОДЫ TFORM .......................................................................... 50
13.5. ПРИМЕР MDI-ПРИЛОЖЕНИЯ ............................................................... 50
13.5.1. Создание интерфейса ................................................................ 50
13.5.2. Написание кода........................................................................... 52
14.РАБОТА С ФАЙЛАМИ В DELPHI ..................................................... 54
14.1. ДОСТУП К ФАЙЛАМ ...................................................................... 54
14.2. ПРОЦЕДУРЫ И ФУНКЦИИ ДЛЯ РАБОТЫ С ФАЙЛАМИ ......... 55
14.3. ТЕКСТОВЫЕ ФАЙЛЫ ..................................................................... 58
14.4. ТИПИЗИРОВАННЫЕ ФАЙЛЫ ....................................................... 59
14.5. НЕТИПИЗИРОВАННЫЕ ФАЙЛЫ.................................................. 60
14.6. СРЕДСТВА WINDOWS ДЛЯ РАБОТЫ С ФАЙЛАМИ ................. 61
14.7. РАБОТА С ФАЙЛОВОЙ СИСТЕМОЙ. .......................................... 66
14.7.1. TDriveComboBox......................................................................... 66
14.7.2. TDirectoryListBox ........................................................................ 67
92

91.

14.7.3. TFileListBox ................................................................................. 69
14.7.4. TFilterComboBox......................................................................... 70
15. СОЗДАНИЕ СОБСТВЕННОГО КОМПОНЕНТА DELPHI........... 72
15.1. НАЧАЛО СОЗДАНИЯ И УСТАНОВКА КОМПОНЕНТА .............................. 72
15.2. АНАЛИЗ КЛАССА НОВОГО КОМПОНЕНТА............................................ 76
15.2.1. Структура класса компонента ................................................ 76
15.2.2. Свойства ..................................................................................... 77
15.2.3 Методы ........................................................................................ 82
15.2.4. События...................................................................................... 84
СПИСОК ЛИТЕРАТУРЫ .......................................................................... 90
ОГЛАВЛЕНИЕ ............................................................................................. 91
93
English     Русский Rules