Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.037 c
2-1131903490
zxc
2005-11-13 20:38
2005.12.04
I/0 error 32


1-1131039262
Ins!7t
2005-11-03 20:34
2005.12.04
Ошибка- The compiler could not find the given identifier???


14-1131948554
Ega23
2005-11-14 09:09
2005.12.04
С днем рождения! 14 ноября


14-1131692903
Ega23
2005-11-11 10:08
2005.12.04
С днем рождения! 11 ноября


8-1120591323
zsergey
2005-07-05 23:22
2005.12.04
Как анимированный Gif вставить в канву?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский