Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.01.20;
Скачать: [xml.tar.bz2];

Вниз

TNotifyEvent   Найти похожие ветки 

 
афвуд   (2004-01-06 18:51) [0]

Как мне написать процедуру, чтобы её можно было вешать как обработчик события.
Проблема в том что указатели на методы класса другие нежели чем на простые процедуры(там добавлен также и указатель на обьект). Как обьявить что процедура типа TNotifyEvent, причём привязывать её к какому то обьекту мне нежелательно.


 
jack128   (2004-01-06 19:02) [1]


> Как обьявить что процедура типа TNotifyEvent, причём привязывать
> её к какому то обьекту мне нежелательно.

TEventHandlers = class
public
class function NotifyEventHandler(Sender: TObject);
class function DatasetNotifyEventHandler(Sender: TDataSet);
// и так далее
end;


 
jack128   (2004-01-06 19:03) [2]

пример использования -)

Button1.OnClick := TEventHandlers.NotifyEventHandler


 
YuRock   (2004-01-06 19:04) [3]

Межно разве-что создать класс с одним методом, объявить переменную этого класса и можно даже объект не создавать (пусть будет nil) - метод будет работать.

А потом можно писать что-то вроде:

OnClick := Object1.MyOnClick,

где Object1 на самом деле = nil.


 
Тимохов   (2004-01-06 19:08) [4]

jack128 © (06.01.04 19:02) [1]
Прикольная штука.
Сам придумал?


 
афвуд   (2004-01-06 19:09) [5]

>OnClick := Object1.MyOnClick,

>где Object1 на самом деле = nil.

Думаю будет Access Violation. Нужно хотя бы один обьект в памяти держать, чтобы в памяти его метод появился.


 
VMcL   (2004-01-06 19:10) [6]

Зачем спрашивать не буду.

Вот вариант:

procedure MyProc(Dummy: Pointer; Sender: TObject);
begin
ShowMessage("My");
end;

procedure TForm1.FormCreate(Sender: TObject);
var
MyMethod: TNotifyEvent;
begin
TMethod(MyMethod).Code := @MyProc;
TMethod(MyMethod).Data := nil;
Button1.OnClick := MyMethod;
end;


 
Тимохов   (2004-01-06 19:11) [7]

афвуд © (06.01.04 19:09) [5]
Вы как-то free вызываете для nil объектов и ничего - все работает.

Можете попробовать
TObject(nil).free();


 
афвуд   (2004-01-06 19:11) [8]

Тоже самое можно сказать про jack128-метод.

Надо ещё просто создать обьект.

Похоже это единтсвенный выход.


 
Vuk   (2004-01-06 19:13) [9]

Можно еще вспомнить, что указатель на метод - это структура, состоящая из двух указателей, на код метода и на данные экземпляра. А еще можно вспомнить, что методы от процедур отличаются неявным параметром self, который передается первым, и этот параметр - указатель на данные экземпляра (для методов экземпляра) или ссылка на класс (для методов класса).

Исходя из этого получаем:


procedure Test(DummySelf: pointer; Sender: TObject); register;
begin
...
end;

procedure TForm1.FormCreate(Sender: TObject);
var
N: TNotifyEvent;
begin
with TMethod(N) do
begin
Code := @Test;
Data := nil;
end;
Button1.OnClick := n;
end;


 
Тимохов   (2004-01-06 19:13) [10]

афвуд © (06.01.04 19:11) [8]
Често скажу [1] не проверял. Но этот метод (если работает) самый рульный - создать AV нереально...


 
YuRock   (2004-01-06 19:14) [11]

> афвуд © (06.01.04 19:09) [5]

Нет. Access Violation не будет никогда, т.к. MyOnClick (как и все методы) - просто функция, в которую параметром передается указатель на объект (Self). Ну и что, что он nil?

Access Violation будет только в том случае, если обратиться к свойствам несозданного объекта класса, но это делать в данном случае не нужно.


 
Vuk   (2004-01-06 19:15) [12]

Во! Пока писал уже ответили про то же самое! :o)


 
афвуд   (2004-01-06 19:16) [13]

Всё понял. Блин. Я сёня соображаловку похоже отключил :))

var m:TMethod

begin
m.Code=@MyProc;
m.Data=nil;
SetMethodProp(<Указатель на мой обьект>,"OnClick",&m);


Кажется так. Идею подал VMcL :) thx.


 
YuRock   (2004-01-06 19:17) [14]

... продолжение
> > афвуд © (06.01.04 19:09) [5]

И вообще я советую только то, что сам проверял и использовал.


 
Тимохов   (2004-01-06 19:22) [15]

