Newsgroup: it.comp.lang.delphi
Titolo: Popup Menu dinamico

Salve,
Creo a runtime un popupmenu.
Quasi tutto funziona, il menu appare al punto giusto con la lista giusta.
Pero` non viene chiamato l' evento onClick. Perche`?
Di sotto il frammento del programma responsabile:
function Tdmmain.TreeDragDropPopupMenu(const 
aPopupPoint:TPoint):TDragDropActions;
var
   PM:TPopupMenu;
   Item:TMenuItem;
begin
   PM:=TPopupMenu.Create(nil);
   try
     Item:=TMenuItem.Create(PM);
     Item.Caption:=tddmiMove;
     Item.OnClick:=MenuItemClick;
     PM.Items.Add(Item);
     Item:=TMenuItem.Create(pm);
     Item.Caption:=tddmiCopy;
     Item.OnClick:=MenuItemClick;
     pm.Items.Add(Item);
     Item:=TMenuItem.Create(pm);
     Item.Caption:='-';
     pm.Items.Add(Item);
     Item:=TMenuItem.Create(pm);
     Item.Caption:=tddmiCancel;
     Item.OnClick:=MenuItemClick;
     pm.Items.Add(Item);
     pm.Popup(aPopupPoint.X,aPopupPoint.Y);
     Result:=FddAction;
   finally
     pm.Free;
   end;
end;
procedure TdmMain.MenuItemClick(Sender:TObject);
var
   MenuItem:TMenuItem;
begin
   if not (Sender is TMenuItem) then
     exit;
   MenuItem:=TMenuItem(Sender);
   if MenuItem.Caption=tddmiCopy then
     FddAction:=ddaCopy
   else if MenuItem.Caption=tddmiMove then
     FddAction:=ddaMove
   else FddAction:=ddaNone;
end;
Grazie per l'aiuto
Enrico


L'errore sta nell'istruzione "pm.free" dopo finally..... Se tu distruggi
il popup menu con tutti i suoi items, come puoi pretendere che funzioni?
:-), ciao.
--- posted by geoForum on 
http://www.delphiedintorni.it

 
Ovvio :)
Pero` allora dove devo mettere l'istruzione free? Cioe` quando e dove 
liberare il menu?
Enrico


Di solito non ti devi preoccupare della distruzione del popupmenu, in
quanto ad esempio se è relativo a un componente specifico(ad esempio una
label, un toolbutton), esso viene distrutto con la distruzione del
componente a cui fà riferimento. Nel caso piu' banale, cioè se appartiene
a una Form, viene sempre distrutto con la distruzione della stessa. Nel
caso piu' estremo, se proprio lo vuoi distruggere quasi subito allora puoi
mettere l'istruzione relativa alla sua distruzione nel gestore dell'evento
click relativo ad ogni suo item in questo modo:
procedure TForm1.MenuItemClick(Sender: TObject);
var
  I: Integer; Comp: TComponent;
begin
  // Codice da eseguire al click
  // ...........................
  // ...........................
  // Supponendo che il popupmenu faccia parte della form....
  for I := 0 to (ComponentCount - 1) do
    if (Components[I] is TPopupMenu) then
      begin
        Comp := Components[I] as TPopupMenu; FreeAndNil(Comp);
      end;
end; 
Secondo me questo non è il piu' professionale degli approcci in quanto
ripeto, di solito la distruzione del popupmenu non viene effettuata
subito, ma automaticamente in un secondo momento, quando il suo parent
viene distrutto, poi vedi tu......le alternative ci sono......decidi tu, ciao.



Pardon, le ultime righe dopo il codice non prenderle in considerazione, ho
detto una cavolata ;-)(dato che ovviamente se il menu viene creato a
run-time, bisogna distruggerlo altrimenti si potrebbero creare piu'
istanze di esso durante l'esecuzione del programma) ciao.


 liberare il menu?
Non vedo il motivo di creare, riempire e distruggere un PopUp continuamente
a runtime, oltretutto in un evento che puo scatenarsi molte volte in pochi
istanti.Cosa vuoi ottenere nel fare cio?
Io agirei piu semplicemente mettendo un PopupMenu sulla form e lo "compili"
solo quando ti serve.
Qualcosa del genere:
function TForm1.AggiungiMenu(ElementoPar: TPopupMenu; strTitolo: string;
  OnClickEvent: TNotifyEvent): TMenuItem;
var
  ElementoMenu : TMenuItem;
begin
  ElementoMenu := TMenuItem.Create(Self);
  ElementoPar.Items.Add(ElementoMenu);
  with ElementoMenu do begin
    Caption := strTitolo;
    OnClick := OnClickEvent;
  end;
  Result := ElementoMenu;
end;
procedure TForm1.EliminaElementoMenu(intIndice: Integer);
// elimino un elemento dal popupmenu
var
  ElementoDaEliminare: TMenuItem;
begin
  ElementoDaEliminare:= PopupMenu1.Items[2];
  ElementoDaEliminare.Free;
end;
procedure TForm1.CliccaSuMenu(Sender: TObject);
begin
 // qui si gestiscono le varie voci del menu
 // magari usando il TAG per semplificare il tutto
 Showmessage((Sender as TMenuItem).Caption);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
 // Personalizzo ogni elemento del menu
 // qui usiamo una procedura generica
// ma in realtà ogni elemento puo' avere il suo gestore
 PopupMenu1.Items.Clear;
 AggiungiMenu(PopupMenu1, 'tddmiMove', CliccaSuMenu);
 AggiungiMenu(PopupMenu1, 'tddmiCopy', CliccaSuMenu);
 AggiungiMenu(PopupMenu1, '-', nil);
 AggiungiMenu(PopupMenu1, 'tddmiCancel', CliccaSuMenu);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
 // modifico il popupmenu
 EliminaElementoMenu(2);
 AggiungiMenu(PopupMenu1, 'Elemento aggiunto dopo', CliccaSuMenu)
end;
procedure TForm1.TreeView1Click(Sender: TObject);
begin
 PopupMenu1.Popup(600, 400);
end;
Mi sembra tutto più semplice da gestire (ma magari mi perdo qualcosa
riguardo al tuo codice...)
Ciao
-- 
ACSH
[TurboDelphi]
Chi fa da se', fatica il doppio

 
Non e` molto lontano dal mio metodo. Qui non distruggi il menu dopo 
l'utilizzo.
Ho risolto il problema aggiungendo un menu a Design time sulla form.
E` il metodo piu` semplice.


 
Questo PopupMenu viene usato in varie forms e l'idea era di riutilizzare 
la stessa procedura di creazione, utilizzo e distruzione del menu senza 
mantenere muliple copie su diverse form.
Ho risolto mettendo il PopupMenu su un DataModule a cui accedono tutte 
le form. Della gestione del popup si occupa adesso il datamodule.
Ho ancora una domanda ma e` tema per un altro post.


 non puo` essere eseguito.
Prova a mettere un bel
     Application.ProcessMessages
subito prima del finally e dopo il 'popup' e vedi cosa succede.
Ciao
ACSH
-- 
Il piu grande sbaglio nel progettare software
a prova di stupido e sottostimare l'enorme
ingegnosita degli stupidi.