Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вызов функции из функции [D7, XP]


Страницы:   1 2 3

Сергей ©   (2011-01-14 22:08:00) 

Вызов функции из функции

Код такой:

type
 TGetMy = procedure() of object;

function MyFunc1(OnGetMy : TGetMy = nil): Boolean;

 procedure EvOnChange(Self, Sender: TObject);
 begin
   if Assigned(OnGetMy) then OnGetMy(); // Âòîðîé âûçîâ.
 end;

var
 Form : TForm;
 EvChange : TMethod;
begin
 if Assigned(OnGetMy) then OnGetMy(); // Ïåðâûé âûçîâ.
 Form := TForm.Create(Application);
 with Form do begin
   with TEdit.Create(Form) do begin
     Parent := Form;
     EvChange.Code := @EvOnChange;
     OnChange := TNotifyEvent(EvChange);
   end;
   // ...
 end;
end;


Проблема в том, что первый вызов OnGetMy проходит, а второй из функции EvOnChange вызывает ошибку Дельфи. Вопрос, как сделать вызов правильно, чтобы ошибки не возникало?


DiamondShark   (2011-01-17 01:51:00) [21]


> sniknik ©   (17.01.11 01:37) [35]

Вообще-то, если решать задачу замены метода на регулярную процедуру, то логично было бы терять/игнорировать именно Self, а не явные параметры.

Но, поскольку Self первый, то "красиво" потерять его не получится. Остаётся только описать и проигнорировать.
Ну и для чистоты концепции неплохо бы передавать в Self именно nil, а не бессмысленную ссылку на объект, Self-ом не являющийся.


sniknik   (2011-01-17 01:37:00) [22]

> То он будет показывать "TEdit" для обоих компонентов, тогда как, по всей видимости Sender'ом
> у второго компонента должно быть TMemo. Засим, код из [22] видимо очень неправильный :).
вообще то он не правильный вовсе не поэтому. а потому, что у метода обычно 2 параметра, и описывать регулярку под метод стоило бы не так
procedure Proc(Sender: TObject);
а так
procedure Proc(Self, Sender: TObject);
и все. ничего более.
что "сдвигает" параметр, а не меняет их местами из-за имени. т.е. ну, чтобы вам было привычнее напишите так
procedure Proc(Self: TObject);
а, второй там просто не используется, и возможности его вызвать с ним тоже нет (без извращений с приведением типа). т.е. ошибок из-за этого тоже не будет.

т.что то, что ты инкриминируешь "у второго компонента должно быть TMemo" неверно, не должен, а есть и будет именно TMemo, но только "за кадром" во втором не присутствующем, а в Self передается из Data куда мы/ты его сам поместил. т.е. ССЗБ в этом случае.

ты что думаешь, ты тут воздухом дышишь?© Морфей из матрицы.
вы как начинающий Нео, привязываетесь к именам... а они не существенны. компьютеру на них начхать, они только для нас.


DiamondShark   (2011-01-17 01:26:00) [23]


> Он будет показывать ровно то, что должен показывать.

Может ты расскажешь, что он должен показывать? Ну, т.е. как ты задачу понял?


Ega23   (2011-01-17 01:10:00) [24]


> То он будет показывать "TEdit" для обоих компонентов, тогда
> как, по всей видимости Sender'ом у второго компонента должно
> быть TMemo.

Он будет показывать ровно то, что должен показывать. Задачи, чтобы это был полноценный TNotifyEvent не было.
Не далее как в четверг как раз такую штуку реализовывал. Но с процедурой мне не понравилось, сделал тупо

TDummyClass = class (TObject)  
public
 class procedure Proc(Sender: TObject);
end;


Servy   (2011-01-17 00:40:00) [25]

По-моему, DiamondShark вполне резонно отмечает, что если код из [22] дополнить например таким образом:


procedure Proc(Sender: TObject);
begin
ShowMessage(Sender.ClassName)
end;

var
M: TMethod;

procedure TForm1.FormCreate(Sender: TObject);
var
 Edit: TEdit;
 Memo: TMemo;
 Button: TButton;
begin
 Edit := TEdit.Create(Self);
 Edit.Parent := Self;
 M.Code := @Proc;
 M.Data := Edit;
 Edit.OnChange := TNotifyEvent(M);

 Memo := TMemo.Create(Self);
 Memo.Parent := Self;
 Memo.Top := 30;
 Memo.OnChange := TNotifyEvent(M);
end;


То он будет показывать "TEdit" для обоих компонентов, тогда как, по всей видимости Sender'ом у второго компонента должно быть TMemo. Засим, код из [22] видимо очень неправильный :).

Единственный вопрос в том, специально ли Юрий Зотов поставил вместо Self - Sender и опустил второй параметр, или это была трагическая случайность, сделавшая код из [22] еще неправильнее, чем планировалось им изначально.


DiamondShark   (2011-01-17 00:30:00) [26]


> Ega23 ©   (17.01.11 00:18) [30]

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


Ega23   (2011-01-17 00:18:00) [27]


> У этой сигнатуры два параметра: неявный Self и явный Sender.

M.Code := @Proc;
M.Data := Edit;


З.Ы. ЛМД.


DiamondShark   (2011-01-16 20:51:00) [28]


> Ega23 ©   (16.01.11 20:31) [28]
> Сфигали она некорректная?

С того, что type TNotifyEvent = procedure (Sender: TObject) of object
У этой сигнатуры два параметра: неявный Self и явный Sender.

З.Ы. У тебя перманентный ФГМ.


Ega23   (2011-01-16 20:31:00) [29]


> из каких побуждений вы использовали некорректную сигнатуру
> процедуры?

Сфигали она некорректная?
З.Ы. У тебя точно перманентный ПМС.


DiamondShark   (2011-01-16 20:15:00) [30]


> Юрий Зотов ©   (16.01.11 20:08) [26]

Да в пень мне тот исходник, экзешник и скриншот.

Вы лучше объясните, из каких побуждений вы использовали некорректную сигнатуру процедуры?
Хотели отучить ТС от копипасты (еретической мысли, что забыли про селф, я разумеется, не допускаю)?


Юрий Зотов   (2011-01-16 20:08:00) [31]


> DiamondShark ©   (16.01.11 19:04) [23]

О, великий Гуру, вот здесь:
http://webfile.ru/5056135
Вы найдете исходник, экзешник и скриншот.

Конечно, можно было обойтись только одним исходником, но он у Вас уже и так есть (см. выше) - и раз Вы не смогли его откомпилировать и запустить, значит, у Вас с этим какие-то проблемы. Поэтому пришлось сделать это за Вас, мне не трудно.

LOL


DiamondShark   (2011-01-16 20:04:00) [32]


> подумай, какая разница как переменную обозвать.

Подумай, какая разница, дать корректный код, или глюкопотенциальную фигню.

Если прототип "procedure Proc" написать корректно, то код будет просто работать корректно всегда.
А так надо помнить, что, благодаря модели "register", вызов с неправильной сигнатурой не портит стек.
Ну, по крайней мере, при двух аргументах не портит.
Ну, в текущей версии компилятора, точняк не портит.
Ну, в том объекте, кому мы делегат навешиваем, точно нет фигни, вроде

property OnChange : TNotifyEvent; read GetOnChange; write SetOnChange;

function TMyCrazyObject.GetOnChange
begin
 Result := FInnerObject.OnChange;
end;

procedure TMyCrazyObject.SetOnChange
begin
 FInnerObject.OnChange := value;
end;


sniknik   (2011-01-16 19:30:00) [33]

> Вы сами свой пример не запускали.
почитай выше, о разнице между 1 и 2мя  переменными ([17]). + подумай, какая разница как переменную обозвать. не, конечно неплохо называть однотипно, но для компа это просто адрес в памяти, а название self или sender он не разбирает (если его не "обучить" конечно, типа RTTI).

