Обработка событий Delphi, создание собственного события
Я новичок в развитии Delphi. Мне нужно создать событие и передать некоторые свойства в качестве параметров. Может ли кто-нибудь поделиться демонстрационной программой, которая показывает, как это сделать с нуля. Я googled почти на каждом сайте, все они дали кусок кода, но мне нужна полноценная программа, которая проста и понятна.
Ответы
Ответ 1
Здесь короткое, но полное консольное приложение, в котором показано, как создать собственное событие в Delphi. Включает все: от объявления типа до вызова события. Прочтите комментарии в коде, чтобы понять, что происходит.
program Project23;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
// Declare an event type. It looks allot like a normal method declaration except
// it suffixed by "of object". That "of object" tells Delphi the variable of this
// type needs to be assigned a method of an object, not just any global function
// with the correct signature.
TMyEventTakingAStringParameter = procedure(const aStrParam:string) of object;
// A class that uses the actual event
TMyDummyLoggingClass = class
public
OnLogMsg: TMyEventTakingAStringParameter; // This will hold the "closure", a pointer to
// the method function itself + a pointer to the
// object instance it supposed to work on.
procedure LogMsg(const msg:string);
end;
// A class that provides the required string method to be used as a parameter
TMyClassImplementingTheStringMethod = class
public
procedure WriteLine(const Something:string); // Intentionally using different names for
// method and params; Names don't matter, only the
// signature matters.
end;
procedure TMyDummyLoggingClass.LogMsg(const msg: string);
begin
if Assigned(OnLogMsg) then // tests if the event is assigned
OnLogMsg(msg); // calls the event.
end;
procedure TMyClassImplementingTheStringMethod.WriteLine(const Something: string);
begin
// Simple implementation, writing the string to console
Writeln(Something);
end;
var Logging: TMyDummyLoggingClass; // This has the OnLogMsg variable
LoggingProvider: TMyClassImplementingTheStringMethod; // This provides the method we'll assign to OnLogMsg
begin
try
Logging := TMyDummyLoggingClass.Create;
try
// This does nothing, because there no OnLogMsg assigned.
Logging.LogMsg('Test 1');
LoggingProvider := TMyClassImplementingTheStringMethod.Create;
try
Logging.OnLogMsg := LoggingProvider.WriteLine; // Assign the event
try
// This will indirectly call LoggingProvider.WriteLine, because that what's
// assigned to Logging.OnLogMsg
Logging.LogMsg('Test 2');
finally Logging.OnLogMsg := nil; // Since the assigned event includes a pointer to both
// the method itself and to the instance of LoggingProvider,
// need to make sure the event doesn't out-live the LoggingProvider
end;
finally LoggingProvider.Free;
end;
finally Logging.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Ответ 2
Полный ответ на проект хорош. Но это альтернативный ответ, показывающий, как делать то, что вы хотите, в форме, которую вы уже имеете.
Перейдите в вашу форму и перейдите в раздел интерфейса, в области типов, вне определения класса формы и добавьте тип:
interface
type
TMyEvent = procedure(Sender:TObject;Param1,Param2,Param3:Integer) of object;
TMyForm = class(TForm)
....
Традиционно, но не требуется, чтобы первым элементом в вашем событии был объект, отправляющий его, но для использования базового класса TObject вместо существующего типа типа формы.
Другие параметры, указанные выше, не требуются вообще, но показывают, как вы объявите свои собственные дополнительные данные. если они вам не нужны, просто используйте Sender: TObject.
И в этом случае вам вообще не нужно определять TMyEvent, просто используйте тип TNotifyEvent.
Теперь объявите поле, которое использует этот тип, в вашей форме:
TMyForm = class(TForm)
private
FMyEvent : TMyEvent;
...
Теперь объявите свойство, которое обращается к этому полю, в разделе свойств формы:
// this goes inside the class definition just before the final closing end
property MyEvent:TMyEvent read FMyEvent write FMyEvent
Теперь перейдите к тому месту, где вы хотите, чтобы это событие загорелось (вызывается, если оно установлено) и пишите это:
// this goes inside a procedure or function, where you need to "fire" the event.
procedure TMyForm.DoSomething;
begin
...
if Assigned(FMyEvent) then FMyEvent(Self,Param1,Param2,Param3);
end;
Ответ 3
Вы используете обработчик событий, чтобы реагировать, когда что-то происходит (например, AfterCreation и перед закрытием).
Чтобы использовать события для своего собственного класса, вам необходимо определить тип события. Измените тип и количество необходимых параметров.
type
TMyProcEvent = procedure(const AIdent: string; const AValue: Integer) of object;
TMyFuncEvent = function(const ANumber: Integer): Integer of object;
В классе вы можете добавить DoEvent (переименование для правильного события). Так вы можете вызвать DoEvent внутри. DoEvent обрабатывает возможность того, что событие не назначено.
type
TMyClass = class
private
FMyProcEvent : TMyProcEvent;
FMyFuncEvent : TMyFuncEvent;
protected
procedure DoMyProcEvent(const AIdent: string; const AValue: Integer);
function DoMyFuncEvent(const ANumber: Integer): Integer;
public
property MyProcEvent: TMyProcEvent read FMyProcEvent write FMyProcEvent;
property MyFuncEvent: TMyFuncEvent read FMyFuncEvent write FMyFuncEvent;
end;
procedure TMyClass.DoMyProcEvent(const AIdent: string; const AValue: Integer);
begin
if Assigned(FMyProcEvent) then
FMyProcEvent(AIdent, AValue);
// Possibly add more general or default code.
end;
function TMyClass.DoMyFuncEvent(const ANumber: Integer): Integer;
begin
if Assigned(FMyFuncEvent) then
Result := FMyFuncEvent(ANumber)
else
Result := cNotAssignedValue;
end;
Ответ 4
в контексте размещения "событий" в DLL я описал концепцию, использующую интерфейсы, шаг за шагом... возможно, это помогает по-другому: Использование прослушивателей событий в не-gui-среда (DLL) (Delphi)
Ответ 5
- type= в основном указатель процедуры или функции (заданная сигнатура)
- поле= переменная типа процедуры или указателя функции (заданная сигнатура)
- Свойство просто выставляет поле так же, как в случае обычных переменных/полей.
В любом месте вашего пользовательского кода компонента вы просто выполняете объект процедуры/функции, предоставляя то, что ему нужно, - это вызывает событие, чтобы ваш обработчик событий был активным.
Особенность такой процедуры или функциональных объектов заключается в том, что ОНИ ПРИЗЫВАЮТСЯ, ГДЕ ВЫ ПРИНИМАЕТЕ ИХ ВНУТРИ ТАМОЖЕННОГО КОМПОНЕНТНОГО КОДА, НО ПРОЗРАЧНО ВНЕ КОМПОНЕНТА СЛИШКОМ (ЧЕРЕЗ ОПУБЛИКОВАННЫЙ ОБЪЕКТ). ТАК ЧТО ПОЛЬЗОВАТЕЛЬ/ПРИЛОЖЕНИЕ УКАЗАЛ, КАК ПРОЦЕДУРА ИЛИ ФУНКЦИЯ ВЫПОЛНЯЕТСЯ В ТАМОЖЕННОМ КОМПОНЕНТЕ, КОГДА ВЫБИРАЕТСЯ.