Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  06:00[Войти] | [Зарегистрироваться]
Ответ на вопрос № 55213
RTTI |

10-09-2007 08:55
Уважаемые мастера Delphi!

Кто может подсказать ответы на слдеующие вопросы:
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;



Результат работы:

Class TForm1: method table at 00447867
  9 published methods
  1: len: 20, adr: 00447954, name: GetProperties
  2: len: 17, adr: 0044794C, name: FormCreate
  3: len: 20, adr: 00447BB0, name: ClearBtnClick
  4: len: 18, adr: 00447BF8, name: SetBtnClick
  5: len: 19, adr: 00447E3C, name: Button1Click
  6: len: 19, adr: 00447E68, name: Button2Click
  7: len: 19, adr: 00447FF8, name: Button3Click
  8: len: 19, adr: 00448020, name: Button4Click
  9: len: 19, adr: 00448040, name: Button5Click

Заранее благодарен.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

11-09-2007 16:56
1. Как отличить обычную процедуру, объявленную в секции Published формы, от объявленного там же обработчика события, например, типа TNotifyEvent?

Никак... По той простой причине, что они ничем не отличаются...

Ни один доступный источник не дает информации, как получить данные не о методах-свойствах, а просто о published-методах.

Основная ошибка... Нет методов-свойств... Есть свойства, являющиеся указателями на процедуры определенного типа. Например, OnClick - это всего лишь указатель на процедуру с одним параметром типа TObject, являющуюся методом какого-либо класса (кстати, не обязательно своего). Если ничего не назначено, он равняется nil, а если назначено, то там хранится указатель на соответствующую процедуру. Но это именно указатель, а не процедура... А процедура может быть любой, удовлетворяющая вышеописанному типу. Указатель на эту процедуру можно назначить либо в дизайн-тайме, либо в ран-тайме, даже более того, можно в ран-тайме по очереди назначать разные процедуры. В дизайн-тайме предлагаются процедуры только из раздела published и только соответствующего типа. Для этого и существует этот раздел и кроме обработчиков, которые нужны в выпадающем списке в инспекторе объектов в дизайн-тайме, других методов там быть не должно (это если делать по уму). Так что мне не понятна необходимость что-либо там различать. В ран-тайме можно назначать обработчиком любую доступную процедуру соответствующего типа и помещать их в раздел published нет никакой необходимости.
То, что обработчики "образуются" двойным кликом в испекторе объектов - это всего лишь избавление программиста от рутины и не более того. Никакими особыми свойствами полученные таким образом процедуры не обладают. Просто экономия времени. Все то-же самое можно набить ручками...
Попытаюсь проиллюстрировать все вышесказанное примером (скопируйте текст в соответствующие файлы):

