Страница 1 из 1
Переопределение событий
Добавлено: 12.02.2011 03:04:57
Dem
Доброго времени суток, Камрады!
Нужна Ваша помощь.
И вот, по какому вопросу:
Код: Выделить всё
mbutton = class(tbutton)
private
public
constructor create(aowner:tcomponent); overload;
destructor destroy; override;
procedure onclick(sender:tobject); override;
end;
Вот-этого события (onclick) в базовом классе не определено. Т.е. при сборке собс-но и сообщает, что: "not found in base class"...
Как повесить свое событие?
P.S. Прошу сильно не пинать - с таким вопросом столкнулся впервые. Ранее не было необходимости.
P.P.S. Вопрос, конечно, не в кнопке, но интересен сам механизм...
Заранее спасибо

Re: Переопределение событий
Добавлено: 12.02.2011 03:12:42
Иван Шихалев
А какова цель всего этого?
И что подразумевается под:
constructor create(aowner:tcomponent); overload;
?
Добавлено спустя 1 минуту 40 секунд:Да, еще — вышеприведенный кусок кода не должен выдавать "not found in base class" на onclick...
Re: Переопределение событий
Добавлено: 12.02.2011 03:30:35
Dem
А какова цель всего этого?
Целей несколько (вернее - в нескольких классах).
Более-предметно:
(обертка для локального прокси)
Код: Выделить всё
TLproxy =class(TIDMappedPortTCP)
private
_defaultPort:integer;
public
constructor create(Aowner:Tcomponent; proxy:string; _defaultPort:string); overload;
destructor destroy; override;
function getDefaultPort:integer;
//property onConnect;
{ошибка тут} procedure onConnect; override;
end;
{...}
constructor TLproxy.create(Aowner:Tcomponent; proxy:string; _defaultPort:string);
begin
inherited create(aowner);
MappedHost:=copy(proxy,1,length(proxy)-(length(proxy)-pos(':',proxy))-1);
MappedPort:=strtoint(trim(copy(proxy,pos(':',proxy)+1,length(proxy)-pos(':',proxy))));
DefaultPort:=_defaultPort;
Active:=true;
end;
{...}
procedure TLproxy.onConnect(acontext: TidContext);
begin
//inherited;
if acontext.Connection.Socket.Binding.PeerIP<>'127.0.0.1'
then acontext.Connection.Disconnect;
end;
Про кнопку для простоты спросил, поскольку думаю, что механизм одинаков...
Добавлено спустя 4 минуты:Да, еще — вышеприведенный кусок кода не должен выдавать "not found in base class" на onclick...
Поправил код.
Re: Переопределение событий
Добавлено: 12.02.2011 09:24:46
Maxizar
Если я вас правильно понял, вам нужно в вашем классе создать событие, которое будет видно в инспекторе объектов, скажем как OnClick для кнопки. И иметь возможность перекрывать его, то делать нужно так:
Событие –это функция или процедура объявленная с дополнительным идентификатором или как там его называют
of object;.
Пример:
Допустим, ваш обработчик OnRun1 имеет один параметр типа Integer, и OnRun2 имеет один параметр типа Integer и возвращает результат типа Boolean.
То необходимо объявить два типа данных событий:
Код: Выделить всё
type
TRun1 = procedure(I: Integer) of object;
TRun2 = function(I: Integer):Boolean of object;
Теперь объявите ваш класс:
Код: Выделить всё
type
TSomeClass = class()
private
FOnRun1: TRun1;
FOnRun2: TRun2;
Protected
procedure DoRun1 (I: Integer); override;
function DoRun2 (I: Integer):Boolean; override;
public
property OnOnRun1: TOnRun1 read FOnOnRun1
write FOnOnRun1;
property OnOnRun2: TOnRun2 read FOnOnRun2
write FOnOnRun2;
end;
Метод DoRun1:Код: Выделить всё
procedure TSomeClass.DoRun1 (I: Integer);
begin
if Assigned(FOnRun1) then
FOnRun1(I);
end;
Метод DoRun2:Код: Выделить всё
procedure TSomeClass.DoRun2 (I: Integer) : Boolean;
begin
if Assigned(FOnRun2) then
Result := FOnRun2(I);
end;
Не забываем о области видимости процедур
DoRun1 и
DoRun2, в большинстве случаев это protected.
Если их нужно будет перекрывать то не забываем про
override;
Скажем нужно будет перекрыть в наследнике делаем так:
Код: Выделить всё
type
TSomeClass2 = class(TSomeClass)
Protected
FI:Integer;
procedure DoRun1 (I: Integer); override;
end;
Метод DoRun1:Код: Выделить всё
procedure TSomeClass2.DoRun1 (I: Integer);
begin
inherited DoRun1(I); //Вызываем метод родителя
//далее делаем дополнительные операции
FI:=FI+I;
end;
необходимо помнить о том как нужно вызывать метод родителя до или после нужных нам операций, зависит от действий и сложности событий
Писал в блокноте, так что возможны опечатки..
Дополнительные источники:
1-
Как создать свое событие для своего класса2 -
Делегирование события
Re: Переопределение событий
Добавлено: 12.02.2011 12:03:16
Odyssey
Dem писал(а):Вот-этого события (onclick) в базовом классе не определено. Т.е. при сборке собс-но и сообщает, что: "not found in base class"...
Как повесить свое событие?
Если под этим имелось в виду "как выполнить мой код при щелчке на моей кнопке", то
В конце кода лучше вызвать inherited Click;, чтобы выполнить ещё и обработчик родительского компонента.
Строго говоря, это не мы не вешали событие, а перекрывали метод, который вызывается при щелчке мышью по компоненту.
Можно, конечно, "повесить событие" в буквальном смысле: завести в классе mbutton
а в конструктор добавить
Но у этого способа есть огромный недостаток: если тот, кто будет пользоваться классом mbutton переназначит событие OnClick в своём коде, то MyBtnClick больше не будет вызываться. Поэтому правило обычно таково: если мы пишем свой класс, то перекрываем (override) родительские методы, а если используем уже написанный класс, то вешаем события.
P.S.
Maxizar писал(а):Если я вас правильно понял, ...
Odyssey писал(а):Если под этим имелось в виду ...
Вот чем мне нравится этот форум. А на некоторых они постоянно в отпуске

Re: Переопределение событий
Добавлено: 12.02.2011 18:15:53
hinst
короче

OnClick - это свойство класса, а не метод, поэтому его нельзя перекрыть

перекрыть надо Click, как уже правильно сказали

inherited не забывайте.

и не путаете ли вы override <перекрыть> и overload <перегрузить>
Re: Переопределение событий
Добавлено: 15.02.2011 01:44:32
Dem
Всем спасибо - информация была полезной/любопытной... отчасти - известной...
Спрошу более-конкретно:
Базовый класс (предок)
Код: Выделить всё
TWebBrowser = class(TOleControl)
{...}
private
FOnBeforeNavigate2: TWebBrowserBeforeNavigate2;
{...}
published
property OnBeforeNavigate2: TWebBrowserBeforeNavigate2 read FOnBeforeNavigate2 write FOnBeforeNavigate2;
{...}
end;
В предке нет процедур
BrowserBeforeNavigate2,
TWebBrowserBeforeNavigate2,
BeforeNavigate и т.п.
Как мне получить доступ к событию "OnBeforeNavigate2"? (перекрыть)
Odyssey писал(а):Но у этого способа есть огромный недостаток: если тот, кто будет пользоваться классом mbutton переназначит событие OnClick в своём коде, то MyBtnClick больше не будет вызываться. Поэтому правило обычно таково: если мы пишем свой класс, то перекрываем (override) родительские методы, а если используем уже написанный класс, то вешаем события.
Как повесить событие - это понятно. А как его перекрыть?
P.S. - с простотой вопроса обманул сам-себя...
P.S.2. - все классы пишутся в редакторе и создаются исключительно в Runtime, и какие из их свойств попадают в визуальный редактор - не имею ни малейшего понятия...
Re: Переопределение событий
Добавлено: 15.02.2011 07:21:10
daesher
Это сложнее (впрочем, можно говорить не просто о событиях, а вообще о свойствах, которыми формально события и являются). Можно:
1. Изменить видимость свойства (прописать его в Public, Private или Protected)
2. Создать такое же свойство с тем же именем. Старое никуда не денется, и при использовании потомка через переменную предка пойдёт обращение к старому свойству.
3. Смириться с тем свойством, которое уже есть, и использовать его (благо, в нём уже есть всё, что надо).
4. Пропатчить код для предка, повесив свойство не на поле, к тому же приватное, а на методы Set... и Get... (пусть они меняют только это поле), которые должны быть виртуальными и видимыми не менее чем protected, а потом перекрывать именно их.
Возможно, Вы хотели изменить тип свойства - тогда остаётся только вариант создания свойства с таким же именем.
Возможно, Вы хотели повесить на это событие что-то дополнительное (т.е., чтобы в потомке делалось что-то ещё, когда оно вызывалось) - это - более сложная задача; необходимо выяснить, когда предок создаёт событие, и попробовать "влезть" туда; или же, опять же, намудрить с Set... и Get... (можно просто с Get...), сохраняя метод, который вешают на событие, и подсовывая вместо него свой метод, который сделает то, что надо, а потом вызовет обычный повешенный на событие метод. Но, опять же, для этого варианта нужно патчить код предка.