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

Технологии программирования. Программирование графических интерфейс

.pdf
Скачиваний:
3
Добавлен:
15.11.2022
Размер:
2.24 Mб
Скачать

16.При вводе данных в поля объекта при его создании

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

иустанавливать фокус ввода на пустом поле.

Вопросы для самоконтроля

1.В каком месте программы, каким образом и зачем надо регистрировать пользовательские классы? Что будет, если классы не зарегистрировать?

2.Объясните, каким образом реализуется процедура создания объектов: диалог для ввода полей объекта, создание объекта, добавление егов список TList, добавление егов список TListBox.

3.Объясните, как сделать, чтобы форма не создавалась автоматически при загрузке программы.

4.Приведите пример создания формы во время выполнения программы.

5.Объясните свойства и методы класса TList.

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

7.Что будет, если метод пользовательских классов Show сделать невиртуальным?

8.Объясните, как сохраняются объекты в файле: диалог для ввода имени файла, открытие файла, получение объекта из списка, запись в файл, закрытие файла. Почему в одном файле можно сохранять объекты разных типов?

9.Объясните, как загружаются объекты из файла: диалог для ввода имени файла, открытие файла, чтение из файла, создание объекта, добавление его в список TList, добавление

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

191

10.Объясните, как редактируется объект: инициируется диалог, сохраняются измененные поля в объекте, заменяется объект в списке TList, заменяется объект в списке TListBox. Как найти объект, который вы отметили в списке TListBox,

всписке TList?

11.Объясните, как отсортировать объекты в списке TList. Каким образом учитывается критерий сортировки? Как обновляются списки TListBox после сортировки?

12.Каким образом осуществляется проверка, все ли поля заполнены, при вводе данных в диалоге создания объекта? Что должна делать программа, если какое-либо поле не заполнено (пустое)?

13.Что должна делать программа перед завершением, если объекты были изменены?

192

13.МЕХАНИЗМЫ ДЕЙСТВИЙ И DRAG-AND-DROP

13.1.Механизм действий

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

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

Для реализации действий имеется компонент TActionList (вкладка Standard), а в класс TComponent добавлено свойство

Action:

property Action : TBasicAction; это объект-действие.

У объектов-действий (TBasicAction) есть имена, а также другие свойства, которые будут применены к связанным с объ- ектом-действием элементам управления, называемым клиентами действия (action clients). Это такие свойства, как заголовок (Caption), графическое представление (ImageIndex), состояние (Checked, Enabled, Visible), свойства обратной связи с пользо-

вателем (Hint, HelpContext).

Каждый объект-действие связан с одним или несколькими объектами-клиентами посредством объекта TActionList. Компонент TActionList содержит список имен действий и связанных с ними имен процедур, который эти действия реализует. Это обработчик события OnExecute.

Чтобы связать компонент с нужным действием, достаточно в раскрывающемся списке свойства Action этого компонента выбрать нужное название.

193

Таким образом, объекты TActionList осуществляют двунаправленную связь между объектом-клиентом и объектомдействием. Операция, произведенная над объектом-клиентом (например, щелчок мыши), перенаправляется объекту-действию, что порождает его событие OnExecute; обновление состояния объекта-действия отражается во всех связанных с ним элементах управления (клиентах действия).

Для определения действия на этапе проектирования следует:

1.Добавить в форму компонент TActionList.

2.Открыть редактор действий, выполнив двойной щелчок на компоненте TActionList.

3.Добавить в редактор объект-действие и установить для него нужные свойства.

4.Дважды щелкнуть на имени действия – автоматически добавляется обработчик для данного действия.

procedure TForm1.Action1Execute (Sender : TObject); begin

end;

5.Внутри блока begin end ввести код обработчика события.

6.Определить для элемента управления свойство Action, выбрав в инспекторе объектов из раскрывающегося списка значений свойства Action имя созданного объекта-действия.

13.2. Технология «Drag-and-Drop»

Концепция drag-and-drop позволяет перемещать объект в пределах формы и даже в другую прикладную программу. Обычно при этом используются следующие два элемента управления.

194

1.Источник. Содержит перемещаемый элемент. Это либо весь элемент управления (например, изображение), либо только его выбранная часть (например, выбранная в текущий момент строка компонента TListBox).

2.Приемник. Это элемент управления, на который будет опущен элемент-источник.

Следующие свойства полезны для программирования опе-

раций drag-and-drop.

property DragMode : TDragMode;

TDragMode = (dmManual, dmAutomatic);

Это свойство определяет, как Delphi обрабатывает начало операции перетаскивания. Если его значение dmAutomatic (события инициируются свойствами и методами компонента), элемент можно переместить в любое время. Если значение dmManual (все необходимые для обслуживания интерфейса события генерируются программой), нужно вручную начинать и заканчивать процесс перетаскивания.

Пример 1

procedure TForm1.ListBox1Click (Sender : TObject); begin

if ListBox1.SelCount >=2 then ListBox1.BeginDrag (false);

end;

В этом фрагменте кода свойству DragMode объекта ListBox1 типа TListBox присвоено значение dmManual, а свойству MultiSelect – True. Когда пользователь щелкает на элементе управления, обработчик события OnClick проверяет, было ли выбрано хотя бы два элемента из списка перед началом перетаскивания. Параметр, переданный методу BeginDrag, определяет, начинается ли перемещение немедленно (True) или ждет, пока указатель мыши переместится минимум на пять пикселей (False).

property DragCursor : TCursor;

195

Это свойство определяет форму указателя мыши, когда он перемещается над элементом управления, в который будет помещен перетаскиваемый объект.

Если компонент готов принять объект, он устанавливает в это свойство значение crDrag, в противном случае – значение crNoDrop. Установка этих свойств осуществляется автоматиче-

