Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

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



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

property Align; property OnMouseDown;

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

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

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

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

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

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

property BtCaption:string read GetBtCaption write SetBtCaption;

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

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

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

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

type

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

Далее определяем переменную этого типа в секции private:

FOnFilter:TFilterEvent;

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

Открыть в отдельном окне Копировать Печать?

property OnFilter:TFilterEvent read FOnFilter write FOnFilter;

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

1. procedure TListAdd.BtClick(Sender:TObject);

2. var

3. CanAdd:boolean;

4. begin

5. if length(FEdit.Text)>0 then begin

6. CanAdd:=True;

7. if Assigned(FOnFilter) then FOnFilter(Self,FEdit.Text,CanAdd);

8. if CanAdd then begin

9. FListBox.Items.Add(FEdit.Text);

10. FEdit.Text:='';

11. FEdit.SetFocus;

12. end else beep;

13. end;

14. end;

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

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

1. procedure TForm1.ListAdd1Filter(Sender: TObject; const EditText: String;

2. var CanAdd: Boolean);

3. var

4. I,N:integer;

5. begin

6. Val(EditText,N,I);

7. CanAdd:=I=0;

8. end;

9.

10. procedure TForm1.ListAdd2Filter(Sender: TObject; const EditText: String;

11. var CanAdd: Boolean);

12. begin

13. CanAdd:=False;

14. if length(EditText)>0 then CanAdd:=(EditText[1]>='A') and (EditText[1]<='Z');

15. end;

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





Дата публикования: 2015-02-18; Прочитано: 283 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.008 с)...