![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
не работает динамически созданный обработчик
vasek © (2005-11-23 23:48:00)для динамически созданной кнопки данный обработчик работает:
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure myClick(Sender: TObject);
end;
var
Form1: TForm1;
const
i : integer = 0;
implementation
{$R *.DFM}
procedure TForm1.myClick(Sender: TObject);
begin
with Sender as TButton do
Self.Caption := ClassName + ' ' + Name;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
with TButton.Create(self) do begin
Left := 20;
Top := 30 + i;
Width := 120;
Height := 40;
Name := 'ThisButton' + IntToStr(i);
Caption := 'There' + IntToStr(i);
OnClick := MyClick; { процедура, определенная где-то еще }
Parent := Form1;
end; {end with}
inc(i, 40);
end; {end button1.click}
end.
а так не хочет... :( :
program Project1;
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls,
Unit1 in 'Unit1.pas';
{$R *.res}
type
TButtonArray = array[1..4,1..4] of TButton;
var
MainForm: TForm;
Hnd, Hnd1: THandle;
Buttons : TButtonArray;
Panel1: TPanel;
procedure ButtonPressed(Sender: TObject);
var
B : TButton;
i1,j1: Integer;
begin
B := Sender as TButton;
begin
{code}
end;
end;
begin
MainForm:= TForm.CreateParented(Hnd);
Application.Initialize;
Application.CreateForm(TForm, MainForm);
Buttons[1,1]:= TButton.CreateParented(MainForm.Handle);
Buttons[1,1].Parent:= MainForm;
Buttons[1,1].OnClick:= ButtonPressed;
end;
почему ?
пишет следующее: incompatible types: 'method pointer and regular procedure'.
begin...end (2005-11-26 21:38:00) [21]> sniknik © (26.11.05 20:37) [39]
> как ни странно да. понимаю. ;)
Тогда мне совершенно непонятно, к чему и о чём был последний абзац в [36].
> self у нас nil. и почему бы это? не потому ли что дату не
> заполнили?
Да, именно поэтому.
> почему? не потому ли что у нас переменная Sender образно
> говоря стала "ио" Self-a?
Да, именно поэтому.
> и что скажи сто тогда неверно в
> >> это потому что поле Data в примере не определено (nil)
Подход неверен, понимаете? Описывая регулярную процедуру, код которой предполагается использовать в качестве кода метода-события OnClick, с одним параметром, Вы теряете один параметр! Т-е-р-я-е-т-е!Вы сами зачем-то назначаете Data (Self), чтобы использовать потом его как Sender, и игнорируете автоматически передающийся при возбуждении события параметр -- "настоящий" Sender. Неужели непонятно?
sniknik (2005-11-26 20:37:00) [22]> procedure of object понимаете?
как ни странно да. понимаю. ;) хелп читать умею, а разница расписана на первой странице описания of object.
> ... Человек пытается по Sender'у определить, какая кнопка нажата. ...
ааааа... вот. теперя я понял с чего ты взьелся, название не понравилось...
так без разницы как переменную назвать. ку?
берем пример, и переделываем в соответствии с
> begin...end © (26.11.05 11:56) [28]
> procedure ClickEventHandler(Self, Sender : TObject)
procedure ClickEventHandler(Self, Sender : TObject);
begin
Form1.Label1.Caption:= TButton( Self).Name;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Method : TMethod;
begin
Method.Code := @ClickEventHandler;
Method.Data := nil;
ButtonInstance.OnClick := TNotifyEvent(Method);
end;
нажимаем кнопочку... оппа а self то у нас и нету, self у нас nil. и почему бы это? не потому ли что дату не заполнили? проверяем
Method.Data := batton1;
работает.
теперь берем вариант
procedure ClickEventHandler(Sender : TObject);
begin
Form1.Label1.Caption:= TButton( Sender).Name;
end;
при Method.Data := nil; сендер тоже нил. странное совпадение, отложим в памяти...
заполняем Method.Data := batton1;
работает.
почему? не потому ли что у нас переменная Sender образно говоря стала "ио" Self-a?
проверяем еще на кнопку вешаем
procedure TForm1.Button3Click(Sender: TObject);
begin
Button1.OnClick(Button4);
end;
т.e. по идее сендер у нас сейчас Button4
и при
Method.Data := batton1;
procedure ClickEventHandler(Sender : TObject);
begin
Form1.Label1.Caption:= TButton( Sender).Name;
end;
должен показать имя Button4 (раз я не прав)
нажимаем кнопочку показывает имя batton1 которое Method.Data прописано...
чешем репу и делаем вывод: под названием Sender в данном случае прячется Self! который "живет", как оказывается, в Method.Data...
обана. какой неожиданный результат. и что скажи сто тогда неверно в
>> это потому что поле Data в примере не определено (nil)
> Неверно.
?
с чего все и началось.
begin...end (2005-11-26 18:59:00) [23]> Zeqfreed © (26.11.05 14:32) [35]
> Я не вижу ничего подобного в [27], ей богу.
А я вижу. Человек пытается по Sender'у определить, какая кнопка нажата. [26] -- у него не получается (что и неудивительно). Далее следует [27], где говорится, что определить не получается именно потому, что в Data находится nil. По-моему, здесь налицо отождествление содержимого Data и Sender'а.
> sniknik © (26.11.05 15:12) [36]
> про Sender я действительно не говорил и даже не думал в
> тот момент.
Странно. Вроде, говорим, говорим, а Вы об этом даже и не думаете, оказывается.
> и даже наоборот, элегантное решение может быть, когда одним
> обработчиком обрабатываются разные данные... (не для того
> ли это и сделано? подумай)
Да, параметр Sender -- объект, возбудивший событие -- для того и придуман. Только Вы никак не поймёте, что в варианте 1 из [32] Sender -- это на самом деле не Sender, а Self.
> вот теперь можеш обвинять в том что я путаю селф и сендер,
> потому как в предыдушем абзатце намек на подобное "кощунство"
Извините, ничего не понял. Переформулируйте, если можно.
> зачем дата инициализируется? по твоему это не нужно, ставили
> бы nil...
Какое отношение к обсуждаемому вопросу имеет приведённый Вами код?
> именно такой способ и подразумевался при разработке VCL.
> (т.е. это основной способ)
Извините, опять ничего не понял.
> TNotifyEvent = procedure(Sender: TObject) of object;
Вы вот это "of object" видите? Различие между procedure (как в [29]) и procedure of object понимаете? Пока что -- не похоже.
vasek (2005-11-26 17:42:00) [24]спасибо всем большое, что приняли участие в обсуждении данной темы. код Zeqfreed © вариант 1 работает отлично - это то что я хотел ;)
sniknik (2005-11-26 15:12:00) [25]про Sender я действительно не говорил и даже не думал в тот момент. это все домыслы "from self".
> Указываем в Method.Data любой другой объект
также как через pointer можно передать указателю на класс указатель на переменную. ничего страшного... с точки зрения языка, программа да порушится при обращении к этой структуре, но вина ли эта pointer-а?
и даже наоборот, элегантное решение может быть, когда одним обработчиком обрабатываются разные данные... (не для того ли это и сделано? подумай)
или пришлось бы плодить одинаковый код при разный данных в разных структурах. (такой вот будет копи пасте компиляторный)
;) вот теперь можеш обвинять в том что я путаю селф и сендер, потому как в предыдушем абзатце намек на подобное "кощунство"
> Где?
function InvokeImplGetter(Self: TObject; ImplGetter: Cardinal): IInterface;
{$IFDEF PUREPASCAL}
var
M: function: IInterface of object;
begin
TMethod(M).Data := Self;
case ImplGetter of
$FF000000..$FFFFFFFF: // Field
Result := IInterface(Pointer(Cardinal(Self) + (ImplGetter and $00FFFFFF)));
$FE000000..$FEFFFFFF: // virtual method
begin
// sign extend vmt slot offset = smallint cast
TMethod(M).Code := PPointer(Integer(Self) + SmallInt(ImplGetter))^;
Result := M;
end;
else // static method
TMethod(M).Code := Pointer(ImplGetter);
Result := M;
end;
end;
зачем дата инициализируется? по твоему это не нужно, ставили бы nil... а скажу зачем, затем что описаны события(переменние) во всех классах всетаки как
TNotifyEvent = procedure(Sender: TObject) of object;
без self-а вначале, и потому без инициализации Data просто не обойтись, что и говорит что именно такой способ и подразумевался при разработке VCL. (т.е. это основной способ)
Zeqfreed (2005-11-26 14:32:00) [26]begin...end © (26.11.05 14:23) [34]
> Вариант 1. Указываем в Method.Data любой другой объект
> (например, форму), и при нажатии на кнопку получаем,
> что событие OnClick возбудила форма. Это неправильно,
> потому что на самом деле его возбудила кнопка.
> Следовательно, вариант 1 нельзя считать корректным.
Ответственность за то, что писать в Method.Data целиком лежит на программисте; и если он хочет туда написать любой другой объект, то должен понимать к чему это приведет. Выводов не делаю.
> Method.Data, судя по утверждениям в [27] -- это и есть
> Sender
Я не вижу ничего подобного в [27], ей богу. Про Sender там ни слова.
begin...end (2005-11-26 14:23:00) [27]> Zeqfreed © (26.11.05 14:05) [32]
Вариант 1.Указываем в Method.Data любой другой объект (например, форму), и при нажатии на кнопку получаем, что событие OnClick возбудила форма . Это неправильно, потому что на самом деле его возбудила кнопка . Следовательно, вариант 1 нельзя считать корректным.
Вариант 2.Вне зависимости от того, что указано в Method.Data, при обращении к Sender получаем верную информацию об инициаторе события. В этом легко убедиться, назначив кнопкам с разными именами один и тот же обработчик, и обращаясь внутри него к свойству(Sender as TComponent).Name.
Как же так? Method.Data, судя по утверждениям в [27] -- это и есть Sender, т.е. объект, инициировавший событие. Однако, даже если Method.Data = nil, вариант 2 будет работать правильно, и определять возбудивший событие объект, хотя он якобы должен быть равен nil.
> sniknik © (26.11.05 14:09) [33]
> код который непосредственно борландом используется
Где?
> оно что глюки дает?
Даёт.
sniknik (2005-11-26 14:09:00) [28]> "Не говорите загадками, Вы меня изводите" (с)
не переваливай с больной головы на здоровую. сам подкинунул "загадку" сказал "неверно" на тот код который непосредственно борландом используется. вот и обьясни. почему неверно? оно что глюки дает? или просто твоему мироощущению не соответствует?
Zeqfreed © (26.11.05 14:05) [32]
> Оба варианта работают, не спорьте :)
это было без вопросов, вариантов всегда больше чем один. (и к тому же я сразу проверил, в отличии от некоторых, не будем показывать пальцами... но это был слоник ;)
вопрос в том почему рабочий код - "неверно". (и без обьяснений...)
Zeqfreed (2005-11-26 14:05:00) [29]sniknik © (26.11.05 13:16) [29]
begin...end © (26.11.05 11:56) [28]
Вариант 1.
procedure ClickEventHandler(Sender : TObject);
begin
if (Sender is TButton) then
ShowMessage(Format('Button with caption %s has just been clicked', [(Sender as TButton).Caption]));
end;
procedure AddButton(ParentForm : TForm; Handler : Pointer; const ButtonCaption : String; const ButtonLeft, ButtonTop : Integer);
var
Method : TMethod;
btn : TButton;
begin
btn := TButton.Create(nil);
Method.Code := Handler;
Method.Data := btn;
with btn do begin
Caption := ButtonCaption;
Parent := ParentForm;
Left := ButtonLeft;
Top := ButtonTop;
OnClick := TNotifyEvent(Method);
end;
end;
Вариант 2.
procedure ClickEventHandler(Self, Sender : TObject);
begin
if (Sender is TButton) then
ShowMessage(Format('Button with caption %s has just been clicked', [(Sender as TButton).Caption]));
end;
procedure AddButton(ParentForm : TForm; Handler : Pointer; const ButtonCaption : String; const ButtonLeft, ButtonTop : Integer);
var
Method : TMethod;
begin
Method.Code := Handler;
Method.Data := nil;
with TButton.Create(nil) do begin
Caption := ButtonCaption;
Parent := ParentForm;
Left := ButtonLeft;
Top := ButtonTop;
OnClick := TNotifyEvent(Method);
end;
end;
Оба варианта работают, не спорьте :)
p.s. Щас открыл справку по TMethod да что-то она состоит из нескольких строк, где ничего толком и не говорится :( Может не там ищу?
begin...end (2005-11-26 13:21:00) [30]> sniknik © (26.11.05 13:16) [29]
Data -- это Self, а не Sender. Ку?
> и посмотри заодно что в генофонде дельфи используется
"Не говорите загадками, Вы меня изводите" (с)
sniknik (2005-11-26 13:18:00) [31]хм. чтото меня сглючило (это про повтор в начале), надо осторожнее методом копи пасте пользоваться... ;)
sniknik (2005-11-26 13:16:00) [32]> Неверно.
а ты проверь.
> Неверно.
а ты проверь.
procedure ClickEventHandler(Sender : TObject)
begin
//
end;
...
var
Method : TMethod;
begin
Method.Code := @ClickEventHandler;
Method.Data := Button1;
ButtonInstance.OnClick := TNotifyEvent(Method);
end;
и посмотри заодно что в генофонде дельфи используется.
begin...end (2005-11-26 11:56:00) [33]> vasek © (26.11.05 03:48) [26]
> procedure ClickEventHandler(Sender : TObject)
procedure ClickEventHandler( Self,Sender : TObject)
> sniknik © (26.11.05 11:48) [27]
> это потому что поле Data в примере не определено (nil)
Неверно.
sniknik (2005-11-26 11:48:00) [34]> т.е не понятно какая кнопочка нажата...
это потому что поле Data в примере не определено (nil). а в хелп по нему ты не заглядывал и не догадатся не пытался (элементарное же рассуждение/действие пропущено) .
> странно столько было сказанно слов хороших и разных, а воз и ныне там... :(
это потому что ты как донкихот сражаешся с ветряными мельницами там где их никто не видит.
и при том в зависимости от того какая мельница тебе примерешилась спосбы борьбы с ней будут разные... а видения твои до сих пор для всех тайна, смысла никто не понимает. вот скажи зачем уходить от dfm? смысл?, если ты оставляеш VCL то ничего от того где ты их создаш не изменится, а если их создавать в события создания формы то и проблемы твоей не будет, если наследовать и непосредственно в событии обработчики писать то тоже твоя проблема исчезает (она похоже в единственном выбраном тобой варианте существует... и так не делают, обычно). а если это типа переход на WinApi такой, ну тогда тут все неправильно начиная с того что весь Appliction надо убирать.
vasek (2005-11-26 03:48:00) [35]извиняюсь, пример Zeqfreed © работает вот только сендер, вот здест почемуто ничего не передает:
procedure ClickEventHandler(Sender : TObject);
begin
if (Sender is TButton) then
ShowMessage(Format('Button with caption %s has just been clicked', [(Sender as TButton).Caption]));
end;
т.е не понятно какая кнопочка нажата...
Германн (2005-11-26 02:41:00) [36]Ну, опять же про садомазохизм. А чем "дфм" так претит?
Ведь в vasek © (23.11.05 23:48) - без "дфм" вообще, просто не обойтись.
Совсем без "дфм", так это в "WinAPI".
vasek (2005-11-26 02:33:00) [37]хм.. в коня или мимо коня, а вопрос ведь остался неразрешенным, то что предложенно ЮЮ - компилятор говорит что не хватает файла ресурсов, а я ведь хотел без дфм обойтись. странно столько было сказанно слов хороших и разных, а воз и ныне там... :(
Leonid Troyanovsky (2005-11-25 14:20:00) [38]
> Плохиш © (25.11.05 13:44) [22]
> Ответ на это был дан ещё ЮЮ © (24.11.05 04:20) [4]
И, в данном контексте, он был единственно верным, бо
избыточный корм, как правило, идет не в коня.
--
Regards, LVT.
Плохиш (2005-11-25 13:44:00) [39]
> vasek © (25.11.05 13:41) [21]
> все просто: необходимо создать массив кнопок и чтобы каждая
> умела чтото делать без дфм.
Ответ на это был дан ещё ЮЮ © (24.11.05 04:20) [4]
vasek (2005-11-25 13:41:00) [40]на тему:
Германн © (25.11.05 01:57) [15]
Может объяснишь простым языком - зачем нужен такой садомазохизм:
Объявление процедур, реализация процедур, создание компонет и т.п. в файле проекта, исходно для этого не предназначенного?
все просто: необходимо создать массив кнопок и чтобы каждая умела чтото делать без дфм.