кстати сам попробуй, а после того как сработает убери значение из M.Data := Edit;. поставь там nil, и вот тогда... бяда бяда. ;)


DiamondShark   (2011-01-16 19:04:00) [34]


> Юрий Зотов ©   (16.01.11 09:55) [22]

Вы сами свой пример не запускали.


Юрий Зотов   (2011-01-16 09:55:00) [35]


procedure Proc(Sender: TObject);
begin
 ShowMessage(Sender.ClassName)
end;

var
 M: TMethod;

procedure TForm1.FormCreate(Sender: TObject);
var
 Edit: TEdit;
begin
 Edit := TEdit.Create(Self);
 Edit.Parent := Self;
 M.Code := @Proc;
 M.Data := Edit;
 Edit.OnChange := TNotifyEvent(M)
end;


Юрий Зотов   (2011-01-16 09:06:00) [36]

Но если уж очень сильно хочется, то:
1. Вложенную процедуру сделать внешней.
2. Назначить EvChange.Data (ссылка на объект, чье событие надо назначить).

Только это все равно неправильно. Правильно - так не делать.


Юрий Зотов   (2011-01-16 08:46:00) [37]

А ответ на вопрос "как правильно осуществить вызов из примера в первом постинге" все же имеется.

Отвечаю: правильно- никак. Правильно- переработать структуру кода так, чтобы не приходилось делать неправильное.


Германн   (2011-01-16 04:07:00) [38]


> В постинге [8], тёзка, я сообщил, что меня не интересует
> TForm1, а также никакие лишние классы. Сколько можно вываливать
> эти детсадовские примеры как создать TButton или TMyClass?
>
>

В постинге [8] кроме очевидного бреда "недоучки" ничего нет!

Но в посте [0] присутствует Form : TForm;
И на этой форме создаются компоненты типа TEdit. Создаются в рантайме, очевидно. Но без всякого понимания что и как нужно делать! А статьи читать - не барское дело!
P.S. Троешники идут лесом!


DiamondShark   (2011-01-15 23:50:00) [39]

Поциэнт хочет вызвать вложенную процедуру как процедуру верхнего уровня?
При этом стучит ложкой и огрызается на медперс-анал?
Вколите ему кто-нибудь два кубика эвтаназепама.


sniknik   (2011-01-15 20:50:00) [40]

> (если же параметров будет больше, или спецификация вызова будет другой, параметры могут передаваться через стек
все правильно, но не смертельно... в дельфи в процедурах делается восстановление состояния указателей, и потому параметром больше параметром меньше, "ерунда, дело житейское" (© Карлсон который живет на крыше)... а иначе бы были невозможны процедуры с открытым списком.
т.е. если к нему не обращаться то неважно, что он "мусорный" (кусок Data метода у него не инициализирован, но и обращения к self нет).

но вот то, что адрес/параметр остались в стеке, т.е. суть локальные, а вызов внешний по отношению к ним,  вот это уже гарантированное AV.

насчет спецификаций ... + похоже параллельный ответ "делающему монстра", ну пофиг.
возьми его код, и замени  
 EvChange.Code := @EvOnChange;
 OnChange := TNotifyEvent(EvChange);
на
 OnChange := TNotifyEvent(OnGetMy); (сохраним переменную собственно в объекте)
и все будет работать (если конечно OnGetMy передана извне, и это адрес "внешней" процедуры, а не такой же локальной).
работает, хотя, при вызове метода 2 параметра Self, Sender, а процедуры объекта только 1 Self. (т.е. лишний не мешает)

> Тогда у тебя может что-то получиться.
не получится, если "именно так как хочется". почему вроде объяснил.

> Нанять программиста.
вот это да. гарантирование решение проблем... т.к. программисты решают задачу, а не правят до посинения неверный путь ее решения, только потому что "так хочется".


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо