Mi piacerebbe essere in grado di generare dinamicamente i menu popup in pascal.Assegnazione dinamica di funzioni anonime in pascal
Vorrei anche essere in grado di assegnare dinamicamente i gestori di OnClick a ciascuna voce di menu.
Questo è il tipo di cosa che sono abituato a fare in C#, questo è il mio tentativo in pascal.
La voce di menu onClick gestore eventi deve appartenere a un oggetto (of Object
), quindi creare un oggetto contenitore per questo.
Ecco il mio codice:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Menus;
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TFoo = class
public
Bar : String;
Val : Integer;
end;
TNotifyEventWrapper = class
private
FProc: TProc<TObject>;
I : Integer;
public
constructor Create(Proc: TProc<TObject>);
published
procedure Event(Sender: TObject);
end;
var
Form1: TForm1;
NE : TNotifyEventWrapper;
implementation
{$R *.dfm}
constructor TNotifyEventWrapper.Create(Proc: TProc<TObject>);
begin
inherited Create;
FProc := Proc;
end;
procedure TNotifyEventWrapper.Event(Sender: TObject);
begin
ShowMessage(IntToStr(I));
FProc(Sender);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
F : TFoo;
I: Integer;
mi : TMenuItem;
begin
if Assigned(NE) then FreeAndNil(NE);
for I := 1 to 10 do
begin
F := TFoo.Create;
F.Bar := 'Hello World!';
F.Val := I;
NE := TNotifyEventWrapper.Create
(
procedure (Sender :TObject)
begin
ShowMessage(F.Bar + ' ' + inttostr(F.Val) + Format(' Addr = %p', [Pointer(F)]) + Format('Sender = %p, MI.OnClick = %p', [Pointer(Sender), Pointer(@TMenuItem(Sender).OnClick)]));
end
);
NE.I := I;
mi := TMenuItem.Create(PopupMenu1);
mi.OnClick := NE.Event;
mi.Caption := inttostr(F.Val);
PopupMenu1.Items.Add(mi);
end;
end;
end.
Cliccando numero della voce di menu 6
Il programma mostra il messaggio previsto
Tuttavia il messaggio successivo era no t mostra il risultato atteso.
Invece di 6 si mostra voce 10
Non importa quale elemento dell'elenco clicco su, tutti sembrano sparare il gestore di eventi per l'ultimo elemento della lista (10).
Mi è stato suggerito che la procedura membro dell'oggetto NE
Event
sia lo stesso indirizzo di memoria per tutte le istanze di tale oggetto.
Qualunque voce di menu clicco su, l'indirizzo di memoria MI.OnClick
è lo stesso.
Mi chiedo se ho trovato un bug/limitazione del delphi – sav
No, non l'hai fatto. Non hai ancora compreso appieno una sfumatura di cattura variabile. Cattura le variabili piuttosto che i valori. –
Si noti che il codice perde. Presumo che tu sappia questo e abbia un piano per affrontarlo più tardi. –