Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ракитин Р.Ю. ООП в Turbo Delphi

.PDF
Скачиваний:
55
Добавлен:
18.03.2015
Размер:
3.59 Mб
Скачать

111

внутри заданной области. Палитры могут пристыковываться друг к другу, подстраивать размеры, а расположенные на них элементы управления можно перетаскивать между палитрами. Так в частности реализованы некоторые окна в самой системе Delphi. Например, Менеджер проектов и Инспектор объектов можно объединить вместе. Для этого в их контекстных меню имеется пункт Dockable (Стыкуемый). Если этот пункт включен (помечен галочкой), то он позволяет данному окну пристыковываться к другим окнам среды.

Практическое задание

Механизм перетаскивания

1. Рассмотрим работу данного механизма на двух примерах: перетаскивание текста из текстового поля на панель и перемещение кнопки по форме. Примеры будут созданы в рамках формы Form1. На ней разместить три компонента (текстовое поле, панель и кнопку), которые получат названия Edit1, Panel1 и Button1.

2. Для объекта Edit1 создадим обработчик события OnMouseDown. В нем проверяем, нажата ли именно левая кнопка, и вызываем метод BeginDrag с параметром False. Это означает, что процесс перетаскивания не начнется, пока пользователь не переместит мышь на некоторое расстояние. Это позволяет не путать простые щелчки на объекте с началом процесса перетаскивания.

procedure TForm1.Edit1MouseDown(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

if Button = mbLeft then Edit1.BeginDrag(False);

end;

3. Для объекта Panel1 создадим обработчик события OnDragOver путем двойного щелчка на соответствующей строке панели Events в Инспекторе объектов. В нем проверяется, является ли исходный (перетаскиваемый) объект полем ввод Edit1. Результат проверки заносится в параметр Accept.

procedure TForm1.Panel1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);

begin

Accept := Source = Edit1 end;

Можно выполнить и более общую проверку.

Source is TEdit;

4. Панель должна обрабатывать еще одно событие OnDragDrop, генерируемое, когда происходит «сброс» перетаскиваемого объекта. В нем производится итоговое действие, в нашем случае: в заголовок панели записывается текст, находящийся в текстовом поле.

112

procedure TForm1.Panel1DragDrop(Sender, Source: TObject; X, Y: Integer);

begin

Panel1.Caption := Edit1.Text end;

5.Запустим программу, на форме Form1, наведем указатель на текстовое поле (в нем первоначально хранится текст Edit1), нажмем левую кнопку мыши и, не отпуская ее, переместим мышь по направлению к панели. Указатель при этом примет вид перечеркнутого кружка, означающего, что в данном месте «сброс» перетаскиваемого объекта недопустим. Когда указатель окажется в области панели, он примет вид небольшой стрелки с квадратом. Теперь отпустим кнопку, и надпись на панели сразу изменится на Edit1.

6.Второй пример идеологически во многом напоминает первый. Для объекта Button1 создадим обработчик нажатия кнопки мыши, в котором начинается процесс перетаскивания кнопки:

procedure TForm2.Button1MouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState;

X, Y: Integer); begin

if Button = mbLeft then Button1.BeginDrag(False);

end;

7. Правом «принимать» кнопку должна обладать сама форма. Для этого она должна так обрабатывать событие OnDragOver, чтобы разрешить прием кнопок.

procedure TForm1.FormDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);

begin

Accept := Source is TButton end;

8. Обработаем событие OnDragDrop. В ходе обработки для исходной кнопки (параметр Source, приведем к типу TButton с помощью операции as) зададим новые координаты ее местоположения на форме (свойства Left и Тор):

procedure TForm1.FormDragDrop(Sender, Source: TObiect; X, Y: Integer);

begin

(Source as TButton).Left := X;

(Source as TButton).Top := Y; end;

Теперь простыми движениями мыши кнопку можно свободно перемещать по форме.

113

Механизм стыковки

