![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вызов функции из функции [D7, XP]
Сергей © (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. (т.е. лишний не мешает)
> Тогда у тебя может что-то получиться.
не получится, если "именно так как хочется". почему вроде объяснил.
> Нанять программиста.
вот это да. гарантирование решение проблем... т.к. программисты решают задачу, а не правят до посинения неверный путь ее решения, только потому что "так хочется".