Есть библиотека dll, не содержащаю никаких классов — одни переменные и константы. По ходу выполнения одной из функций создается пункт меню основного приложения. Вопрос в том, как создать событие OnClick для этого пункта меню. Все коды, которые я просматривал делаются так: в проект включается какой-то класс, например, TForm1, и у него уже прописывается событие. Затем это событие назначается кому надо... ))
А мне не нужно создавать класс, я хочу написать, например, так:
library MyLib;
var MenuItem: TMenuItem;
MainMenu: TMainMenu;
procedure Clicked;
begin
SowMessage('Hello world!');
end;
begin
MenuItem:=TMenuItem.Create(MainMenu);
MenuItem.Caption:='File';
MainMenu.Items.Add(MenuItem);
MenuItem.OnClick:=Clicked;
end.
Или так нельзя и придется создавать класс пункта меню? Оченно не хотелось бы...
Помогите, буду очень признателен!
Здравствуйте, vasketsov, Вы писали:
V>Здравствуйте, LeXa24, Вы писали:
LX>>Ну собственно так и делают. Вот только наверное Clicked с параметром Sender:TObject
V>Ага, а Procedure — то же, что и Procedure of Object ?
Сам то понял что сказал? V>Короче, я так не думаю, но на 0 не тянет .
Ну предположим ты не хочешь получать Sender. И как ты будешь узнавать на что ты тыкнул?
Или есть большое желание писать под каждый пункт свою процедуру?
В общем вот код, пробуй. Все прекрасно работает.
procedure TForm1.DoSomething(Sender:TObject);
begin
ShowMessage('NEW');
end;
procedure TForm1.FormShow(Sender: TObject);
var
MenuItem:TMenuItem;
begin
MenuItem:=TMenuItem.Create(MainMenu1);
MenuItem.Caption:='New';
MenuItem.OnClick:=DoSomething;
MainMenu1.Items.Add(MenuItem);
end;
Здравствуйте, LeXa24, Вы писали:
V>>Ага, а Procedure — то же, что и Procedure of Object ? LX>Сам то понял что сказал?
Понял.
Тип обработчика этого события — procedure (Sender:TObject) of object;
А это не то же самое, что procedure (Sender:TObject);
LX>В общем вот код, пробуй. Все прекрасно работает.
Вот так — да, работает, никто и не спорит, а как сначала написал — без объекта — не будет.
Не согласен с каждым ответом!
Во всех присутствует явно или неявно класс TForm1 (или еще какой-нть). А как обойтись без них? Вот в чем суть вопроса...
Re[2]: Динамическое создание событий
От:
Аноним
Дата:
13.01.03 18:41
Оценка:
Здравствуйте, GrayWolf, Вы писали:
GW>Во всех присутствует явно или неявно класс TForm1 (или еще какой-нть). А как обойтись без них? Вот в чем суть вопроса...
Метод класса отличается от обычной процедуры тем, что в него неявно передается указатель на Self первым параметром. Поэтому если уж так хочется использовать простую процедуру вместо метода класса (зачем — это уже другой вопрос), то сделай первый параметр фиктивным TObject-ом:
procedure DoOnClick(AFake: TObject);
begin
ShowMessage('test');
end;
procedure TForm1.FormCreate(Sender: TObject);
var
LHandler: TNotifyEvent;
P: Pointer;
begin// Танец с бубном
P := @DoOnClick;
Move(P, LHandler, SizeOf(Pointer));
// Присвоение
Button1.OnClick := LHandler;
end;
Но, имхо, это есть извращение, к тому же теряется указатель на Self.
Здравствуйте, GrayWolf, Вы писали:
GW>Не согласен с каждым ответом! GW>Во всех присутствует явно или неявно класс TForm1 (или еще какой-нть). А как обойтись без них? Вот в чем суть вопроса...
Ну тогда, наверное, придется пересмотреть архитектуру приложения... То есть, если вчерне набросать, то будем иметь что-то вроде (сорри за Билдеровский код):
TMenuItem* MenuItem= new TMenuItem(MainMenu);
MenuItem->Caption = "File";
MainMenu->Items->Add(MenuItem);
MenuItem->Tag = 1; // уникальное число
MenuItem->OnClick = SharedClickHandler;
void __fastcall TForm1::SharedClickHandler(TObject* Sender)
{
TMenuItem* mi = dynamic_cast<TMenuItem*>(Sender); // if(Sender is TMenuItem)if(mi)
{
if(mi->Tag == 1)
{
// вызываем одну функцию
}
else ....
}
}
Как хранить указатели на функции — дело ваше... Есть масса удобных способов и классов, например, тот-же TList. Удачи!
procedure TForm1.FormCreate(Sender: TObject);
var
LHandler: TNotifyEvent;
P: Pointer;
begin
P := @DoOnClick;
Move(P, LHandler, SizeOf(Pointer));
Button1.OnClick := LHandler;
end;
Да, так можно делать. Если мы точно не собираемся использовать в нашей процедуре переданный фейковый указатель, то никаких проблем не возникнет. Однако процедура Move выглядит небезопасной. Борланд позаботилась о нас, грешных, объявив в юните SysUtils тип
TMethod = record
Code, Data: Pointer;
end;
Таким образом, можно переписать код вот так:
procedure TForm1.FormCreate(Sender: TObject);
var
LHandler: TNotifyEvent;
begin
with TMethod(LPhandler) do
begin
Data:= nil;
Code:= @DoOnClick;
end;
Button1.OnClick := LHandler;
end;
... << RSDN@Home 1.0 beta 3 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vasketsov, Вы писали:
LX>>В общем вот код, пробуй. Все прекрасно работает. V>Вот так — да, работает, никто и не спорит, а как сначала написал — без объекта — не будет.
Писал не я. Как раз я и написал, что Sender добавить надо!
— сколько программистов надо чтобы заменить сгоревшую лампочку?
— сколько не бери, а лампочку не поменять — проблема аппаратная, программным путем не решается...
Здравствуйте, vasketsov, Вы писали:
V>А функция класса (в смысле, со словом class) не подойдет? V>Это если создавать класс не хочется, но зато без извратов.
Увы, создавать класс все же придется. То есть минимальный код для обработки TNotifyEvent такой:
type TDummyHandleClass = class
class Procedure HandleIt(Sender: TObject);
end;
class procedure TDummyHandleClass.HandleIt(Sender: TObject);
begin///end;
... << RSDN@Home 1.0 beta 3 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vasketsov, Вы писали:
А-а, я просто всегда встаю в тупик, когда начинаются перемешивания классов и объектов. Все верно. создавать не надо объект! В этом плюс — классы не надо потом уничтожать...
... << RSDN@Home 1.0 beta 3 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Честно говоря, вы меня порадовали...
Так все просто... Конечно, это небольшой изврат, но главное, что это работает.
Что впрочем и требуется. Еще бы набрать хоть чуть времени и потестить код, что получилось...
Но все равно, всем спасибо