1. Рассмотрим механизм стыковки (drag-and-dock) для этого создадим новый проект. На главной форме разместим две панели Panel1 и Panel2. На первой панели дополнительно поместим две кнопки Button1 и Button2. Примерный вид приложения показан на рисунке.

2. Обеспечить работу механизма стыковки можно и без программирования. Для этого сначала укажем те объекты, которые будут выступать в роли стыкуемых палитр: Panel1 и Раnеl2. Свойства DockSite этих объектов определяют, может ли данный объект выполнять функции палитры. Значения этих свойств установим равным True.

3. Чтобы автоматически поддерживать режимы стыковки, не обращаясь программно к методам этих палитр, для свойств DragMode (Режим перетаскивания) зададим значение dmAutomatic. Кроме того, значения свойств DragKind (Вид перетаскивания)

изменим с dkDrag (Свободное перетаскивание) на dkDock (Стыковка).

4.Кнопки не могут служить полноценными палитрами (свойства DockSite у них нет), поэтому для каждой из кнопок настроим только свойства DragMode (значение dmAutomatic) и DragKind (значение dkDock). Созданную программу откомпилируем и запустим. Теперь любую панель можно таскать по форме, помещать внутрь другой панели и перетаскивать кнопки, стыкуя их друг с другом самым причудливым образом.

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

6.Чтобы позволить и кнопкам, и панелям «приземляться» на форме, изменим свойства основной формы: свойство DockSite на True, а значение свойства

DragKind установим равным dkDock. Теперь и кнопки, и панели в процессе их перемещения будут устанавливаться в любом месте формы.

114

7. Программная поддержка процесса стыковки похожа на обработку процесса перетаскивания. Однако стыкуемой палитре необходимо предварительно обработать новое сообщение OnGetSitelnfo, с помощью которого передается информация об объекте, который хочет пристыковаться к данной палитре, и его размер (хранящийся в параметре InfluenceRect). Аргумент CanDock, передающийся по ссылке, должен получить значение True, если разрешение на стыковку дается. При этом можно изменить область, отводимую для стыковки (прямоугольник InfluenceRect, который тоже передается по ссылке). Например, можно запретить панели Panel2 принимать кнопки.

procedure TForm3.Panel2GetSiteInfо (Sender: TObject; DockClient: TControl; var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);

begin

CanDock := not(DockClient is TButton) end;

Через параметр DockClient передается элемент управления (класс TControl), который собирается пристыковаться к панели.

8. Если теперь перемещать кнопки по форме, то хотя они и могут располагаться на панели Panel2, но процесс автоподстройки их положения и размера под панель выполняться не будет (а объект Panel1 по-прежнему сможет пристыковываться к палитре Panel2).

9. Два события: OnDockOver (При попытке стыковки), генерируемое при перемещении объекта над палитрой, и OnDockDrop (При завершении стыковки) – аналогичны событиям OnDragOver и OnDragDrop. Еще одно новое событие, OnUnDock, посылается палитре при попытке вытаскивания объекта с нее. Обрабатывая это событие, можно, например, запретить перемещать с палитры (панели Panel1) определенные элементы управления (кнопки).

procedure TForm3.PanellUnDock (Sender: TObject; Client: TControl; NewTarget: TWinControl; var Allow: Boolean);

begin

Allow := not (Client is TButton); end;

Параметр Client описывает элемент управления, который пользователь пытается забрать с палитры. Параметр Allow должен получить значение True, если разрешается забрать этот элемент, и False в противном случае.

115

Глава 10. Использование меню

Компоненты меню являются наиболее часто используемыми элементами управления в среде Windows.

Компонент Главное меню (TMainMenu)

Компонент TMainMenu предназначен для добавления к программе главного меню.

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

Чтобы добавить к разрабатываемой программе меню, надо выбрать на панели компонентов Standard (Стандартные) компонент TMainMenu и поместить его на форме в произвольном месте.

Компонент ТМаinМеnu невизуальный, в отличие от визуальных компонентов, например TEdit и TLabel. Это означает, что хотя он виден на форме как небольшой квадрат, в окне созданной программы в таком виде компонент не появится. Представление его на форме в миниатюрном виде просто указывает на наличие в программе объекта, ответственного за меню. А создается меню с помощью специального редактора.

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

Редактор меню вызывается двойным щелчком на объекте МаinМеnu1. Первоначально меню пустое. Откроем Инспектор объектов и в свойство Caption (Заголовок) текущего пункта напишем команду &Действия, а затем нажмем клавишу ENTER. Редактор меню переключится обратно в проектируемое меню, где уже появится первый пункт.

+ Символ амперсанда (&) ставится перед тем символом, который

определяет клавишу быстрого вызова.

Теперь надо опять нажать клавишу ENTER, и система Delphi переключится к заголовку Caption для нового пункта. В него введем очередное название (например, &Сложить), опять нажимаем клавиша ENTER, и цикл формирования меню повторяется. Создадим еще три пункта: Разность, Умножить,

Делить.

Чтобы вставить линию-разделитель, надо в свойстве Caption в первой позиции указать символ «-» (дефис).

Самым последним добавим пункт &Выход.

Для вставки/добавления новых пунктов служит клавиша INSERT, для удаления клавиша DELETE. Но проектируемому меню можно перемещаться с помощью курсорных клавиш.

Редактор меню позволяет создавать и подменю. Например, создадим подменю Операция, в котором разместим пункты: Сложить, Разность,

116

Умножить и Делить. Создав новый пункт и нажав правой кнопкой мыши, выберите Create Submenu (Создать подменю). И уже в нем

методом описанным выше создадим пункты меню.

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

+ Редактировать структуру меню можно только обращением к

объекту MainMenu.

С каждым пунктом меню можно связать системную горячую клавишу, для этого используется свойство ShortCut. В котором указывается сочетание клавиш, например Ctrl+Alt+S или F1 (их можно выбрать из всплывающего меню). Выбранная горячая клавиша будет отображаться напротив пункта меню.

В свойстве Bitmap можно указать иконку, которая будет отображаться вместе с пунктом меню.

Создание обработчиков

Чтобы создать обработчик события, возникающего при выборе одного из пунктов меню, надо в Редакторе меню дважды щелкнуть на соответствующем пункте, например на пункте Выход. Как и в случае кнопки, система Delphi автоматически создаст новый метод обработки события OnClick.

procedure TMyForm.N4Click(Sender: TObject); begin

...

end;

N4 это идентификатор пункта меню Выход внутри программы. В описании класса TMyForm (наряду с другими пунктами: N1, N2 и т.д.) декларирован так:

N4: TMenuItem;

Класс TMenuItem предназначен для объявления пунктов меню.

Чтобы закрыть приложение при выборе пункта Выход, надо в реализации метода N4Click вызвать метод Close класса TForm, наследником которого является класс TMyForm. Этот метод выполняет корректное закрытие текущей формы (окна) и следовательно всего приложения.

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

117

procedure TMyForm.N2Click (Sender: TObject); var

a, b, c: real; begin

a:=StrToFloat(Edit1.Text);

b:=StrToFloat(Edit2.Text);

c:=a+b;

Label1.Caption:= FormatFloat('0.00', c); end;

Аналогичным образом реализуйте остальные пункты меню.

Компонент Контекстное меню (TPopupMenu)

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

После того как TPopupMenu размещен па форме (он почти не отличается от компонента TMainMenu и также является невизуальным), структура будущего меню формируется способом, описанным при создании строки меню. Единственное отличие состоит в том, что в контекстном меню не может быть нескольких разделов верхнего уровня, так как все его пункты располагаются в одном вертикальном столбце.

Разместим в примере, рассмотренном ранее, компонент PopupMenu. Продублируем название всех пунктов главного меню в контекстном меню.

Так как необходимые нам обработчики созданы ранее для главного меню, свяжем их с соответствующими пунктами контекстного меню. Для этого, выбрав нужный пункт меню, перейдем на вкладку Events и напротив события OnClick выберем соответствующий метод.

Например, для пункта Выход выберем

обработчик N4Click. Аналогичным способом создается и обработчик события, возникающего при выборе остальных пунктов меню.

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

118

Глава 11. Работа с файловой системой. Стандартные диалоговые окна

Windows

Файлы

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

приближении файл можно рассматривать как массив переменной длины неограниченного размера.

Работа с файлами в приложениях Delphi может производиться двумя принципиально разными способами:

с помощью специальных механизмов работы с файлами файловых переменных и дескрипторов;

с помощью потоков данных.

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

Мы рассмотрим первый подход работы с файлами, как наиболее часто используемый в приложениях VCL.

1. Файловый ввод/вывод c помощью компонентов

Работа с текстовыми файлами может осуществляться с помощью методов

LoadFromFile и SaveToFile, имеющихся у классов VCL TStrings и TStringList. Эти классы описывают списки строк и обладают множеством методов, позволяющих манипулировать строками.

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

var

List: TStringList; SFile: String;

В момент, когда вы хотите загрузить в свой список файл, надо создать спи- сок List и задать имя открываемого файла:

List := TStringList.Create;

SFile :='c:\MyTest\Test.txt';

119

Когда объект List больше не будет нужен, его надо будет удалить из памяти оператором:

List.Free;

Если вы хотите открыть файл, расположенный в текущем каталоге, то имя файла SFile можно указывать без пути к нему. Загрузка файла в список осуществляется оператором:

List.LoadFromFile (SFile);

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

try

List.LoadFromFile (SFile); except

ShowMessage ('Файл “ ‘ + SFile + ‘ “ не найден’); end;

Итак, если файл нормально загрузился в список List, можно работать с его текстом. Текст расположен в свойстве списка Strings[Index], в котором каждая строка имеет тип AnsiString. Индексы начинаются с нуля. Для нашего примера List.Strings[0] это первая строка, List.Strings[l]

вторая и т.д.

Если вы хотите сохранить файл после проведенного редактирования,

можно выполнить оператор

List.SaveToFile (SFile);

где SFile содержит прежнее или новое имя файла.

Если вы открываете файл для того, чтобы пользователь мог его просмотреть, что-то в нем отредактировать и сохранить, можно обойтись без описанного выше объекта типа TStringList. В приложениях VCL для этих

целей проще воспользоваться многострочными окнами редактирования типов ТМеmo или TRichEdit. В последнем случае вы можете работать не только с обычными текстовыми файлами, но и с файлами в обогащенном формате RTF. Свойства Lines этих компонентов имеют тип TStrings, что позволяет применять к ним непосредственно методы LoadFromFile и SaveToFile. Например:

Memol.Lines.LoadFromFile (SFile); RichEditl.Lines.LoadFromFile (SFile);

2. Использование файловых переменных

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

120

объявлен в разделе описания переменных. При объявлении файла указывается тип элементов файла.

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

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

использоваться для обращения к этому файлу во всех процедурах обработки.

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

3.Закрытие файла. При этом файл становится доступным к другим файлам без ограничений.

Типизированные файлы

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

<Имя>: file of <ТипЭлементов>;

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

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

AssignFile (<ИмяПеременной>, <ПутьФайлаНаДиске>);

Затем необходимо открыть файл одной из процедур:

1.Rewrite (<ИмяПеременной>) открытие файла в режиме записи (при этом происходит полное уничтожение его содержимого, а размер файла становится равным нулю);

2.Reset (<ИмяПеременной>) открытие файла в режиме чтения (вносить изменения в содержимое файла не разрешается).

Запись в открытый файл осуществляется с помощью процедуры

Write (<ИмяПеременной>, <СписокПеременных>);

где <СписокПеременных> переменные перечисляемые через запятую и соответствующие типу файла.

Считывание данных из файла осуществляется с помощью процедуры:

Read (<ИмяПеременной>, <СписокПеременных>);

По завершении работы с файлом его надо закрыть. Это выполняется с помощью процедуры: