Форум: "Основная";
Текущий архив: 2005.12.04;
Скачать: [xml.tar.bz2];
ВнизДинамический OnClick Найти похожие ветки
← →
msguns © (2005-11-02 18:28) [0]В рантайме создается TPopUpMenu с соответствующими итемами. Как назначить событию OnClick этих итемов ругулярные процедуры ?
Все происходит в библиотечном юните, где нет type
Спасибо за помощь
← →
DiamondShark © (2005-11-02 18:37) [1]z: TMethod;
z.Code := @MyRegularProc;
z.Data := nil;
Item.OnClick := TNotifyEvent(z);
procedure MyRegularProc(Self: TObject; Sender: TObject)
← →
Leonid Troyanovsky © (2005-11-02 18:40) [2]
> DiamondShark © (02.11.05 18:37) [1]
> z.Data := nil;
IMHO, все же, не nil.
--
Regards, LVT.
← →
DiamondShark © (2005-11-02 18:43) [3]
> IMHO, все же, не nil.
Можно и не nil.
Разницы-то...
← →
Leonid Troyanovsky © (2005-11-03 09:22) [4]
> DiamondShark © (02.11.05 18:43) [3]
> Можно и не nil.
> Разницы-то...
Небольшая разница, все же, есть.
Для обработчиков методы и свойства содержащего их класса привычно
доступны. Противные же случаи толкают на грех глобализма.
--
Regards, LVT.
← →
msguns © (2005-11-03 10:12) [5]Вот такой код:
procedure DBGridEx_MenuClick(Self: TObject; Sender: TObject);
begin
Досюда дело не доходит вообще
ShowMessage(TMenuItem(Sender).Caption);
end;
procedure DBGridEx_ShowHideColumn(Grid: TDBGrid; TitleColumn: TColumn);
// Позволяет добавить или убрать колонку грида
// Вызов этой процедуры следует выполнять по событию OnTitleClick грида
var
pmn: TPopupMenu;
pmi: TMenuItem;
X,Y: integer;
i: integer;
e: TMethod;
begin
// Определить текущую колонку грида
pmn := TPopupMenu.Create(nil); // Создать всплывающее меню
e.Code := @DBGridEx_MenuClick;
e.Data := nil;
with pmn do
begin
pmi := TMenuItem.Create(pmn);
pmi.Caption := "Убрать колонку";
pmi.OnClick := TNotifyEvent(e);
Items.Add(pmi);
pmi := TMenuItem.Create(pmn);
pmi.Caption := "Добавить колонку";
pmi.OnClick := TNotifyEvent(e);
Items.Add(pmi);
TitleColumn.PopupMenu := pmn;
// Открыть меню под (над) заголовком колонки
with TDBGridCrack(Grid) do
Y := Grid.ClientOrigin.Y+CellRect(Col,Row).Bottom-CellRect(Col,Row).Top;
X := Grid.ClientOrigin.X;
for i := 0 to TitleColumn.Index-1 do
if Grid.Columns[i].Visible then
X := X+Grid.Columns[i].Width+1;
pmn.Popup(X,Y);
Free;
end;
end;
не работает.
Вернее, нет реакции на клик в меню.
← →
Игорь Шевченко © (2005-11-03 10:33) [6]msguns © (03.11.05 10:12) [5]
Вот такой код, например, работает:unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, StdCtrls;
type
TForm1 = class(TForm)
PopupMenu: TPopupMenu;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure MenuEventHandler (Self: TObject; Sender: TObject);
begin
ShowMessage ("Event handler traps an event");
end;
procedure TForm1.Button1Click(Sender: TObject);
var
mi: TMenuItem;
method: TMethod;
begin
mi := TMenuItem.Create (PopupMenu);
mi.Caption := "Catch me!";
PopupMenu.Items.Add (mi);
method.Code := @MenuEventHandler;
method.Data := nil;
mi.OnClick := TNotifyEvent(method);
end;
end.
← →
msguns © (2005-11-03 11:18) [7]Ну да !
В твоем примереButton1Click
является методом класса, мне же надо "засунуть" в событие регулярную процедуру. Ибо в юните, отрывок из которого я привел, нет формы (это одна из процедур библиотечного юнита универсального назначения).
Такой способ я успешно использовал в процедурах другого библ.юнита, который динамически создает формы-диалоги. Там, ессно, есть объявление форм и все работает !
А как быть в этом случае ? У Тексейры с Пачеко такого я не нашел, поиск в хэлпе и MSDN (TMethod) ничего не дал ;(
← →
Игорь Шевченко © (2005-11-03 11:30) [8]msguns © (03.11.05 11:18) [7]
В моем примере ButtonClick, как ты сам понимаешь, является создателем элемента меню, поэтому является он методом объекта, не является - какая нафиг разница ? Обработчик нажатия на меню не является методом класса, как ты, опять же, можешь видеть из моего кода, так что я не совсем понимаю, в чем разница между твоим и моим кодом.
← →
Leonid Troyanovsky © (2005-11-03 11:47) [9]
> msguns © (03.11.05 11:18) [7]
> Такой способ я успешно использовал в процедурах другого
> библ.юнита, который динамически создает формы-диалоги. Там,
> ессно, есть объявление форм и все работает !
Ну, ты ходил-ходил и заслуженно наступил на грабли.
Если procedure DBGridEx_ShowHideColumn объявлена в dll,
то я сильно сомневаюсь в работоспособности тамошнего меню.
Как минимум, создать его следует в exe.
А как максимум - даже неохота язык мозолить.
--
Regards, LVT.
← →
Игорь Шевченко © (2005-11-03 12:03) [10]Leonid Troyanovsky © (03.11.05 11:47) [9]
> Если procedure DBGridEx_ShowHideColumn объявлена в dll,
> то я сильно сомневаюсь в работоспособности тамошнего меню.
>
> Как минимум, создать его следует в exe.
Я очень извиняюсь, а разве GExperts не подобным образом работает ? В смысле, с процедурами обработки меню в DLL.
← →
Leonid Troyanovsky © (2005-11-03 12:19) [11]
> Игорь Шевченко © (03.11.05 12:03) [10]
> > Как минимум, создать его следует в exe.
> Я очень извиняюсь, а разве GExperts не подобным образом
> работает ? В смысле, с процедурами обработки меню в DLL.
>
А чего ты извиняешься? :)
Это мне неудобно, что я не щупал GExperts.
Но, думаю, что дело не в месте размещения кода,
а в банальных дубликактах глобальных переменных,
в т.ч. и, скажем, для окна popup menues.
--
Regards, LVT.
← →
jack128 © (2005-11-03 12:27) [12]Leonid Troyanovsky © (03.11.05 12:19) [11]
> Я очень извиняюсь, а разве GExperts не подобным образом
> работает ? В смысле, с процедурами обработки меню в DLL.
Его dll"ки скомпилированы с ран-тайм пакетами, со всеми втекающими и вытекающими..
← →
Игорь Шевченко © (2005-11-03 12:33) [13]jack128 © (03.11.05 12:27) [12]
> Его dll"ки скомпилированы с ран-тайм пакетами
Кстати, да :)
← →
msguns © (2005-11-03 12:36) [14]>Игорь Шевченко © (03.11.05 11:30) [8]
Прошу прощения, невнимательно посмотрел (почта задрала !)
В твоем примере само TPopupMenu объявлено в интерфейсе, у меня же такого объявления быть не может ;(
Сейчас плюнул на универсальность и делаю все в самом приложении. И та же картина ! На клик реакции нету !
Уже пробовал в форме объявить обработчик клика на пункте меню и его назначить динамически созданным пунктам динамически созданного же попменю - реакции НОЛЬ ! При клике в меню просто оно закрывается, а до моего обработчика дело не доходит ;((
← →
msguns © (2005-11-03 12:43) [15]В общем получается интересная весчь.
Если я кидаю на форму попменю, в нем определяю оно подменю и ему создаю OnClick, а затем в процедуре чищу, заполняю нужными итемами и назначаю им этот же обработчик, то все лихо пляшет !
СтОит же мне попытаться создать попменю динамически и проделать с ним то же самое, но с регулярной процедурой (или даже тем же самым обработчиком), как реакции на клик просто нетути.
Блин, явно не хватает понимания чего-то фундаментального ;))
← →
msguns © (2005-11-03 12:51) [16]Видимо все же дело в "перехватчике" сообщения клика. Стоп !!! Щас попробую...
← →
Игорь Шевченко © (2005-11-03 12:56) [17]
> СтОит же мне попытаться создать попменю динамически
И назначить его тому компоненту, при клике на который должно всплывать меню....
← →
msguns © (2005-11-03 13:14) [18]>Игорь Шевченко © (03.11.05 12:56) [17]
>И назначить его тому компоненту, при клике на который должно всплывать меню....
Все значительно интереснее...
Значицца такочки:
1. Кидаю на форму пупменю, определяю в ем один пункт и для это пункта в OI даблкликом определяю обработчик Click1.
В процедуре чищу и заполняю это меню, назначая пунктам OnClick := Click1.
Запускаю - на ура !
2. В процедуре вместо "кинутого" пупменю создаю пупменю2, для него проделываю то же самое. Запускаю - лейся, песня !
Ага !, подумал Штирлиц, нащупав наган. Создаю ручками обработчик Click2, полностью идентичный Click1.
В проце заменяюOnClick := Click1
наOnClick := Click2
Запускаю - болт ! Убираю пупап2, вставляю вместо него "кинутый" пупап.
Запускаю - БОЛТ !
В OI заменяю (выбором из списка) Click1 на Click2 - БОЛТ ! В обоих вариантах !!!. Возвращаю Click1 - БОЛТ
Что ж это делается-то, люди добрые ? А ?
← →
Игорь Шевченко © (2005-11-03 13:20) [19]msguns © (03.11.05 13:14) [18]
Если не трудно, тоже самое, но без слесарных терминов
← →
msguns © (2005-11-03 13:35) [20]>Игорь Шевченко © (03.11.05 13:20) [19]
>Если не трудно, тоже самое, но без слесарных терминов
Вот какие мы серьезные ;))
Дело в том, что все работает (имеется в виду то, что нажатие на левую кл.мыши благополучно попадает в обработчик OnClick пункта меню), если я сам это обработчик получил "даблкликом" в OI
При этом не играет роли, какой объект TPopupMenu я задействую в своей процедуре: тот, который визуально "положен" на форму либо созданный динамически в самой процедуре.
Но как только я сменил обработчик (неважно как, то ли в OI, то ли в коде), обработчик на это событие не реагирует.
← →
Игорь Шевченко © (2005-11-03 13:47) [21]msguns © (03.11.05 13:35) [20]
Что в моем коде отличается от твоего ? Я создаю динамически элемент PopupMenu (MenuItem), динамически же присваиваю ему событие на свойство OnClick, все работает.
Может быть, ты по шагам будешь двигаться, так оно и выяснится, что и где ты делаешь не так.
← →
jack128 © (2005-11-03 13:52) [22]Приведи dfm и pas файлы с НЕрабочем вариантом.
← →
msguns © (2005-11-03 13:54) [23]Вот полный текст процедуры в варианте с визуальным меню:
procedure TfrmChild.ShowHideGridColumn(Grid: TDBGrid; TitleColumn: TColumn);
// Позволяет добавить или убрать колонку грида
// Вызов этой процедуры следует выполнять по событию OnTitleClick грида
var
pmi: TMenuItem;
X,Y: integer;
i: integer;
m: TMethod;
begin
// Определить текущую колонку грида
LoadHideColumns(Grid,ListColumns);
with pmnuGridCol do
begin
Items.Clear;
pmi := TMenuItem.Create(pmnuGridCol);
pmi.Caption := "Убрать колонку";
pmi.OnClick := mniDelColClick;
Items.Add(pmi);
if ListColumns.Count>0 then
begin // Создать второй пункт меню
pmi := TMenuItem.Create(pmnuGridCol);
pmi.Caption := "Добавить колонку";
Items.Add(pmi);
for i := 0 to ListColumns.Count-1 do
begin
pmi := TMenuItem.Create(pmnuGridCol);
pmi.Caption := PColDef(ListColumns[i])^.ColName;
pmi.OnClick := mniDelColClick;
Items[Items.Count-1].Add(pmi);
end;
end;
// Открыть меню под (над) заголовком колонки
with TDBGridCrack(Grid) do
Y := Grid.ClientOrigin.Y+CellRect(Col,Row).Bottom-CellRect(Col,Row).Top;
X := Grid.ClientOrigin.X;
for i := 0 to TitleColumn.Index-1 do
if Grid.Columns[i].Visible then
X := X+Grid.Columns[i].Width+1;
Popup(X,Y);
//Free;
end;
end;
СтрокаFree
как ты понимаешь, осталась от варианта с динамическим меню. Если ее откомментарить, то до AV меню раскроется и на клик реакции не будет. В приведенном же виде реакция есть.
Это один из непонятных мне моментов. Другой заключался в отказе при замене обработчика на аналогичный. Все равно когда, в дизайне или в рантайме.
← →
jack128 © (2005-11-03 14:03) [24]Ты можешь сделать такой вариант, чтобы я всавил код, нажал f9 и выледз твой глюк ??
msguns © (03.11.05 13:54) [23]
то до AV меню раскроется и на клик реакции не будет
Естественно не будет. Меню то уже будет уничтожено.
← →
msguns © (2005-11-03 14:05) [25]>jack128 © (03.11.05 13:52) [22]
>Приведи dfm и pas файлы с НЕрабочем вариантом.
Они шибко большие.
Ладно, спасибо всем за участие и сочувствие. Перенес процедуру в рабочий проект и решил проблему. Жаль, что не вышло с укиверсализацией, позже подумаю..
← →
Leonid Troyanovsky © (2005-11-03 15:08) [26]
> msguns © (03.11.05 14:05) [25]
> Перенес процедуру
> в рабочий проект и решил проблему. Жаль, что не вышло с
> укиверсализацией, позже подумаю..
И где тут универсализация?
Если используемые гриды нуждаются в симбиозе с меню,
то, IMHO, следует сделать их наследниками одного прообраза.
А сделать универсальный обработчик меню на все случаи жизни,
все равно, особого смысла не имеет.
Во всяком случае, пользы от этого будет куда меньше,
чем, скажем, от механизма Actions.
--
Regards, LVT.
← →
msguns © (2005-11-03 16:34) [27]>Leonid Troyanovsky © (03.11.05 15:08) [26]
>И где тут универсализация?
В данном случае ее сделать и не получилось
>А сделать универсальный обработчик меню на все случаи жизни,
все равно, особого смысла не имеет.
Это не обработчик меню, а набор функций (процедур) для манипулирования гридами и данными в этих гридах. В частности, процедуры удаления-добавления колонок в дбгрид, сохранения-восстановления текущей конфигурации грида, поиска-сортировки, вывода Excel содержимого отображенных полей датасета, подсчета сумм по колонке и т.д., т.п.
В одной из процедур я хотел сделать "прятание"-показ колонок через меню непосредственно под/над "кликнутым" заголовком, с помощью которого юзер может либо спрятать текущую (кликнутую) колонку, либо добавить в этом месте одну из "спрятанных".
← →
evvcom © (2005-11-03 16:42) [28]У тебя похоже где-то что-то перетирается или не туда записывается. Включи использование отладочных DCU, поставь бряк на if Assigned(FOnClick) и посмотри, чему он там равен. Наверняка nil.
← →
Leonid Troyanovsky © (2005-11-03 16:45) [29]
> msguns © (03.11.05 16:34) [27]
> Это не обработчик меню, а набор функций (процедур) для манипулирования
> гридами и данными в этих гридах. В частности, процедуры
> удаления-добавления колонок в дбгрид, сохранения-восстановления
> текущей конфигурации грида, поиска-сортировки, вывода Excel
> содержимого отображенных полей датасета, подсчета сумм по
> колонке и т.д., т.п.
Все перечисленное свидельствует лишь в пользу создания некоего
прообраза, от которого и будут наследоваться все используемые гриды.
> В одной из процедур я хотел сделать "прятание"-показ колонок
> через меню непосредственно под/над "кликнутым" заголовком,
> с помощью которого юзер может либо спрятать текущую (кликнутую)
> колонку, либо добавить в этом месте одну из "спрятанных".
<нудно>
Для этого упомянутый прообраз снабжается неким индексированным
свойством (постой-ка, а почему это не TColumn.Visible?), которое
устанавливается посредством некоего action, назначаемоего некоему мню.
</нудно>
--
Regards, LVT.
← →
jack128 © (2005-11-03 16:51) [30]evvcom © (03.11.05 16:42) [28]
if Assigned(FOnClick) и посмотри, чему он там равен. Наверняка nil.
До туда код тоже не дойдет. Когда придет WM_COMMAND форма полезет искать меню с соответствующим ID"шником, чтобы вызвать его Click, но так как меню уже будет уничтожено, то форма ничего не найдет. На этом дело и заглохнет..
← →
Leonid Troyanovsky © (2005-11-03 16:51) [31]
> Leonid Troyanovsky © (03.11.05 16:45) [29]
> Для этого упомянутый прообраз снабжается неким индексированным
> свойством (постой-ка, а почему это не TColumn.Visible?),
> которое
> устанавливается посредством некоего action, назначаемоего
А.. да. Еще необходимо сделать обработчик клика на заголовке.
Создание симбиоза с меню, которое будет всплывать при
клике на оном - факультативно.
Ну, и , конечно, свойство - ShowPopupMenuBelow(Above).
--
Regards, LVT.
← →
Экспериментатор (2005-11-05 12:03) [32]Сделай в initialization модуля создание PopupMenu
в finalization - его Free
а в своих функциях используй его следующим образом:
сначала Очищай Items , потой его заполняй новыми пунктами и присваивай им обработчики, никаких Free после при вызова Popup нельзя делать.
Посмотри внимательно на procedure TPopupMenu.Popup(X, Y: Integer);
в нем вызывается
TrackPopupMenu(FItems.Handle, AFlags, X, Y, 0 { reserved }, PopupList.Window, nil);
как ты думаешь для чего?
← →
Экспериментатор (2005-11-05 12:20) [33]в догонку:
при создании Menu добавляется в PopupList
при уничтожении - удаляется,
И вот часть оконной процедуры объекта TPopupList
procedure TPopupList.WndProc(var Message: TMessage);
var
I, Item: Integer;
MenuItem: TMenuItem;
FindKind: TFindItemKind;
ContextID: Integer;
Canvas: TCanvas;
SaveIndex: Integer;
DC: HDC;
begin
case Message.Msg of
WM_COMMAND:
for I := 0 to Count - 1 do
if TPopupMenu(Items[I]).DispatchCommand(Message.wParam) then Exit;
WM_INITMENUPOPUP:
for I := 0 to Count - 1 do
with TWMInitMenuPopup(Message) do
if TPopupMenu(Items[I]).DispatchPopup(MenuPopup) then Exit;
WM_MENUSELECT:
with TWMMenuSelect(Message) do
begin
FindKind := fkCommand;
if MenuFlag and MF_POPUP <> 0 then FindKind := fkHandle;
for I := 0 to Count - 1 do
begin
if FindKind = fkHandle then
begin
if Menu <> 0 then
Item := GetSubMenu(Menu, IDItem) else
Item := -1;
end
else
Item := IDItem;
MenuItem := TPopupMenu(Items[I]).FindItem(Item, FindKind);
if MenuItem <> nil then
begin
Application.Hint := GetLongHint(MenuItem.Hint);
Exit;
end;
end;
Application.Hint := "";
end;
и т.д.
Делай выводы
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.12.04;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.052 c