Comment puis-je créer une liste de fichiers utilisée le plus récemment dans Delphi 2009?
-
25-09-2019 - |
Question
J'ai un TActionManager, et un TActionMainMenuBar, et je sais comment ajouter un TActionClientItem pour chaque fichier MRU à la barre de menu principal. Mais dois-je créer une action distincte pour chaque fichier MRU dans la liste? Ou est-il un moyen de créer une seule action, et de passer en quelque sorte une étiquette ou quelque chose à l'événement OnExecute de l'action basée sur quel fichier MRU a été cliqué?
l'aide deDelphi dit: « Pour plus d'informations sur les listes MRU, des exemples de code et méthodes pour trouver des actions dans les listes, voir FindItemByAction et FindItemByCaption dans l'aide en ligne. » Mais je ne trouve rien dans ces sujets qui est utile, et goûtez certainement pas le code. Je voudrais vraiment éviter d'utiliser un composant 3ème partie pour y parvenir.
La solution
Vous aurez un TAction
pour chaque élément de menu de toute façon afin qu'ils puissent avoir des valeurs de Caption
distinctes. Mais vous ne devez pas avoir des gestionnaires d'événements de OnExecute
séparés. Le gestionnaire d'événements recevra une référence à l'action dans son paramètre Sender
. Utilisez la propriété Tag
de l'expéditeur de se référer à une liste où vos noms de fichiers sont conservés. (Ne pas utiliser la propriété Caption
pour découvrir quel fichier à ouvrir;. Que vous empêche de faire de belles choses comme l'ajout d'accélérateurs ou abrégeant chemins difficiles à manier)
C'est ce que la documentation suppose que vous feriez aussi. FindItemByAction
retourne first élément que l'action donnée est attaché. Si vous attachez une seule action à tous vos éléments de menu MRU, alors vous ne serez pas en mesure d'utiliser cette fonction pour vous dire que le menu a été sélectionné. D'autre part, l'élément de menu ne tiendrait pas plus d'informations que l'action associée serait, donc je ne vois aucune raison de chercher l'élément de menu de toute façon. Il suffit d'utiliser les informations de l'action directement.
Autres conseils
J'utilise le code comme suit, mais vous pouvez avoir besoin de frapper autour de quelques-uns. La seule chose qui manque est évidemment IAbbreviatedFileName
qui enveloppe essentiellement la fonction API Windows PathCompactPath
. Vous voulez un moyen de abrège les noms de fichiers très longs et c'est mon choix préféré. Désolé pour une énorme décharge de code, mais quelqu'un peut trouver quelque chose d'utilisation dans!
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);