Кто может подсказать ответы на слдеующие вопросы:
1. Как отличить обычную процедуру, объявленную в секции Published формы, от объявленного там же обработчика события, например, типа TNotifyEvent?
2. Как отсортировать эти обработчики по их типам?
Нигде не могу найти ничего вразумительного по этому вопросу. Нашел функцию, которая позволяет получить список всех published-методов формы, однако она не позволяет узнать тип метода... Листинг привожу ниже.
procedure EnumMethods(aClass: TClass; lines: TStrings);
type
TMethodtableEntry = packed record
len: Word;
adr: Pointer;
name: ShortString;
end;
{Note: name occupies only the size required, so it is not a true shortstring! The actual
entry size is variable, so the method table is not an array of TMethodTableEntry!}
var
pp: ^Pointer;
pMethodTable: Pointer;
pMethodEntry: ^TMethodTableEntry;
i, numEntries: Word;
begin
if aClass = nil then
Exit;
pp := Pointer(Integer(aClass) + vmtMethodtable);
pMethodTable := pp^;
lines.Add(format('Class %s: method table at %p', [aClass.Classname,
pMethodTable]));
if pMethodtable <> nil then
begin
{first word of the method table contains the number of entries}
numEntries := PWord(pMethodTable)^;
lines.Add(format(' %d published methods', [numEntries]));
{make pointer to first method entry, it starts at the second word of the table}
pMethodEntry := Pointer(Integer(pMethodTable) + 2);
for i := 1 to numEntries do
begin
with pMethodEntry^ do
lines.Add(format(' %d: len: %d, adr: %p, name: %s', [i, len, adr,
name]));
{make pointer to next method entry}
pMethodEntry := Pointer(Integer(pMethodEntry) + pMethodEntry^.len);
end;
end;
//EnumMethods(aClass.ClassParent, lines);
end;
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
11-09-2007 16:56
1. Как отличить обычную процедуру, объявленную в секции Published формы, от объявленного там же обработчика события, например, типа TNotifyEvent?
Никак... По той простой причине, что они ничем не отличаются...
Ни один доступный источник не дает информации, как получить данные не о методах-свойствах, а просто о published-методах.
Основная ошибка... Нет методов-свойств... Есть свойства, являющиеся указателями на процедуры определенного типа. Например, OnClick - это всего лишь указатель на процедуру с одним параметром типа TObject, являющуюся методом какого-либо класса (кстати, не обязательно своего). Если ничего не назначено, он равняется nil, а если назначено, то там хранится указатель на соответствующую процедуру. Но это именно указатель, а не процедура... А процедура может быть любой, удовлетворяющая вышеописанному типу. Указатель на эту процедуру можно назначить либо в дизайн-тайме, либо в ран-тайме, даже более того, можно в ран-тайме по очереди назначать разные процедуры. В дизайн-тайме предлагаются процедуры только из раздела published и только соответствующего типа. Для этого и существует этот раздел и кроме обработчиков, которые нужны в выпадающем списке в инспекторе объектов в дизайн-тайме, других методов там быть не должно (это если делать по уму). Так что мне не понятна необходимость что-либо там различать. В ран-тайме можно назначать обработчиком любую доступную процедуру соответствующего типа и помещать их в раздел published нет никакой необходимости.
То, что обработчики "образуются" двойным кликом в испекторе объектов - это всего лишь избавление программиста от рутины и не более того. Никакими особыми свойствами полученные таким образом процедуры не обладают. Просто экономия времени. Все то-же самое можно набить ручками...
Попытаюсь проиллюстрировать все вышесказанное примером (скопируйте текст в соответствующие файлы):
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
Button1.OnClick := Actions[RadioGroup1.ItemIndex];
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Обработчик, назначенный в дизайнере');
end;
procedure TForm1.Click0(Sender: TObject);
begin
WindowState := wsMaximized;
end;
procedure TForm1.Click1(Sender: TObject);
begin
WindowState := wsNormal;
end;
procedure TForm1.Click2(Sender: TObject);
begin
ShowMessage('Hello, World!');
end;
procedure TForm1.Click3(Sender: TObject);
begin
ModalResult := mrOk;
Close;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ModalResult <> mrOk then
begin
ShowMessage('Нет, сэр, так вы не выйдете... Попробуйте через SuperButton...');
Action := caNone;
end
else
ShowMessage('Bye!');
end;
{ TOtherClass }
procedure TOtherClass.SuperProcedure(Sender: TObject);
begin
ShowMessage(Format('Выполняется процедура из другого класса'#13#13 +
'Procedure: TOtherClass.SuperProcedure'#13 +
'Sender: %s',
[Sender.ClassName]));
// Кстати, экземпляр TOtherClass мы не создавали
end;
В рунтайме определить тип метода (в общем случае) никак.Тип определяется в дизан-тайме только если метод является значением какого либо свойства. Дизайнер же определяет тип по тексту.Так что GEO прав - никакой RTTY здесь не поможет, да vmtTable тоже, т.к не содержит списка параметров и их типов.
Вы слышали про RTTY? Там хранится информация о типах в рантайме. В том числе и о свойствах из раздела published. Почитайте хелп про RTTY.
Про RTTI я, конечно же, слышал. Но! Ни один доступный источник не дает информации, как получить данные не о методах-свойствах, а просто о published-методах. Можно получить список полей, событий и т.д., а вот это - никак (может быть, я не знаю...). Обратите внимание, что в приведенном выше листинге НЕТ НИ ОДНОГО ОПЕРАТОРА из модуля TypInfo.pas. Может быть, существуют подобные способы и для моего случая? Может, кто-то умеет использовать эту таблицу методов (vmtMethodtable)?
>>>То есть вы хотите сказать, что в рантайме нет никакой возможности выяснить тип методаundefined
Вы слышали про RTTY? Там хранится информация о типах в рантайме. В том числе и о свойствах из раздела published. Почитайте хелп про RTTY. TypeInfo.pas модуль для работы c RTTY. С ее помошью можно получить любую информацию о свойствах процедурного типа, с описанием количества передаваемых параметров, их типа и т.п. в частности.
То есть вы хотите сказать, что в рантайме нет никакой возможности выяснить тип метода и, например, при совпадении типов присвоить его подходящему обработчику? В таком случае - печально :-(
А, может быть, все-таки есть какая-то зацепка?
>>> Как-то он различает эти методы?
Вы сами ответили на этот вопрос: "соответствуют этому обработчику по типу". То есть любой published-метод, являющийся процедурой и содержащий один параметр типа TObject, в Object Inspector попадет в список возможных обработчиков события TNotifyEvent.
Как Object Inspector определяет, что данный метод содержит один параметр типа TObject? Подозреваю, что он анализирует паскалевский текст.
А как же тогда Object Inspector справляется с этим? Как-то он различает эти методы? Ведь когда вы открываете ComboBox со списком методов, в нем отображаются только те методы, которые соответствуют этому обработчику по типу. Как бы это сделать подобным образом?
А никак не отличить. Если процедура по типу не соответствует обработчику событий, то она гарантированно не является обработчиком событий. Если же процедура по типу соответствует обработчику какого-либо события, то она может являться обработчиком этого события, а может не являться. Чтобы процедура сатала обработчиком события, она должна быть указана в специальном свойстве, которое содержит указатель на обработчик события.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.