Unit1.pas

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    RadioGroup1: TRadioGroup;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure RadioGroup1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Click0(Sender: TObject);
  private
    procedure Click1(Sender: TObject);
    procedure Click2(Sender: TObject);
  public
    procedure Click3(Sender: TObject);
  end;

  TOtherClass = class(TObject)
  public
    procedure SuperProcedure(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var Actions: array [0..4] of TNotifyEvent;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Actions[0] := Click0;
  Actions[1] := Click1;
  Actions[2] := Click2;
  Actions[3] := TOtherClass(nil).SuperProcedure;
  Actions[4] := Click3;
end;

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;

end.



Unit1.dfm

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 196
  ClientWidth = 288
  Color = clBtnFace
  Font.Charset = RUSSIAN_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'Arial'
  Font.Style = []
  OldCreateOrder = False
  Position = poDesktopCenter
  OnClose = FormClose
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 16
  object RadioGroup1: TRadioGroup
    Left = 32
    Top = 8
    Width = 217
    Height = 114
    Caption = #1055#1086' '#1082#1085#1086#1087#1082#1077
    Items.Strings = (
      #1056#1072#1079#1074#1077#1088#1085#1091#1090#1100
      #1042#1086#1089#1089#1090#1072#1085#1086#1074#1080#1090#1100
      'Hello, world!'
      #1055#1088#1086#1094#1077#1076#1091#1088#1072' '#1080#1079' '#1076#1088#1091#1075#1086#1075#1086' '#1082#1083#1072#1089#1089#1072
      #1047#1072#1082#1088#1099#1090#1100)
    TabOrder = 0
    OnClick = RadioGroup1Click
  end
  object Button1: TButton
    Left = 96
    Top = 144
    Width = 89
    Height = 25
    Caption = 'SuperButton'
    TabOrder = 1
    OnClick = Button1Click
  end
end


11-09-2007 08:15 | Вопрос к автору: запрос дополнительной информации
Хочу задать любимый вопрос: а зачем?
Может быть задачу можно решить проще.

11-09-2007 08:08
В рунтайме определить тип метода (в общем случае) никак.Тип определяется в дизан-тайме только если метод является значением какого либо свойства. Дизайнер же определяет тип по тексту.Так что GEO прав - никакой RTTY здесь не поможет, да vmtTable тоже, т.к не содержит списка параметров и их типов.

11-09-2007 06:18 | Сообщение от автора вопроса
Вы слышали про RTTY? Там хранится информация о типах в рантайме. В том числе и о свойствах из раздела published. Почитайте хелп про RTTY.

Про RTTI я, конечно же, слышал. Но! Ни один доступный источник не дает информации, как получить данные не о методах-свойствах, а просто о published-методах. Можно получить список полей, событий и т.д., а вот это - никак (может быть, я не знаю...). Обратите внимание, что в приведенном выше листинге НЕТ НИ ОДНОГО ОПЕРАТОРА из модуля TypInfo.pas. Может быть, существуют подобные способы и для моего случая? Может, кто-то умеет использовать эту таблицу методов (vmtMethodtable)?

11-09-2007 05:14
Похоже, что никак.
»вопрос КС №45705«

11-09-2007 04:31
>>>То есть вы хотите сказать, что в рантайме нет никакой возможности выяснить тип методаundefined
Вы слышали про RTTY? Там хранится информация о типах в рантайме. В том числе и о свойствах из раздела published. Почитайте хелп про RTTY. TypeInfo.pas модуль для работы c RTTY. С ее помошью можно получить любую информацию о свойствах процедурного типа, с описанием количества передаваемых параметров, их типа и т.п. в частности.

11-09-2007 04:16 | Сообщение от автора вопроса
То есть вы хотите сказать, что в рантайме нет никакой возможности выяснить тип метода и, например, при совпадении типов присвоить его подходящему обработчику? В таком случае - печально :-(
А, может быть, все-таки есть какая-то зацепка?

11-09-2007 03:25
>>> Как-то он различает эти методы?
Вы сами ответили на этот вопрос: "соответствуют этому обработчику по типу". То есть любой published-метод, являющийся процедурой и содержащий один параметр типа TObject, в Object Inspector попадет в список возможных обработчиков события TNotifyEvent.

Как Object Inspector определяет, что данный метод содержит один параметр типа TObject? Подозреваю, что он анализирует паскалевский текст.

11-09-2007 01:18 | Сообщение от автора вопроса
Дорогие товарищи, уважаемый Geo!

А как же тогда Object Inspector справляется  с этим? Как-то он различает эти методы? Ведь когда вы открываете ComboBox со списком методов, в нем отображаются только те методы, которые соответствуют этому обработчику по типу. Как бы это сделать подобным образом?

10-09-2007 09:21
А никак не отличить. Если процедура по типу не соответствует обработчику событий, то она гарантированно не является обработчиком событий. Если же процедура по типу соответствует обработчику какого-либо события, то она может являться обработчиком этого события, а может не являться. Чтобы процедура сатала обработчиком события, она должна быть указана в специальном свойстве, которое содержит указатель на обработчик события.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Жили у бабуси два веселых гуся. Один белый, другой КАКОЙ?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования