Вопрос по классам, обработчикам событий...

Vadik(R)

Well-Known Member
12.12.2007
469
0
25
Волгоград
#1
Начал изучать классы в C++, столкнулся с понятиями слота и сигнала. Прочитал про connect, SIGNAL и SLOT, и стало интересно, как было все реализовано в Delphi, где я раньше кодил и уютнее себя чувствал :welcome:
Первый пример, который я решил разобрать - это событие Button1.OnClick.
Я так понимаю, в Delphi C-подобный код создается автоматически:
Код:
connect(Button1, SIGNAL(OnClick()), Form1, SLOT(Button1Click(TObject)))
Просто этот код Delphi пишет автоматически и мы его не видем. Далее, почитав, что при вызове connect SLOT может принимать параметры только из SIGNAL'а, я решил, что connect Delphi пишет так:
Код:
connect(Button1, SIGNAL(OnClick(TObject)), Form1, SLOT(Button1Click(TObject)))
Вот. Далее, я решил поэксперементировать, а какого черта Button1Click должен принимать параметр TObject? Ведь, он может принимать не все параметры из SIGNAL'а. Решил написать код:
Код:
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click;
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click;
begin
ShowMessage('1');
end;

end.
На что получил ругательство Delphi (The Button1Click method referenced by Button1.OnClick has an incompatible parameter list. Remove the reference? - No), но тем не менее программу он всё равно скомпилировал и запустил. Далее, я рассуждал так. На лишние параметры в SLOT'е Delphi ругается - правильно делает. А на их недостаток - тоже. Странно. И я решил, что Delphi в обработчик события всегда будет передавать Sender'а, вызвавшего это событие, например, чтобы выполнять разный код при различных Sender'ах, или не выполнять ничего при определённых Sender'ах.
Тогда я решил создать свой класс, сделать событие, и привязать обработчик к этому событию. Если бы он ругался бы на обработчик без параметров, а на обработчик с параметром TObject - нет, тогда всё ясно, Delphi всегда передает в обработчик Sender'а, независимо ни от чего другого. То есть, даже если SIGNAL будет без параметров. Однако, я такое только попытался сделать, и тут же возникли проблемы. Вот код, при нажатии на кнопку вылетает AccessViolation, из-за чего он возникает и как его исправить - я не знаю. Код:
Код:
unit Unit1;

interface

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

type
TMyObj = class(TObject) //Свой класс
summ: integer;
procedure sum(a, b: integer);
end;
TForm1 = class(TForm)
Button1: TButton;
MyObj: TMyObj;
procedure sumsum(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

/* Какое-то событие, которое в будущем хочу использовать как сигнал. Знаю, что оно
не должно иметь тела кода, но тем не менее, оно даже сейчас пока не работает. :( */
procedure TMyObj.sum(a, b: integer);
begin
summ := a + b;
end;

/* Обработчик будущего события. Чтобы убедиться, что Sender передается всегда, независимо от параметров
функции-сигнала. */
procedure TForm1.sumsum(Sender: TObject);
begin
ShowMessage(IntToStr((Sender as TMyObj).summ));
end;

/* Нажатием на кнопку изначально хотел породить сигнал, но потом пришёл к еще одной проблеме -
ошибка AccessViolation, хотя не понимаю, откуда она возникает, вроде же все правильно?
Если написать Button1 и какое-то свойство/метод - всё работает, а если MyObj - то никак.
Думал, проблема в том, что прежде надо создать объект, но видимо, тоже не в этом дело. :( */
procedure TForm1.Button1Click(Sender: TObject);
begin
//Пробовал разные варианты - все равно возникает ошибка :(
//Form1.MyObj.Create;
//Form1.MyObj.sum(1, 3);
Form1.MyObj.summ := 1;
//Form1.MyObj.Free;
end;

end.
. Собственно, объясните, пожалуста, из-за чего возникает ошибка и как её исправить? А заодно может и найдёте ошибки в моих рассуждениях и избавите от кучи работы, которую я, возможно, делаю впустую.
P.S. Классы начал изучать в C++, потому что в универе мы их проходим. А почему вспомнил про Delphi? Потому что за ним сижу уже 4 года, а за C++ - только полгода, поэтому и интересуюсь, как это устроено в Delphi.

Ааа, может надо писать:
Код:
Form1.MyObj := TMyObj.Create;
?? Тогда, объясните, почему такой вариант не работает:
Код:
Form1.MyObj.Create;
, и чем они различаются?
 

Vadik(R)

Well-Known Member
12.12.2007
469
0
25
Волгоград
#2
На другом форуме подсказали, что я не могу назначить обработчик события с другим прототипом, потому что спецификация обработчика такая, и ничего с этим поделать нельзя. Не получится присвоить на OnClick обработчик, описанный отличнительно от типа TNotifyEvent.
Да, жаль в Delphi нет некоторых возможностей C.
 
E

etc

Гость
#3
А что не понятно то?
1 конструктор это грубо говоря class function
2 с событиями, вы просто почитайте как они устроены тут