ски, если DragMode = dmAutomatic.

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

property Cursor : TCursor;

type TCursor = -32768..32767;

Операцию drag-and-drop можно выполнить с помощью следующих трех событий:

3. property OnDragOver : TDragOverEvent;

TDragOverEvent = procedure (Sender, Source : TObject; x,y : integer;State : TDragState; var Accept : 196oolean) of object;

TDragState = (dsDragEnter, dsDragLeave, dsDragMove);

Событие OnDragOver вызывается приемником, когда над ним перемещается объект.

Sender – компонент, который возбудил событие (обычно это Self – сам компонент-получатель, при ручном управлении это может быть не так);

Source – объект-источник;

x,y – текущие координаты указателя мыши. state – состояние указателя:

dsDragEnter – только что появился над компонентом; dsDragLeave – только что покинул компонент или была

отпущена кнопка мыши; dsDragMove – перемещается над компонентом.

Accept = true, если компонент готов принять элементисточник.

4. property OnDragDrop : TDragDropEvent; TDragDropEvent = procedure (Sender, Source : TObject; x,y

: integer) of object;

196

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

5. property OnEndDrag : TEndDragEvent;

TEndDragEvent = procedure (Sender, Target : TObject; x, y :

integer) of object;

Событие генерируется объектом-источником, когда операция drag-and-drop завершается.

Sender – источник;

Target – приемникили nil, еслиникто непринял «посылку»; x, y – координаты мышивмоментотпускания левой кнопки. Некоторые элементы управления определяют дополнительное событие OnStartDrag, генерируемое источником, когда

начинается выполнение операции drag-and-drop.

Пример 2

Разместим на форме Form1 различные компоненты, в том числе и метку TLable с именем lbOut.

Установим во всех компонентах в свойство DragMode

значение dmAutomatic.

Создадим обработчик события OnDragOver для метки: procedure TForm1.lbOutDragOver (Sender, Source : TObject;

x, y : integer; State : TDragState; var Accept : 197oolean); begin

Accept : = true;

lbOut.Caption : = (Source as TComponent).name;

end;

Теперь перетаскивание любого компонента на метку lbOut заставит ее показывать имя перетаскиваемого компонента.

Пример 3

Имеются два элемента управления типа TListBox: ListBox1 и ListBox2.

197

Установим свойство DragMode для ListBox1 равным dmAutomatic.

procedure TForm1.ListBox2DragOver (Sender, Source : TObject; x, y : integer; State : TDragState; var Accept : 198oolean);

begin

if Source = ListBox1 then Accept : = true

end;

Этот обработчик проверяет, является ли источником объект ListBox1, и, если является, устанавливает Accept = true.

Теперь, когда происходит сближение с объектом ListBox2, попытаемся сделать кое-что с опускаемым элементом.

Следующий обработчик просто добавляет выбранный (и перемещенный) элемент из ListBox1 в ListBox2:

procedure TForm1.ListBox2DragDrop (Sender, Source : TObject; x,y : integer);

begin

with Source as TListBox do ListBox2.Items.Add (Items [ItemIndex]);

end;

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

Начало перетаскивания происходит при вызове метода:

procedure BeginDrag (Immediate : 198oolean);

Программист должен связать вызов этого метода с ка- ким-либо событием в системе. Например, если свойство DragMode = dmAutomatic, BeginDrag вызывается функцией окна при нажатии левой кнопки мыши. Параметр Immediate определяет, когда именно возникает состояние drag-and-drop. Если True, – то немедленно, если False, – то после перемещения на пять пикселей. Последний вариант дает возможность использовать нажатие левой кнопки и для перетаскивания, и для регистрации щелчков на элементе управления. В режиме dmAutomatic такой возможности нет.

198

procedure DragDrop (Source : TObject; x, y: integer);

Вызывает обработчик события OnDragDrop.

procedure EndDrag (Drop : 199oolean);

Вызывает обработчик события OnEndDrag и в параметре Drop сообщает о том, был ли принят объект.

function Dragging : Boolean;

Возвращает True, если данный элемент в настоящий момент перетаскивается.

13.3. Обработка исключительных ситуаций

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

Обычно возникновение такой ситуации приводит к аварийному завершению программы. Однако в ряде языков программирования (PL-1, Ада, С++, Object Pascal) программисту предоставляется возможность написать подпрограмму – обработчик исключительной ситуации, которая автоматически вызывается при возникновении соответствующей исключительной ситуации. Эта подпрограмма может выполнять предусмотренные программистом действия и либо снова передать управление основной программе, либо нормальными средствами завершить выполнение последней.

Object Pascal реализует следующий механизм обработки исключительной ситуации.

В программе определяется так называемый контролируемый блок. Контролируемый блок – это либо блок try..except, либо блок try…finally. Если при выполнении операторов, помещенных внутри блока, возникает исключительная ситуация, то, во-первых, создается объект класса исключения и, во-вторых, этот объект и управление передаются за конец контролируемого

199

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

Обработчик исключения – это конструкция on класс_исключения do оператор;

или

on имя_объекта:класс_исключения do оператор;

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

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

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

raise вызов_конструктора_класса_исключения

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

Стандартные классы исключений

Стандартные классы исключений так же, как и абстрактный класс Exception (смотри выше), определены в модуле SysUtils. Ниже приведены некоторые из них.

EAbort – так называемая «тихая» обработка исключительной ситуации. Обработка ее происходит без какого-либо диагностического сообщения.

EAccessViolation – ошибка доступа к области памяти. EArrayError – ошибка при работе с массивом, например

неверный индекс.

EConvertError – ошибка преобразования в функциях

StrToInt или StrToFloat.

200