Come posso creare un elenco di file utilizzato più di recente in Delphi 2009?
-
25-09-2019 - |
Domanda
Ho un TActionManager, e un TActionMainMenuBar, e so come aggiungere un TActionClientItem per ogni file MRU alla barra dei menu principale. Ma devo creare un'azione separata per ogni file MRU nella lista? O c'è un modo per creare una sola azione, e in qualche modo passare un tag o qualcosa per evento OnExecute dell'azione basata su quale file MRU stato cliccato?
l'aiuto di Delphi dice: "Per ulteriori informazioni sugli elenchi MRU, codice di esempio, e metodi per la ricerca di azioni nelle liste, vedi FindItemByAction e FindItemByCaption nella guida in linea." Ma io non riesco a trovare nulla in quei soggetti che è utile, e il codice non certo di esempio. Mi piacerebbe molto per evitare di usare un componente di terze parti per ottenere questo fatto.
Soluzione
avrai una TAction
separata per ogni voce di menu in ogni caso in modo che possano avere valori Caption
distinti. Ma non si deve avere gestori di eventi OnExecute
separati. Il gestore di eventi riceveranno un riferimento al ricorso nel suo parametro Sender
. Utilizzare la proprietà Tag
del mittente per fare riferimento a una lista in cui sono conservati i nomi di file. (Non utilizzare la proprietà Caption
per scoprire quali file da aprire;. Che limita il fare le cose belle come l'aggiunta di acceleratori o abbreviare i percorsi poco maneggevoli)
Questo è ciò che la documentazione presuppone che faresti, anche. ritorna FindItemByAction
il prima elemento che l'azione data è attaccato. Se si collega una singola azione a tutte le voci di menu MRU, allora non sarà in grado di utilizzare tale funzione di dirvi quale menu selezionato. D'altra parte, la voce di menu non avrebbe retto più informazioni di quante l'azione associata sarebbe, quindi non vedo alcuna ragione per cercare la voce di menu in ogni caso. Basta usare le informazioni dall'azione diretta.
Altri suggerimenti
Io uso codice come segue, ma potrebbe essere necessario a bussare in giro un po '. L'unica cosa molto chiaramente mancante è IAbbreviatedFileName
che avvolge sostanzialmente la funzione API PathCompactPath
di Windows. Avrai voglia un modo per abbreviare i nomi di file molto lunghi e questo è la mia scelta preferita. Ci scusiamo per una enorme discarica di codice di esempio, ma qualcuno può trovare qualcosa di utilizzo all'interno!
type
TFileAwareMenuItem = class(TMenuItem)
private
FFileName: string;
public
property FileName: string read FFileName write FFilename;
end;
TMRU = class
private
FParent: array of TMenuItem;
FMenuItemStart: array of TMenuItem;
FMenuItemFinish: array of TMenuItem;
FMenuCount: Integer;
FRegistryKey: string;
FOwner: TCustomForm;
FMRUFileNames: TStringList;
FAction: TAction;
function GetCount: Integer;
function GetItem(Index: Integer): string;
procedure SetAction(Value: TAction);
procedure Read;
procedure Write;
procedure UpdateMenu;
public
constructor Create(const RegistrySubKey: string; const Owner: TCustomForm);
destructor Destroy; override;
procedure RegisterBoundingMenuItems(Start, Finish: TMenuItem);
procedure Add(const FileName: string);
procedure Delete(ItemNum: Integer);
property Count: Integer read GetCount;
property Action: TAction read FAction write SetAction;
property Items[Index: Integer]: string read GetItem; default;
end;
const
MRUSize=9;
AppRegistryKey='??put your apps registry key here??';
var
Registry: TRegistry;
constructor TMRU.Create(const RegistrySubKey: string; const Owner: TCustomForm);
begin
inherited Create;
FRegistryKey := Format('%s\%s', [AppRegistryKey, RegistrySubKey]);
FOwner := Owner;
FMRUFileNames := TStringList.Create;
Read;
end;
destructor TMRU.Destroy;
begin
Write;
FreeAndNil(FMRUFileNames);
inherited;
end;
procedure TMRU.RegisterBoundingMenuItems(Start, Finish: TMenuItem);
begin
inc(FMenuCount);
SetLength(FParent, FMenuCount);
SetLength(FMenuItemStart, FMenuCount);
SetLength(FMenuItemFinish, FMenuCount);
FMenuItemStart[FMenuCount-1] := Start;
FMenuItemFinish[FMenuCount-1] := Finish;
Assert(Start.Parent=Finish.Parent);
FParent[FMenuCount-1] := Start.Parent;
UpdateMenu;
end;
procedure TMRU.UpdateMenu;
var
Intf: IAbbreviatedFileName;
i, j: Integer;
FileName: string;
NewMenuItem: TFileAwareMenuItem;
begin
Intf := FOwner as IAbbreviatedFileName;
for i := 0 to FMenuCount-1 do begin
j := FMenuItemStart[i].MenuIndex+1;
while j<FMenuItemFinish[i].MenuIndex do begin
FParent[i][j].Free;
end;
for j := 0 to Count-1 do begin
NewMenuItem := TFileAwareMenuItem.Create(FMenuItemStart[i].Owner);
NewMenuItem.Action := Action;
NewMenuItem.FileName := FMRUFileNames[j];
FileName := ReplaceString(Intf.AbbreviatedFileName(NewMenuItem.FileName, False), '&', '&&');
NewMenuItem.Caption := Format('&%d. %s', [j+1, FileName]);
FParent[i].Insert(FMenuItemFinish[i].MenuIndex, NewMenuItem);
end;
FMenuItemStart[i].Visible := (Count>0) and (FMenuItemStart[i].MenuIndex>0);
FMenuItemFinish[i].Visible := (FMenuItemFinish[i].MenuIndex<FParent[i].Count-1);
end;
end;
procedure TMRU.Read;
var
i: Integer;
s: string;
begin
if Registry.OpenKey(HKEY_CURRENT_USER, FRegistryKey) then begin
FMRUFileNames.Clear;
for i := 0 to MRUSize-1 do begin
s := Registry.ReadString(IntToStr(i+1), '');
if s<>'' then begin
FMRUFileNames.Add(s);
end;
end;
UpdateMenu;
Registry.CloseKey;
end;
end;
procedure TMRU.Write;
var
i: Integer;
ValueName: string;
begin
if Registry.OpenKey(HKEY_CURRENT_USER, FRegistryKey, KEY_ALL_ACCESS, True) then begin
Registry.WriteInteger('Size', MRUSize);
for i := 0 to MRUSize-1 do begin
ValueName := IntToStr(i+1);
if i<Count then begin
Registry.WriteString(ValueName, FMRUFileNames.Strings[i]);
end else begin
if Registry.ValueExists(ValueName) then begin
Registry.DeleteValue(ValueName);
end;
end;
end;
Registry.CloseKey;
end;
end;
function TMRU.GetCount: Integer;
begin
Result := Min(FMRUFileNames.Count, MRUSize);
end;
function TMRU.GetItem(Index: Integer): string;
begin
Result := FMRUFileNames[Index];
end;
procedure TMRU.SetAction(Value: TAction);
begin
if Value<>FAction then begin
FAction := Value;
UpdateMenu;
end;
end;
procedure TMRU.Add(const FileName: string);
var
i, Index: Integer;
begin
Index := -1;
for i := 0 to FMRUFileNames.Count-1 do begin
if FileNamesEqual(FileName, FMRUFileNames[i]) then begin
Index := i;
break;
end;
end;
if Index<>-1 then begin
FMRUFileNames.Move(Index, 0);
end else begin
FMRUFileNames.Insert(0, FileName);
if FMRUFileNames.Count>MRUSize then begin
FMRUFileNames.Delete(FMRUFileNames.Count-1);
end;
end;
UpdateMenu;
Write;
end;
procedure TMRU.Delete(ItemNum: Integer);
begin
FMRUFileNames.Delete(ItemNum);
UpdateMenu;
end;
initialization
Registry := TRegistry.Create;
if not Registry.KeyExists(AppRegistryKey) then begin
Registry.CreateKey(AppRegistryKey);
end;
finalization
FreeAndNil(Registry);