Граждане!
Если уж зашел разговор на эту тему, то может объясните мне почему это работает.

tc = class
private s: string;
public procedure SetS( const S: string);
end;

tp = procedure ( {const}S: String) of object;

var
p: tp;
c: tc;
begin
c := tc.create();

tmethod(p).code := @tc.SetS;
tmethod(p).data := c;
p("1111");
end;

Мне казалось, что p("1111") должен давать AV.


 
афвуд   (2004-01-06 19:22) [16]

Т.е. SetMethodProp(<Указатель на мой обьект>,"OnClick",m);


 
Тимохов   (2004-01-06 19:27) [17]

забыл еще реализацию SetS

procedure tc.sets;
begin
fs := s;
showmessage(fs);
end;

Так вопрос - вроде, когда пишешь const, то передается указатель, а в случае без const, должна строка засовываться в буфер. Т.е. вроде как разный метод передачи данных, а все работате.
Или я что-то не понимаю в передаче параметров типа string?


 
YuRock   (2004-01-06 19:28) [18]

> Тимохов © (06.01.04 19:22) [15]

А почему это должно не работать? Ты же присваиваешь tmethod(p).data := c, а указатель на объект с - и есть указатель на структуру данных объекта (на сколько я понимаю).


 
Тимохов   (2004-01-06 19:29) [19]

YuRock © (06.01.04 19:28) [18]
См 17. Я там дал уточнение вопроса.


 
YuRock   (2004-01-06 19:30) [20]

> YuRock © (06.01.04 19:28) [18]

[18] к [17] относится. Правда я не знаю, что такое "fs"


 
jack128   (2004-01-06 19:33) [21]


> Тимохов © (06.01.04 19:08) [4]


> Сам придумал?

Да.
Вообще лично я считаю, то что компилятор это пропускает - это баг. в procedure(Sender: Tobject) of object - первым неявным параметром передается объект(экземпляр класса), а в моем случае - классовая ссылка на teventhandler.На лицо несоответствее типов. Но борланду веднее. -)

> афвуд © (06.01.04 19:11) [8]
> Тоже самое можно сказать про jack128-метод.
Нет. Причины см выше.


 
VMcL   (2004-01-06 19:37) [22]

>>YuRock © (06.01.04 19:04) [3]

Если MyOnClick - виртуальный метод, то будет немного грустно.


 
Тимохов   (2004-01-06 19:37) [23]

jack128 © (06.01.04 19:33) [21]
Классный метод. Хотя с тем, что на лицо ошибка (вернее неточность) компилятора согласен.


 
YuRock   (2004-01-06 19:40) [24]

> [22]

Интересно... кому понадобится делать метод класса, объектов которого даже создаваться не будет, виртуальным?..

Все равно спасибо за уточнение.


 
Vuk   (2004-01-06 19:43) [25]

to jack128:
>Вообще лично я считаю, то что компилятор это пропускает - это
>баг.
С какого перепугу это баг-то? Указатель на метод = код + данные. В случае с объектом данные - это ссылка на экземпляр, а в случае с классом - ссылка на класс. И где баг?


 
VMcL   (2004-01-06 19:43) [26]

>>jack128 © (06.01.04 19:02) [1]

Кстати, гы: [Error] Function needs result type :))


 
VMcL   (2004-01-06 19:45) [27]

>>YuRock © (06.01.04 19:40) [24]

Ну мало что в голову взбредет. Человеку ж понадобилось обработчики of object на процедуры сослать (см. [0]) :))


 
jack128   (2004-01-06 19:45) [28]


> Тимохов © (06.01.04 19:22) [15]

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


 
Vuk   (2004-01-06 19:48) [29]

to VMcL:
>Если MyOnClick - виртуальный метод, то будет немного грустно.
А также если даже метод невиртуальный, но там используются поля экземпляра.


 
jack128   (2004-01-06 19:48) [30]


> Vuk © (06.01.04 19:43) [25]


> Указатель на метод = код + данные.
Ну если так, то бага нету. Просто я считаю, что нужно различать КЛАССОВЫЙ метод и просто метод. Но это мое личное мнение :-). А по твоему получается что данные могут быть любые (ну например целое число).


 
Vuk   (2004-01-06 19:49) [31]

to jack128:
>Просто я считаю, что нужно различать КЛАССОВЫЙ метод и просто
>метод.
А на кой черт оно надо? :o)


 
YuRock   (2004-01-06 19:49) [32]

> VMcL © (06.01.04 19:45) [27]

