كيف يمكنني إنشاء قائمة الملفات المستخدمة مؤخرًا في Delphi 2009؟

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

سؤال

لديّ TactionManager ، و TactionMainmenubar ، وأعرف كيفية إضافة TactionClientItem لكل ملف MRU إلى شريط القائمة الرئيسي. ولكن هل يجب علي إنشاء إجراء منفصل لكل ملف MRU في القائمة؟ أم أن هناك طريقة لإنشاء إجراء واحد فقط ، وتمرير علامة أو شيء ما إلى حدث Onexecute الخاص بالإجراء بناءً على ملف MRU الذي تم النقر عليه؟

تقول مساعدة Delphi: "لمزيد من المعلومات حول قوائم MRU ، ونموذج الرمز ، وطرق العثور على الإجراءات في القوائم ، انظر FindItemByAction و FindItemByCaption في المساعدة عبر الإنترنت." لكن لا يمكنني العثور على أي شيء في تلك الموضوعات مفيدة ، وبالتأكيد ليس عينة الكود. أود حقًا تجنب استخدام مكون الطرف الثالث لإنجاز هذا.

هل كانت مفيدة؟

المحلول

سيكون لديك منفصلة TAction لكل عنصر قائمة على أي حال بحيث يمكن أن يكون متميزًا Caption القيم. لكن ليس عليك أن يكون لديك منفصلة OnExecute معالجات الأحداث. سيتلقى معالج الأحداث إشارة إلى الإجراء في Sender معامل. استخدم المرسل Tag خاصية للإشارة إلى قائمة حيث يتم الاحتفاظ بأسماء الملفات الخاصة بك. (لا تستخدم Caption خاصية لاكتشاف الملف الذي يجب فتحه ؛ هذا يقيدك من القيام بأشياء لطيفة مثل إضافة مسرعات أو مسارات غير عملية.)

هذا ما تفترضه الوثائق التي ستفعلها أيضًا. FindItemByAction إرجاع أول العنصر الذي يتم إرفاق الإجراء المعطى. إذا قمت بإرفاق إجراء واحد لجميع عناصر قائمة MRU الخاصة بك ، فلن تتمكن من استخدام هذه الوظيفة لإخبارك بالأي القائمة التي تم تحديدها. من ناحية أخرى ، لن يحتفظ عنصر القائمة بأي معلومات أكثر من الإجراء المرتبط به ، لذلك لا أرى أي سبب للبحث عن عنصر القائمة على أي حال. فقط استخدم المعلومات من الإجراء مباشرة.

نصائح أخرى

أستخدم الكود على النحو التالي ، ولكن قد تحتاج إلى ضربه. الشيء الوحيد الوحيد المفقود هو المفقود هو IAbbreviatedFileName الذي يختتم بشكل أساسي وظيفة Windows API PathCompactPath. ستحتاج إلى طريقة لختصر أسماء الملفات الطويلة جدًا وهذا هو خياري المفضل. آسف لمثل هذا التفريغ الكبير من التعليمات البرمجية ، ولكن قد يجد شخص ما شيئًا من الاستخدام!

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);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top