Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.06.2011, 10:25   #1
VadEr
Форумчанин
 
Аватар для VadEr
 
Регистрация: 24.03.2009
Сообщений: 375
По умолчанию События Delphi

Приветствую Вас господа программисты!

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

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TClsMsg = class
  private
    FOnLog: TNotifyEvent; // тут мы храним адрсс процедуры
    procedure SetOnLog(const Value: TNotifyEvent);
  public
    data: String;
  published
    property OnLog :TNotifyEvent read FOnLog write SetOnLog;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    l : TClsMsg;
  public
    { Public declarations }
    procedure OnLog(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TClsMsg }

procedure TClsMsg.SetOnLog(const Value: TNotifyEvent);
begin
  FOnLog := Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  l.data := IntToStr(Random(10));
  if Assigned(l.FOnLog) then l.FOnLog(l); // вызываем процедуру
end;

procedure TForm1.OnLog(Sender: TObject);
begin
  Memo1.Lines.Add(TClsMsg(Sender).data);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  randomize;
  l := TClsMsg.Create;
  l.OnLog := OnLog; // сохраняем адресс в поле, через свойство
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  l.Free;
end;

end.
Посмотрел на это чудо тип TNotifyEvent объявляется он как процедура:
TNotifyEvent = procedure(Sender: TObject) of object;
- тут не понятен постфикс "of object;"?


Хотя в хелпе указано, что это на подобие OnClick у кнопки.
В данном случае ни какой асинхронности не будет? Т.е. когда мы жмем кнопку мы отправим сообщение и программа сразу получает управление без входа в этот OnClick. И только тогда, когда форма получит наше сообщение управление перейдет в OnClick.
А при вызове нашего события if Assigned(l.FOnLog) then l.FOnLog(l); управление передастся сразу процедурке и пока она не отработает, ничего не сделаешь?

Последний раз редактировалось VadEr; 28.06.2011 в 10:52.
VadEr вне форума Ответить с цитированием
Старый 28.06.2011, 10:41   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Не совсем понятен становится смысл данного усложнения логики.
Твоя программа (виндовая) обрабатывает некие сообщения ей от ОС. Сообщения считываются в бесконечном цикле. Оконная процедура имеет операторы условий, которые вызывают некие действия.
События - это индивидуальное определение этих действий. Смысл событий в том, чтоб дать возможность программисту связать некий код с срабатыванием некого условия. Т.Е. не полагаться на стандартные обработчики, которые кстати далеко не всегда доступны программисту, а переопределить их под свое.
Если ты написал некой компонент, он в цикле вращает некой массив. Задача - выполнить некое действие если элемент массива ниже нуля.
Ты можешь описать процедуру, которую ты в это условие вставишь (имею ввиду вызов), но представь что ты этот компонент будешь распространять, платно причем. Ты врядли поделишься исходниками, а я как пользователь скажу - "А мне нужно чтоб при этом условии делалось то что я хочу - лампочка должна включаться". Поскольку ты в своем компоненте не предусмотрел для меня дать возможность описать свое действие, я плюну на компонент и потребую деньгу назад.
Если же ты описал в компоненте событие, которое в цикле (внутри компонента, в недоступном для меня месте) будет вызываться, я вполне смогу описать свое тело обработчика и останусь доволен решенной задачей.

Понял в чем смысл событий? Дать возможность описать действие для класса вне его пределов.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 28.06.2011, 11:40   #3
VadEr
Форумчанин
 
Аватар для VadEr
 
Регистрация: 24.03.2009
Сообщений: 375
По умолчанию

Уважаемый Stilet это как раз я и хотел бы узнать: if Assigned(l.FOnLog) then l.FOnLog(l) это моя оконная процедура будет задействована?, т.е. адресс обработчика в WinProg передастся?

В бесконечном цикле будет создана отдельная ветка на обработчик FOnLog(l))?:con fused:

Последний раз редактировалось VadEr; 28.06.2011 в 11:58.
VadEr вне форума Ответить с цитированием
Старый 28.06.2011, 11:46   #4
VadEr
Форумчанин
 
Аватар для VadEr
 
Регистрация: 24.03.2009
Сообщений: 375
По умолчанию

вот попробовал по другому, тут точно будет событийная модель с обработкой сообщений
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  M_TestMsg = WM_USER + 100;

type
  TClsMsg = class
  public
    data: String;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    l : TClsMsg;
  public
    { Public declarations }
    procedure OnLog(var Msg: TMessage); message M_TestMsg;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TClsMsg }

procedure TForm1.Button1Click(Sender: TObject);
begin
  l.data := IntToStr(Random(10));
   //Это одно и тоже или как?
  //Perform(M_TestMsg, 0, LPARAM(l));           //???
  SendMessage(Handle, M_TestMsg, 0, LPARAM(l))  //???
end;

procedure TForm1.OnLog(var Msg: TMessage);
begin
  Memo1.Lines.Add(TClsMsg(Msg.LParam).data);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
  l := TClsMsg.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  l.Free;
end;

end.
тут тоже возникли непонятки с Perform, судя по всему он вызывает WindowProc:
Код:
function TControl.Perform(Msg: Cardinal; WParam, LParam: Longint): Longint;
var
  Message: TMessage;
begin
  Message.Msg := Msg;
  Message.WParam := WParam;
  Message.LParam := LParam;
  Message.Result := 0;
  if Self <> nil then WindowProc(Message);
  Result := Message.Result;