В принципе, иногда это удобно (вернее, не [0], а [1] или [3]), когда одинаковые по смыслу и реализации события разных по типу классов надо использовать. Или даже одинаковых по типу классов, но не всегда, а, скажем, часто...


 
Тимохов   (2004-01-06 19:50) [33]

jack128 © (06.01.04 19:45) [28]
Хорошо. Но это работает также для всех других типов.
Я всегда думал, что если не написать const для массива array[0..99] of integer то при передаче в метод он весь затолкался бы в стек. Если с const, то только указатель на начало массива. Насколько я понимаю в этом и есть суть (вернее ее часть) директивы const - в оптимизации.

Но даже для указанного массива это работает.
Я ясно сформулировал вопрос?


 
YuRock   (2004-01-06 19:52) [34]

> Vuk © (06.01.04 19:48) [29]

См. [11] (самый конец). Там этот вариант оговаривается.


 
jack128   (2004-01-06 19:56) [35]


> Я всегда думал, что если не написать const для массива array[0..99]
> of integer то при передаче в метод он весь затолкался бы
> в стек
Я всегда считал иначе -). Если SizeOf(MyType) > 4 d регистры проца или в стек загоняется УКАЗАТЕЛЬ на переменную (мы говорим передаче по значению) В случае константной ссылки - всегда передается ссылка. За константностью следит компилятор.


 
Тимохов   (2004-01-06 19:59) [36]

jack128 © (06.01.04 19:56) [35]
А все-таки пример с массивом - там ясно больше чем 4 байта.

код

type
sss = array[1..10] of integer;
tc = class
public procedure SetS(const a: sss);
end;

procedure tc.sets;
begin
showmessage(inttostr(a[1]) + "-"+inttostr(a[10]));
end;

type
tp = procedure ({const}S: sss) of object;

procedure TForm1.Button17Click(Sender: TObject);
var
p: tp;
c: tc;
a: sss;
begin
a[1] := 12;
a[10] := 122;
c := tc.create();
tmethod(p).code := @tc.SetS;
tmethod(p).data := c;
p(a);
end;

выведется строка "12-122"


 
Vuk   (2004-01-06 20:00) [37]

to YuRock:
>Там этот вариант оговаривается.
Свойства, извините, это есть более хитрая вещь, чем поля экземпляра и с ними не так уж все однозначно. В конце концов для свойства в качестве аксессоров могут быть указаны два метода класса...


 
YuRock   (2004-01-06 20:02) [38]

> Тимохов © (06.01.04 19:59) [36]

Ну и что здесь удивительного?


 
Тимохов   (2004-01-06 20:04) [39]

YuRock © (06.01.04 20:02) [38]
Прочтите 33. Там я постарался сформулировать вопрос. В 36 пример кода.

Я так понимаю, что у меня есть пробелы в знаниях о передачи параметров?


 
YuRock   (2004-01-06 20:05) [40]

> Vuk © (06.01.04 20:00) [37]

Я имелл в виду классику ("классы состоят из методов (функций) и свойств (данных)")


 
jack128   (2004-01-06 20:08) [41]

Вот код для строк
{$O-}

procedure SameProcValue(s: string);
begin
end;

procedure SameProcConst(const s: string);
begin
end;

procedure SameProcVar(var s: string);
begin
end;

procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
S := StringOfChar("A", 10);
SameProcValue(s); // здесь breakpoint и View CPU
SameProcConst(s);
SameProcVar(s);
end;

{$O+}
В твоем примере, как и в моем передается указатель на данные (указатель на первый символ строки или на первый элемент массива)


 
Тимохов   (2004-01-06 20:10) [42]

jack128 © (06.01.04 20:08) [41]
Да наверное, ты прав. Я еще посмотрю это на свежую голову.
Наверное, только перед SameProcValue делается копия s, причем не в стеке, и указатель на эту копию и передается.

Да будем изучать asm.


 
jack128   (2004-01-06 20:10) [43]

ну то есть в моем примере отличие в SameProcVar.

tp = procedure ({const}S: sss) of object; - закоментировать const - не коментировать - результат один. Ты попробуй поэксперементировать с даными у которых SizeOf(MyType) = 4


 
YuRock   (2004-01-06 20:12) [44]

> Тимохов © (06.01.04 19:50) [33]

Нет. Затолкается в стек только когда вообще ничего не писать перед параметром.

А const - то же, что и var, но с одним отличием: дельфя не даст откомпилить код, в котором будет хоть какой-нибудь намек на изменения параметра, переданного с директивой const (т.е. используется только для скорости), а var наоборот - для изменения и предназначен (хотя способ передачи идентичен const).


 
Тимохов   (2004-01-06 20:13) [45]

jack128 © (06.01.04 20:10) [43]
с Byte, Integer, Double - все работает ОК.


 
Тимохов   (2004-01-06 20:14) [46]

YuRock © (06.01.04 20:12) [44]
Вот похоже что вы не правы в "Затолкается в стек только когда вообще ничего не писать перед параметром", т.к. если бы это было так, то мой пример не работал бы. Наверное затолкается в стек все тот указатель, только на копию строки, созданную не в стеке.

Буду асм смотреть.


 
jack128   (2004-01-06 20:19) [47]


> Тимохов © (06.01.04 20:13) [45]
> jack128 © (06.01.04 20:10) [43]
> с Byte, Integer, Double - все работает ОК.
Да?? Странно.. Напиши сюда о результах своих иследований -)


 
YuRock   (2004-01-06 20:28) [48]

> Тимохов © (06.01.04 20:14) [46]
Нет. Он работает не по-этому. А потому, что в дельфях переменная типа стринг - это и есть указатель.
Правда, менять она его не дает, если var не написать :)


 
Тимохов   (2004-01-06 20:29) [49]

А что писать? Просто в примере замени последовательно на byte, integer, double. Все работает.

type
tc = class
public procedure Show(const a: ТИП);
end;

procedure tc.Show;
begin
showmessage(floattostr(a));
end;

type
tp = procedure ({const}S: ТИП) of object;

procedure TForm1.Button17Click(Sender: TObject);
var
p: tp;
c: tc;
i: ТИП;
begin
c := tc.create();
tmethod(p).code := @tc.SetS;
tmethod(p).data := c;
i := 1223424;
p(i);
end;


 
Тимохов   (2004-01-06 20:32) [50]

YuRock © (06.01.04 20:28) [48]
Вы не правы - если ничего не писать, то менять параметр можно.
Проверил.


 
YuRock   (2004-01-06 20:42) [51]

> Тимохов © (06.01.04 20:14) [46]

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


 
jack128   (2004-01-06 20:43) [52]


> А что писать? Просто в примере замени последовательно на
> byte, integer, double. Все работает.

Я имел ввиду, вот это

> Да будем изучать asm.
Я с асмом на вы.

Лично мои домыслы таковы.
по значению.
Для типов SizeOf(Type) <= 4 передают копию параметра с стек.
Для типов SizeOf(Type) > 4 передают адрес параметра с стек.

по ссылке.
Для всех типов передается адрес параметра в стек

по константной ссылке
Для типов SizeOf(Type) <= 4 передают копию параметра с стек.
Для типов SizeOf(Type) > 4 передают адрес параметра с стек.

Если скажите что означает lea eax, [тра - ля - ля] , то выскажусь точнее -)


 
YuRock   (2004-01-06 20:45) [53]

> Тимохов © (06.01.04 20:32) [50]

Ну, правильно, можно, только при выходе из функции он "вернется на место"... Хотя если это в примере [15], то я не удивлюсь уже ничему.


 
jack128   (2004-01-06 20:53) [54]


> Наверно, все параметры на самом деле по 4 байта, а что там
> - адрес или значение - придумывает компилятор в зависимости
> от кода... Хотя это бред...
Почему бред?
Вот еще один пример
{$O-}

procedure SameProcValue(s: string);
begin
PByte(s)^ := 49;
end;

procedure SameProcConst(const s: string);
begin
PByte(s)^ := 49;
end;

procedure SameProcVar(var s: string);
begin
PByte(s)^ := 49;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
S := StringOfChar("A", 10);
SameProcValue(s);
ShowMessage(s); s[1] := "A";
SameProcConst(s);
ShowMessage(s); s[1] := "A";
SameProcVar(s);
ShowMessage(s);
end;

{$O+}
А теперь замените тип параметра на integer и в процедурах напишите PInteger(@s)^ := 10; и посмотрите на результат (после выхода из каждой процедуры обнуляйте переменную s)



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2004.01.20;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.58 MB
Время: 0.012 c
14-63367
RNZ
2003-12-29 10:10
2004.01.20
Delphi 8


3-63034
ИМХО
2003-12-22 10:52
2004.01.20
TClientDataSet: вопрос на засыпку


1-63180
Эли
2004-01-10 14:36
2004.01.20
Вернуть активность форме


1-63113
Dr.Karter
2004-01-08 09:18
2004.01.20
Че делать с PDF


1-63159
DDA
2004-01-05 21:48
2004.01.20
Контекстное меню





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский