كيف يمكنني إنشاء قائمة الملفات المستخدمة مؤخرًا في Delphi 2009؟
-
25-09-2019 - |
سؤال
لديّ 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);