Форум: "Начинающим";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];
ВнизСоздание массива констант из указателей method pointers Найти похожие ветки
← →
Fosgen (2006-07-29 10:55) [0]Вопрос в следующем:
1. Есть класс TObject1
2. У этого класса имеется куча отднотипных методов (около 100), использующих соответственно поля и св-ва класса TObject1
3. Есть класс TObject2, имеющий св-во OnEvent, по типу совпадающее с методами класса TObject1
4. В процессе работы создается один объект класса TObject1, и много-много объектов класса TObject2. При создании множества объектов класса TObject2, им надо назначать в св-во OnEvent обработчики из класса TObject1.
5. Для этого счастья я планировал завести массив констант. Где будут храниться указатели на методы-обработчики класса TObject1... НО...
1) Создать такой массив на этапе компиляции не представляется возможным, поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны. Дельфя ругается.
2) Массив получается создать если предварительно объявить процедурный тип навроде TNotifyEvent и задать все методы-обработчики класса TObject1 как class procedure, но в этом случае они теряют доступ к св-вам и полям класса TObject1. Почему? Да фиг его знает... Я так этого и не понял, пробовал работать на уровне private\public\published - не помогает.
3) Была идея создать массив переменных где формировать указатели типа method pointers на методы-обработчики класса TObject1. Но в Дельфи я не обнаружил ни одной функции, по имени (либо еще как-то) возвращающей указатель на метод, а не просто нетипизированный указатель. Последний - никуда не впился...
В общем я свои идеи исчерпал, через case ... of либо if ... then делать присвоения 100 различных вариантов меня как-то ломает... Ну как-то тупо это получается...
Пожалуйста, подскажите что в таком случае можно сделать, либо есть какой-то вариант решения?
← →
Loginov Dmitry © (2006-07-29 16:35) [1]Букв слишком много...
← →
Пусик © (2006-07-29 16:58) [2]
> Loginov Dmitry © (29.07.06 16:35) [1]
> Букв слишком много...
Ну так не читай.
> Fosgen (29.07.06 10:55)
Сконструируй простейший пример для демонстрации твоей задачи и положи сюда, тогда можно будет разобраться в проблеме.
← →
tesseract © (2006-07-29 17:37) [3]> 3) Была идея создать массив переменных где формировать указатели
> типа method pointers на методы-обработчики класса TObject1.
> Но в Дельфи я не обнаружил ни одной функции, по имени (либо
> еще как-то) возвращающей указатель на метод, а не просто
> нетипизированный указатель. Последний - никуда не впился...
а через typecasting?
только процедырный тип должен быть один на всех.
а не проще TObject2 от Tobject1 унаследовать? и потом assign-ить?
← →
Fosgen (2006-07-29 20:56) [4]2: Пусик © (29.07.06 16:58) [2]
Значит так по вариантам:
В одном модуле (всегда):type TObject2 = class
private
public
Event: Byte;
FonClick: TGLNotify;
published
property onClick: TGLNotify read FonClick write FonClick;
end;
В другом модуле (module2):
Вариант № 1:
Uses module2;
type TObject1 = class
FrameCount: Word;
Visible: Boolean;
Elements: array of TObject2;
private
procedure CheckBoxChange(Sender: TGLWidget);
procedure CheckChange(Sender: TGLWidget);
procedure NoAction(Sender: TGLWidget);
procedure ChgHullCond(Sender: TGLWidget);
end;
const
EventHandlers: array[0..100] of TGLNotify =
(NoAction, ChgHullCond, ChgHullCondT, ....
Вот на последнюю строку она и ругается. В принципе понятно почему.
Вариант № 2:
Uses module2;
type TGLNotify = procedure(Sender: TGLWidget) of object;
type TObject1 = class
public
FrameCount: Word;
Visible: Boolean;
Elements: array of TObject2;
published
class procedure CheckBoxChange(Sender: TGLWidget);
class procedure CheckChange(Sender: TGLWidget);
class procedure NoAction(Sender: TGLWidget);
class procedure ChgHullCond(Sender: TGLWidget);
end;
const
EventHandlers: array[0..100] of TGLNotify =
(TObject1.NoAction, TObject1.ChgHullCond, TObject1.ChgHullCondT, ....
В этом варианте из обработчиков TObject1.NoAction, TObject1.ChgHullCond и т.д. не видно св-в FrameCount: Word; Visible: Boolean и т.д.
2: tesseract © (29.07.06 17:37) [3]
а не проще TObject2 от Tobject1 унаследовать? и потом assign-ить?
Нет не проще. И совсем из другой оперы. Зачем мне допустим делать кнопку потомком формы (как пример)? А обработчики формы-то надо присваивать на события кнопки...
← →
Fosgen (2006-07-29 21:01) [5]Косяк мой. В указанном коде во втором варианте строку:
type TGLNotify = procedure(Sender: TGLWidget) of object;
надо перенести в module2, ну и класс TGLWidget считать равным TObject2 это одно и то же, только заменить забыл...
← →
jack128 © (2006-07-30 17:19) [6]Fosgen (29.07.06 10:55)
1) Создать такой массив на этапе компиляции не представляется возможным, поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны.
адреса как раз известны. P := @TObject.SameMethod. Нно событие - это не только адрес метода, но и указатель на собственно объект. А этого вот этого объекта на этапе компиляции еще нет.
Fosgen (29.07.06 10:55)
все методы-обработчики класса TObject1 как class procedure, но в этом случае они теряют доступ к св-вам и полям класса TObject1. Почему?
потому что ты они стали классовыми методами. То есть связанными с классом, а конкретным экземпляром этого класса(читай с объектом).
Как это делается:var
Obj1: TObject1;
Handlers: array [0..100 - 1] of TNotifyEvent;
Obj2Arr: array [0..100 - 1] of TObject2;
begin
// Гдето выше объект Obj1 должен быть уже создан!!!!!!!!!!!!!
Handlers[0] := Obj1.CheckBoxChange;
Handlers[1] := Obj1.CheckChange;
Handlers[2] := Obj1.NoAction;
Handlers[3] := Obj1.ChgHullCond;
// и так далее...
for I := low(Obj2Arr) to high(Obj2Arr) do
begin
Obj2Arr[I] := TObject2.Create;
Obj2Arr[I].SameEvent := Handlers[I];
end;
end;
← →
Fosgen (2006-07-30 20:42) [7]2: jack128 © (30.07.06 17:19) [6]
Уважаемый, а Вы внимательно читаете предыдущие посты?
адреса как раз известны. P := @TObject.SameMethod. Нно событие - это не только адрес метода, но и указатель на собственно объект. А этого вот этого объекта на этапе компиляции еще нет.
Вроде я еще в первом своем посте так и написал:
поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны...
А т.к. Ваш указательP := @TObject.SameMethod
является относительным TObject, то на выходе получите Вы только тип Pointer, который интереса в данном контексте никому не представляет.
То есть связанными с классом, а конкретным экземпляром этого класса(читай с объектом).
И с каким именно классом\объектом (по примеру) они стали связаны?
Как это делается:
Знаете ояпть же, как написано в ПЕРВОМ посте: делать присвоения 100 различных вариантов меня как-то ломает
Если Вам такое решение нравится - милости прошу, но для меня это не является ответом Как это делается:. Потому что гибкости в таком подходе - никакой. Количество методов изменилось, процесс заполнения массива тоже переделывай... Да и зачем тогда массив-то? В чем его смысл? Через case...of сразу и присваивай методы. Тем более что Вы не поняли - я не утверждал чтоObj2Arr[I].SameEvent := Handlers[I];
Будет применимо всегда. Тем более что даже количество элементов Obj2Arr может различаться (превышать) с кол-вом элементов Handlers... И не всегда первый элемент Obj2Arr должен содержать ссылку на первый элемент Handlers.
← →
Джо © (2006-08-01 05:02) [8]Не уверен, что я верно понял задачу.
Вот что-то в таком роде подойдет?
...
TObject2 = class
private
FOnEvent: TOnEventProc;
public
property OnEvent: TOnEventProc read FOnEvent write FOnEvent;
end;
TObject1 = class
published
procedure A (Sender: TObject2);
procedure B (Sender: TObject2);
procedure C (Sender: TObject2);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
MethodNames: array [1..3] of string =
(
"A",
"B",
"C"
);
var
Objects2: array [1..3] of TObject2;
Object1: TObject1;
procedure CreateAssignEventHandlers;
var
I: Integer;
MP: Pointer;
Met: TMethod;
begin
for I := Low(Objects2) to High (Objects2) do
begin
Objects2[I] := TObject2.Create;
MP := Object1.MethodAddress(MethodNames[I]);
Met.Code := MP;
Met.Data := Objects2[I];
Objects2[I].OnEvent := TOnEventProc(Met);
end;
end;
{ TObject1 }
procedure TObject1.A(Sender: TObject2);
begin
ShowMessage ("A")
end;
procedure TObject1.B(Sender: TObject2);
begin
ShowMessage ("B")
end;
procedure TObject1.C(Sender: TObject2);
begin
ShowMessage ("C")
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
// проверка
for I := Low(Objects2) to High (Objects2) do
Objects2[I].OnEvent (Objects2[I]);
end;
initialization
Object1 := TObject1.Create;
CreateAssignEventHandlers;
finalization
// ну, тут удаляем все объекты, это я опустил
end.
← →
Джо © (2006-08-01 05:03) [9]Перед этим кодом, разумеется:
typeTObject2 = class;
TOnEventProc = procedure (Sender: TObject2) of object;
← →
Джо © (2006-08-01 05:05) [10]Всё, точно спать пора... В процедуре CreateAssignEventHandlers вот так:
Met.Code := MP;
Met.Data := Object1;
← →
Fosgen (2006-08-01 20:14) [11]Однако!
Благодарствую, Джо!
Решение, предложенное тобой, по крайней мере удовлетворяет все вышеизложенные конфликты. Проверить корректность работы структурыMP := Object1.MethodAddress(MethodNames[I]);
Met.Code := MP;
Met.Data := Objects2[I];
Objects2[I].OnEvent := TOnEventProc(Met);
Еще не успел, но как минимум все компилируется! Т.е. нет несовпадения типов и нет проблем с доступом к полям и переменным.
А я как раз и не мог найти тип, способный хранить двойной указатель на метод. Оказывается есть прямо TMethod...
Да, и откуда ты выкопал такую структуру:TOnEventProc(Met);
??? Очень интересно, даже нигде намека не встречал... Но компилируется, млин!!!
Спасибо!!!
← →
Джо © (2006-08-01 21:02) [12]> Проверить корректность работы структуры
>
> Met.Data := Objects2[I];
Тут я допустил машинальную ошибку. Исправился в посте [10] :)
← →
DiamondShark © (2006-08-01 23:24) [13]{$M+}
TObject1 = class
published
procedure A (Sender: TObject2);
procedure B (Sender: TObject2);
procedure C (Sender: TObject2);
end;
{$M-}
← →
Джо © (2006-08-01 23:37) [14]> [13] DiamondShark © (01.08.06 23:24)
> {$M+}
Оно дляMethodAddress
не нужно :)
← →
DiamondShark © (2006-08-01 23:53) [15]И ведь правда не нужно. :-Х
← →
Fosgen (2006-08-02 09:58) [16]2: Джо © (01.08.06 21:02) [12]
Да там я разумеется исправил как должно быть. В конце концов, если я с такими вопросами на форум выпадаю, то думаю - не безнадежно тупой и уж основы-то знаю. :)
Однако, решение искалось почти две недели, за последнюю было "опрошено" около 10 программеров в живую, и сколько-то человеков просмотрело вопрос на форуме, а предложить настоящее решение смог только один... Мда...
Спасибо, Джо!
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.046 c