Following up on yesterdays Delphi: using IInterface to restore cursor at end of mehod (prelude to a memento that executes any code at end of method) here is the memento I meant.
They are based on anonymous methods, which in Delphi are closures: they capture location.
The location is kept just as long as needed, based on a well known Delphi reference counting mechanism: interfaces. The same one I used for the TTemporaryCursor class (and one of the reasons the TTemporaryCursor will keep functioning).
My goal was to simplify code like this:
procedure TTemporaryCursorMainForm.TemporaryCursorClassicButtonClick(Sender: TObject); var Button: TButton; SavedCursor: TCursor; SavedEnabled: Boolean; begin Button := Sender as TButton; SavedEnabled := Button.Enabled; try Button.Enabled := False; SavedCursor := Screen.Cursor; try Screen.Cursor := crHourGlass; Sleep(3000); finally Screen.Cursor := SavedCursor; end; finally Button.Enabled := SavedEnabled; end; end;
Into this:
procedure TTemporaryCursorMainForm.TemporaryCursorMementoButtonClick(Sender: TObject); var Button: TButton; SavedEnabled: Boolean; begin TTemporaryCursor.SetTemporaryCursor(); Button := Sender as TButton; SavedEnabled := Button.Enabled; TAnonymousMethodMemento.CreateMemento(procedure begin Button.Enabled := SavedEnabled; end); Button.Enabled := False; Sleep(3000); // sleep 3 seconds with the button disabled crHourGlass cursor // Delphi will automatically restore the cursor end;
We’ve already seen one of the try…finally…end blocks vanish by using TTemporaryCursor. Now lets look at TAnonymousMethodMemento:
unit AnonymousMethodMementoUnit; interface uses System.SysUtils; type IAnonymousMethodMemento = interface(IInterface) ['{29690E1E-24C8-43A5-8FDF-5F21BB32CEC2}'] end; TAnonymousMethodMemento = class(TInterfacedObject, IAnonymousMethodMemento) strict private FFinallyProc: TProc; public constructor Create(const AFinallyProc: TProc); destructor Destroy; override; procedure Restore(const AFinallyProc: TProc); virtual; class function CreateMemento(const AFinallyProc: TProc): IAnonymousMethodMemento; end; implementation { TAnonymousMethodMemento } constructor TAnonymousMethodMemento.Create(const AFinallyProc: TProc); begin inherited Create(); FFinallyProc := AFinallyProc; end; destructor TAnonymousMethodMemento.Destroy; begin Restore(FFinallyProc); inherited Destroy(); end; class function TAnonymousMethodMemento.CreateMemento(const AFinallyProc: TProc): IAnonymousMethodMemento; begin Result := TAnonymousMethodMemento.Create(AFinallyProc); end; procedure TAnonymousMethodMemento.Restore(const AFinallyProc: TProc); begin AFinallyProc(); end; end.
Like TTemporaryCursor, I’ve kept it self-contained.
It uses a TProc parameter – a parameterless anonymous method– called AFinallyProc that needs to be executed right before the memento goes out of scope.
It can be called like any method, as to the compiler it is a method.
–jeroen
Filed under: Delphi, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Software Development