end;
который содержит какую то процедуру TWndMethod = procedure(var Message: TMessage) of object; видимо ту самую окна?


В целом бы хотелось бы уяснить: эти реализации суть одно и тоже или все таки разные?

Последний раз редактировалось VadEr; 28.06.2011 в 11:52.
VadEr вне форума Ответить с цитированием
Старый 28.06.2011, 11:48   #5
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
речь идет всего лишь о сохранении адреса процедуры в поле объекта
Не совсем так.
На самом деле для полей объекта для хранения данных типа procedure|function(..) of object компилятор резервирует область памяти, описываемую структурой TMethod:

TMethod = record
Code, // это поле хранит собственно точку входа в код подпрограммы, ассоциированной с методом некоего объекта или класса
Data: Pointer; // а это поле предназначено для хранения ссылки на конкретный объект или класс; при вызове подпрограммы по адресу из поля Code компилятор запишет этот указательв РОН ebx и доступ к нему в теле вызванной подпрограммы будет возможен через явное или неявное обращение к
Код:
Self
end;

Цитата:
не понятен постфикс "of object;"
Этот постфикс предписывает компилятору трактовать объявленный тип как тип, описывающий процедурный или функциональный метод объекта, а не как тип, описывающий регулярную процедуру или функцию.
mss вне форума Ответить с цитированием
Старый 28.06.2011, 11:51   #6
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
видимо ту самую окна?
Оконная ф-ция - это регулярная функция.
Не следует путать ее с методом дельфийского класса или объекта.
mss вне форума Ответить с цитированием
Старый 28.06.2011, 13:04   #7
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,527
По умолчанию

Исправленная схема работы для поста #1
Код:
type
  TClsMsg = class
  private
    FOnLog: TNotifyEvent; // тут мы храним адрсс процедуры
ЧТОБЫ использовать его внутри процедур(методов данного класса)
    procedure SetOnLog(const Value: TNotifyEvent);
    procedure SetData(const Value: string);
  private
    Fdata: String;
public
   property data: string read Fdata write SetData;
    property OnLog :TNotifyEvent read FOnLog write SetOnLog;
  end;

 TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    l : TClsMsg;
  public
    { Public declarations }
  private 
    procedure OnLog(Sender: TObject);
  end;


//процедура внесения изменений в объект
procedure TclsMsg.setData(const value: string);
begin
// изменяем данные
   Fdata:=value;
// извещаем об этом с указанием для какого объекта(self) это произошло
   if assigned(FonLog) then Fonlog(self);
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  l.data := IntToStr(Random(10));
//  if Assigned(l.FOnLog) then l.FOnLog(l); // вызываем процедуру
мы не вызываем ее непосредственно
а получаем извещение(событие) при заполнении 
end;

//данная процедура вызывается из объекта l
procedure TForm1.OnLog(Sender: TObject);
begin
  Memo1.Lines.Add(TClsMsg(Sender).data);
end;
программа — запись алгоритма на языке понятном транслятору
evg_m вне форума Ответить с цитированием
Старый 28.06.2011, 14:20   #8
VadEr
Форумчанин
 
Аватар для VadEr
 
Регистрация: 24.03.2009
Сообщений: 375
По умолчанию

Цитата:
Сообщение от evg_m Посмотреть сообщение
мы не вызываем ее непосредственно
а получаем извещение(событие) при заполнении
здорово конечно я решил глубже оптимизировать:
Код:
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TClsMsg = class
  private
    Fdata: String;
    FOnLog: TNotifyEvent;
    procedure SetData(const Value: string);
  public
    constructor Create(OnLog: TNotifyEvent);
    property data: string read Fdata write SetData;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    l : TClsMsg;
    procedure OnLog(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
  l := TClsMsg.Create(OnLog);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  l.Free;
end;

{ TClsMsg }

constructor TClsMsg.Create(OnLog: TNotifyEvent);
begin
  FOnLog := OnLog;
end;

procedure TClsMsg.SetData(const Value: string);
begin
   Fdata:=value;
   if assigned(FonLog) then Fonlog(self);
end;

procedure TForm1.OnLog(Sender: TObject);
begin
  Memo1.Lines.Add(TClsMsg(Sender).data); //  тут почуму-то я могу обращаться к  сокрытому полю TClsMsg(Sender).Fdata ?
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  l.data := IntToStr(Random(10));
end;

end.

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

Последний раз редактировалось VadEr; 28.06.2011 в 14:50.
VadEr вне форума Ответить с цитированием
Старый 28.06.2011, 16:20   #9
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,527
По умолчанию

вызов процедуры Fon.... это
Цитата:
все таки мы передаем управление
ПРИ наличии if assigned(Fon..) таковой.

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

Последний раз редактировалось evg_m; 28.06.2011 в 16:22.
evg_m вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
События в edit (Delphi) Евгений1 Помощь студентам 8 08.03.2011 21:34
События в idTCPServer и idTCPClient (Delphi) _PROGRAMM_ Помощь студентам 3 11.11.2010 19:35
События в WPF. Обращение к компонентам формы из события Casper-SC Общие вопросы .NET 3 25.07.2010 19:03
Delphi события кнопки Alexmur07 Помощь студентам 3 29.11.2009 11:16
События мыши в Delphi -COREY- Помощь студентам 0 15.11.2009 15:27