?
Solved

Making a 'recently used file' list in the File-menu at runtime

Posted on 2006-11-04
15
Medium Priority
?
233 Views
Last Modified: 2010-04-05
Dear Experts,

I want to make a 'Recent Files'-list in my File-menu, similar to what Microsoft Word and such uses for the last files you opened. I have searched and searched on this site, and I found the code below, but I don't understand how to
implement it in my application.

for i := 0 to FRecentFiles.Count - 1 do
begin
RecentFileItem := TMenuItem.Create(self);
File1.add(RecentFileItem);
//The Caption is actually cropped to what's after the last / (The filename without path)
RecentFileItem.Caption := ExtractFileName(FRecentFiles[i]);
RecentFileItem.Tag := i;
RecentFileItem.Visible := true;
RecentFileItem.OnClick := OpenRecentFile;
end;

procedure TForm1.OpenRecentFile(Sender: TObject);
begin
  OpenThisFile(FRecentFiles[TComponent(Sender).Tag]);
end;

Does someone know how?

Kind Regards,

Peter Kiers
0
Comment
Question by:peterkiers
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 5
15 Comments
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874425
Well the first thing here is to work out all the variables being used and what they are.

For example:

File1 = TMainMenu Item by the look of it
FRecentFiles maybe a TObjectList or TList, not sure.

Also there is a procedure missing for the code for OpenThisFile
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874436
In fact, FRecentFiles seems to be a specific object, not sure if it is a custom file store object.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17874460
I found the example on this site with the title:

Best practise for making a 'recently used file' list in the File-menu at runtime

Peter
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874464
Ah ok, I found the thread you were looking at.
All it is is a TStringList holding a list of filenames and their paths.

Im guessing that the list is loading and saving itself to a registry or text file, text file would be the easiest.

You will also need a TOpenDialog component on your form to open the selected file.

Let me add some extra code, 1 sec while I write.
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874473
btw, do you want the same list as from Windows? Or your own list via when you open from within your application?
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17874479
My own list.

P.
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874509
Ok here is a quick one.
Limit 10 different file names.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, Contnrs, ShellAPI;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    OpenDialog1: TOpenDialog;
    Open1: TMenuItem;
    N1: TMenuItem;
    RecentFiles1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Open1Click(Sender: TObject);
  private
    FRecentFiles: TStringList;

    procedure LoadRecentFileList;
    procedure SaveRecentFileList;
    procedure OpenRecentFile( Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FRecentFiles := TStringList.Create;
  FRecentFiles.Duplicates := dupIgnore;

  if FileExists( 'c:\MyRecentFileList.txt') then
    FRecentFiles.LoadFromFile( 'c:\MyRecentFileList.txt');

  LoadRecentFileList;
end;

procedure TForm1.LoadRecentFileList;
var
  i: Integer;
  RecentFileItem: TMenuItem;
begin
  for i := 0 to FRecentFiles.Count - 1 do
  begin
    RecentFileItem := TMenuItem.Create(self);
    RecentFiles1.add(RecentFileItem);
    //The Caption is actually cropped to what's after the last / (The filename without path)
    RecentFileItem.Caption := ExtractFileName(FRecentFiles[i]);
    RecentFileItem.Tag := i;
    RecentFileItem.Visible := true;
    RecentFileItem.OnClick := OpenRecentFile;
  end;
end;


procedure TForm1.OpenRecentFile( Sender: TObject);
var
  sFileName: String;
begin
  sFileName := FRecentFiles[ TMenuItem( Sender).Tag];

  ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);
end;

procedure TForm1.SaveRecentFileList;
begin
  FRecentFiles.SaveToFile( 'c:\MyRecentFileList.txt');
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SaveRecentFileList;
end;

procedure TForm1.Open1Click(Sender: TObject);
var
  sFileName: String;
begin
  if OpenDialog1.Execute then
  begin
    sFileName := OpenDialog1.FileName;

    ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);

    FRecentFiles.Insert(0, sFileName);
    if FRecentFiles.Count > 10 then
      FRecentFiles.Delete( 10);

    RecentFiles1.Clear;
    LoadRecentFileList;
  end;
end;

end.






object Form1: TForm1
  Left = 264
  Top = 160
  Width = 870
  Height = 640
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  Menu = MainMenu1
  OldCreateOrder = False
  OnClose = FormClose
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object MainMenu1: TMainMenu
    Left = 104
    Top = 40
    object File1: TMenuItem
      Caption = 'File'
      object Open1: TMenuItem
        Caption = 'Open'
        OnClick = Open1Click
      end
      object N1: TMenuItem
        Caption = '-'
      end
      object RecentFiles1: TMenuItem
        Caption = 'Recent Files'
      end
    end
  end
  object OpenDialog1: TOpenDialog
    Left = 232
    Top = 40
  end
end
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874525
Slightly made it a bit more clever


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, Contnrs, ShellAPI;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    OpenDialog1: TOpenDialog;
    Open1: TMenuItem;
    N1: TMenuItem;
    RecentFiles1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Open1Click(Sender: TObject);
  private
    FRecentFiles: TStringList;

    procedure LoadRecentFileList;
    procedure SaveRecentFileList;
    procedure OpenRecentFile( Sender: TObject);
    procedure ReloadFileList( sFileName: String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FRecentFiles := TStringList.Create;
  FRecentFiles.Duplicates := dupIgnore;

  if FileExists( 'c:\MyRecentFileList.txt') then
    FRecentFiles.LoadFromFile( 'c:\MyRecentFileList.txt');

  LoadRecentFileList;
end;

procedure TForm1.LoadRecentFileList;
var
  i: Integer;
  RecentFileItem: TMenuItem;
begin
  for i := 0 to FRecentFiles.Count - 1 do
  begin
    RecentFileItem := TMenuItem.Create(self);
    RecentFiles1.add(RecentFileItem);
    //The Caption is actually cropped to what's after the last / (The filename without path)
    RecentFileItem.Caption := ExtractFileName(FRecentFiles[i]);
    RecentFileItem.Tag := i;
    RecentFileItem.Visible := true;
    RecentFileItem.OnClick := OpenRecentFile;
  end;
end;


procedure TForm1.OpenRecentFile( Sender: TObject);
var
  sFileName: String;
  i: Integer;
begin
  sFileName := FRecentFiles[ TMenuItem( Sender).Tag];

  i := FRecentFiles.IndexOf( sFileName);

  FRecentFiles.Delete( i);
  ReloadFileList( sFileName);

  ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);
end;

procedure TForm1.SaveRecentFileList;
begin
  FRecentFiles.SaveToFile( 'c:\MyRecentFileList.txt');

  FreeAndNil( FRecentFiles);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SaveRecentFileList;
end;

procedure TForm1.Open1Click(Sender: TObject);
var
  sFileName: String;
  i: Integer;
begin
  if OpenDialog1.Execute then
  begin
    sFileName := OpenDialog1.FileName;

    ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);

    i := FRecentFiles.IndexOf( sFileName);
    if i >= 0 then
      FRecentFiles.Delete( i);

    ReloadFileList( sFileName);
  end;
end;

procedure TForm1.ReloadFileList(sFileName: String);
begin
  FRecentFiles.Insert(0, sFileName);
  if FRecentFiles.Count > 10 then
    FRecentFiles.Delete( 10);

  RecentFiles1.Clear;
  LoadRecentFileList;
end;

end.
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17874533
Im heading out now so won't see any more responses.
Hopefully this will give you most of what you need.
Ill check back later tonight to see if you need anything else.

Good luck with your coding.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17874538
Wauw, I am impressed.

I need a little time to try your example.

Peter
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17874726
Your example works fine.
Only one little question:

Is it possible that the recent files appears as menu-items instead as a submenu-items?

file
  open
  recentfiles > documen1
                     document2
                             etc...
instead

file
open
--------------
document1
document2
 etc...
--------------

Peter
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17875853
Yeah let me adjust it slightly, Ive just got to make the delete current recent file from the first menu item without deleting the Open menuitem as I made it easy by using the .clear call to the previous menuitem. Cant do this on the file one as it would delete the open one.
0
 
LVL 15

Accepted Solution

by:
mikelittlewood earned 2000 total points
ID: 17875920
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ShellAPI;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    OpenDialog1: TOpenDialog;
    File1: TMenuItem;
    Open1: TMenuItem;
    N1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Open1Click(Sender: TObject);
  private
    { Private declarations }
  public
    FRecentFiles: TStringList;

    procedure LoadRecentFileList;
    procedure SaveRecentFileList;
    procedure OpenRecentFile( Sender: TObject);
    procedure ReloadFileList( sFileName: String);
    procedure ClearList;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.LoadRecentFileList;
var
  i: Integer;
  RecentFileItem: TMenuItem;
begin
  for i := 0 to FRecentFiles.Count - 1 do
  begin
    RecentFileItem := TMenuItem.Create(self);
    File1.add( RecentFileItem);
    //The Caption is actually cropped to what's after the last / (The filename without path)
    RecentFileItem.Caption := ExtractFileName(FRecentFiles[i]);
    RecentFileItem.Tag := i;
    RecentFileItem.Visible := true;
    RecentFileItem.OnClick := OpenRecentFile;
    RecentFileItem.Name := 'Recent' + IntToStr( i);
  end;
end;

procedure TForm1.ClearList;
var
  i: Integer;
  FMenuItem: TMenuItem;
begin
  for i := 0 to FRecentFiles.Count - 1 do
  begin
    FMenuItem := TMenuItem( FindComponent( 'Recent' + IntToStr( i)));
    FreeAndNil( FMenuItem);
  end;
end;

procedure TForm1.OpenRecentFile(Sender: TObject);
var
  sFileName: String;
  i: Integer;
begin
  sFileName := FRecentFiles[ TMenuItem( Sender).Tag];

  i := FRecentFiles.IndexOf( sFileName);

  FRecentFiles.Delete( i);
  ReloadFileList( sFileName);

  ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);
end;

procedure TForm1.ReloadFileList(sFileName: String);
begin
  FRecentFiles.Insert(0, sFileName);
  if FRecentFiles.Count > 10 then
    FRecentFiles.Delete( 10);

  ClearList;
  LoadRecentFileList;
end;

procedure TForm1.SaveRecentFileList;
begin
  FRecentFiles.SaveToFile( 'c:\MyRecentFileList.txt');

  FreeAndNil( FRecentFiles);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FRecentFiles := TStringList.Create;
  FRecentFiles.Duplicates := dupIgnore;

  if FileExists( 'c:\MyRecentFileList.txt') then
    FRecentFiles.LoadFromFile( 'c:\MyRecentFileList.txt');

  LoadRecentFileList;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SaveRecentFileList;
end;

procedure TForm1.Open1Click(Sender: TObject);
var
  sFileName: String;
  i: Integer;
begin
  if OpenDialog1.Execute then
  begin
    sFileName := OpenDialog1.FileName;

    ShellExecute(Handle, 'open', PChar( sFilename), nil, nil, SW_SHOWNORMAL);

    i := FRecentFiles.IndexOf( sFileName);
    if i >= 0 then
      FRecentFiles.Delete( i);

    ReloadFileList( sFileName);
  end;
end;

end.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17875934
Mike, your example works fine.

Thanks for your help.

5OO p's comming your way...

Greetings,

Peter Kiers
0
 
LVL 15

Expert Comment

by:mikelittlewood
ID: 17875936
Glad I could help, sorry for the slow reply, just crawled out of bed  :o)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
Suggested Courses
Course of the Month10 days, 2 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question