Comment puis-je créer une liste de fichiers utilisée le plus récemment dans Delphi 2009?

StackOverflow https://stackoverflow.com/questions/4605664

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 de

Delphi 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.

Était-ce utile?

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top