-5

I'm making a Notepad clone. I've implemented 70% of the options, but there are options that I don't know how to do, and I can't figure out how. Like Save and Save As options.

When I open some text that has already been saved, and then insert something new into it, how can the Save option save to that file and not look like Save As? This way, when I open and want to save, it looks like I'm only making that file for the first time.

And as for the New option, I inserted via TMainMenu that the file name (an additional variable in the TForm instance) should reset to blank, so does the window title.

unit Unit1;
{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, StdCtrls,
  PrintersDlgs;

type

  { TForm1 }

  TForm1 = class(TForm)
    FindDialog1: TFindDialog;
    FontDialog1: TFontDialog;
    MainMenu1: TMainMenu;
    Memo1: TMemo;
    MenuItem1: TMenuItem;
    MenuItem10: TMenuItem;
    MenuItem11: TMenuItem;
    MenuItem12: TMenuItem;
    MenuItem13: TMenuItem;
    MenuItem14: TMenuItem;
    MenuItem15: TMenuItem;
    MenuItem16: TMenuItem;
    MenuItem17: TMenuItem;
    MenuItem18: TMenuItem;
    MenuItem19: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem20: TMenuItem;
    MenuItem21: TMenuItem;
    MenuItem22: TMenuItem;
    MenuItem23: TMenuItem;
    MenuItem24: TMenuItem;
    MenuItem25: TMenuItem;
    MenuItem3: TMenuItem;
    MenuItem4: TMenuItem;
    MenuItem5: TMenuItem;
    MenuItem6: TMenuItem;
    MenuItem7: TMenuItem;
    MenuItem8: TMenuItem;
    MenuItem9: TMenuItem;
    OpenDialog1: TOpenDialog;
    PageSetupDialog1: TPageSetupDialog;
    PrintDialog1: TPrintDialog;
    ReplaceDialog1: TReplaceDialog;
    SaveDialog1: TSaveDialog;
    Separator1: TMenuItem;
    Separator2: TMenuItem;
    Separator3: TMenuItem;
    Separator4: TMenuItem;
    Separator5: TMenuItem;
    Separator6: TMenuItem;
    procedure MenuItem10Click(Sender: TObject);
    procedure MenuItem11Click(Sender: TObject);
    procedure MenuItem12Click(Sender: TObject);
    procedure MenuItem13Click(Sender: TObject);
    procedure MenuItem14Click(Sender: TObject);
    procedure MenuItem15Click(Sender: TObject);
    procedure MenuItem17Click(Sender: TObject);
    procedure MenuItem18Click(Sender: TObject);
    procedure MenuItem20Click(Sender: TObject);
    procedure MenuItem22Click(Sender: TObject);
    procedure MenuItem3Click(Sender: TObject);
    procedure MenuItem4Click(Sender: TObject);
    procedure MenuItem5Click(Sender: TObject);
    procedure MenuItem6Click(Sender: TObject);
    procedure MenuItem7Click(Sender: TObject);
    procedure MenuItem8Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.MenuItem4Click(Sender: TObject);
begin
         if SaveDialog1.Execute then
    Memo1.Lines.SaveToFile(SaveDialog1.FileName);
         SaveDialog1.FileName:= Opendialog1.FileName;

end;

procedure TForm1.MenuItem5Click(Sender: TObject);
begin
      SaveDialog1.execute;
end;

procedure TForm1.MenuItem6Click(Sender: TObject);
begin
PageSetupDialog1.execute;
end;

procedure TForm1.MenuItem7Click(Sender: TObject);
begin
      PrintDialog1.execute;
end;

procedure TForm1.MenuItem8Click(Sender: TObject);
begin
  Application.Terminate
end;

procedure TForm1.MenuItem3Click(Sender: TObject);

begin

 if Opendialog1.Execute then
 Memo1.Lines.LoadFromFile(OpenDialog1.FileName);


end;

procedure TForm1.MenuItem18Click(Sender: TObject);
begin
     if OpenDialog1.Execute then
  begin
    if fileExists(OpenDialog1.Filename) then
      ShowMessage(OpenDialog1.Filename);
  end
else
  ShowMessage('No file selected');

end;

procedure TForm1.MenuItem10Click(Sender: TObject);
begin

  Memo1.Undo;
end;

procedure TForm1.MenuItem11Click(Sender: TObject);
begin
      memo1.CutToClipboard;
end;


procedure TForm1.MenuItem12Click(Sender: TObject);
begin
  memo1.CopyToClipboard;

end;

procedure TForm1.MenuItem13Click(Sender: TObject);
begin
     memo1.PasteFromClipboard;
end;

procedure TForm1.MenuItem14Click(Sender: TObject);
begin
  memo1.Clear;

end;

procedure TForm1.MenuItem15Click(Sender: TObject);
begin
  memo1.SelectAll;

end;

procedure TForm1.MenuItem17Click(Sender: TObject);
begin

  Memo1.WordWrap:=not(Memo1.WordWrap);
end;

procedure TForm1.MenuItem20Click(Sender: TObject);
begin

  FindDialog1.execute;
end;

procedure TForm1.MenuItem22Click(Sender: TObject);
begin
  ReplaceDialog1.execute;
end;

end.
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Vzas Tack
  • 33
  • 5
  • 2
    Disappointing that you have not done any improvements to rename your event handlers as suggested in a comment to your previous question ( https://stackoverflow.com/questions/72077134/clone-notepad-mainmenu-open-new-save-save-as-problems) – Tom Brunberg May 01 '22 at 18:09

1 Answers1

4

First off, give your TMenuItem objects more meaningful names. In fact, make it a habit of never using default object names at design-time, always name the objects you create, so you known what they do in the code, and more importantly you can see what their event handlers are meant to do just by looking at their names.

Second, you mention there is a filename variable in your TForm class, but there is no such variable in the code you have shown. You should add one, it will help you when making decisions in some of your event handlers, and will make your code more self-documenting.

Lastly, why do you have 2 menus invoking the TOpenDialog, and 2 menus invoking the TSaveDialog? Only the Open menu item should invoke the TOpenDialog, and only the Save As menu item should invoke the TSaveDialog. If you create a New file, the Save menu item should be disabled until the Save As menu has saved the file. When you Open an existing file, the Save menu should save to the same file without prompting the user for a new filename.

Try something more like this:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, StdCtrls,
  PrintersDlgs;

type

  { TForm1 }

  TForm1 = class(TForm)
    FindDialog1: TFindDialog;
    FontDialog1: TFontDialog;
    MainMenu1: TMainMenu;
    Memo1: TMemo;
    UndoMenuItem: TMenuItem;
    CutMenuItem: TMenuItem;
    CopyMenuItem: TMenuItem;
    PasteMenuItem: TMenuItem;
    NewMenuItem: TMenuItem;
    SelectAllMenuItem: TMenuItem;
    WordWrapMenuItem: TMenuItem;
    FindMenuItem: TMenuItem;
    ReplaceMenuItem: TMenuItem;
    OpenMenuItem: TMenuItem;
    SaveAsMenuItem: TMenuItem;
    SaveMenuItem: TMenuItem;
    PageSetupMenuItem: TMenuItem;
    PrintMenuItem: TMenuItem;
    ExitMenuItem: TMenuItem;
    OpenDialog1: TOpenDialog;
    PageSetupDialog1: TPageSetupDialog;
    PrintDialog1: TPrintDialog;
    ReplaceDialog1: TReplaceDialog;
    SaveDialog1: TSaveDialog;
    Separator1: TMenuItem;
    Separator2: TMenuItem;
    Separator3: TMenuItem;
    Separator4: TMenuItem;
    Separator5: TMenuItem;
    Separator6: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure UndoMenuItemClick(Sender: TObject);
    procedure CutMenuItemClick(Sender: TObject);
    procedure CopyMenuItemClick(Sender: TObject);
    procedure PasteMenuItemClick(Sender: TObject);
    procedure NewMenuItemClick(Sender: TObject);
    procedure SelectAllMenuItemClick(Sender: TObject);
    procedure WordWrapMenuItemClick(Sender: TObject);
    procedure MenuItem18Click(Sender: TObject);
    procedure FindMenuItemClick(Sender: TObject);
    procedure ReplaceMenuItemClick(Sender: TObject);
    procedure OpenMenuItemClick(Sender: TObject);
    procedure SaveAsMenuItemClick(Sender: TObject);
    procedure SaveMenuItemClick(Sender: TObject);
    procedure PageSetupMenuItemClick(Sender: TObject);
    procedure PrintMenuItemClick(Sender: TObject);
    procedure ExitMenuItemClick(Sender: TObject);
  private
    FileName: string;
    function CheckForUnsavedChanges: Boolean;
  public
    
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption := '(Unsaved)';
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := CheckForUnsavedChanges;
end;

function TForm1.CheckForUnsavedChanges: Boolean;
var
  Choice: Integer;
begin
  Result := not Memo1.Modified;
  if Result then Exit;
  Choice := Application.MessageBox('Document has been modified, save changes?', 'Notepad Clone', MB_ICONQUESTION + MB_YESNOCANCEL);
  Result := Choice <> IDCANCEL;
  if Choice <> IDYES then Exit;
  SaveMenuItem.Click;
  Result := not Memo1.Modified;
end;

procedure TForm1.SaveAsMenuItemClick(Sender: TObject);
begin
  if FileName <> '' then
  begin
    SaveDialog1.InitialDir := ExtractFilePath(FileName);
    SaveDialog1.FileName := ExtractFileName(FileName);
  end;
  if not SaveDialog1.Execute then Exit;
  Memo1.Lines.SaveToFile(SaveDialog1.FileName);
  Memo1.Modified := False;
  FileName := SaveDialog1.FileName;
  Caption := FileName;
end;

procedure TForm1.SaveMenuItemClick(Sender: TObject);
begin
  if FileName <> '' then
  begin
    Memo1.Lines.SaveToFile(FileName);
    Memo1.Modified := False;
  end else
    SaveAsMenuItem.Click;
end;

procedure TForm1.PageSetupMenuItemClick(Sender: TObject);
begin
  PageSetupDialog1.Execute;
end;

procedure TForm1.PrintMenuItemClick(Sender: TObject);
begin
  PrintDialog1.Execute;
end;

procedure TForm1.ExitMenuItemClick(Sender: TObject);
begin
  Close;
end;

procedure TForm1.OpenMenuItemClick(Sender: TObject);
begin
  if not CheckForUnsavedChanges then Exit;
  if not OpenDialog1.Execute then Exit;
  Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
  Memo1.Modified := False;
  FileName := OpenDialog1.FileName;
  Caption := FileName;
end;

procedure TForm1.UndoMenuItemClick(Sender: TObject);
begin
  Memo1.Undo;
end;

procedure TForm1.CutMenuItemClick(Sender: TObject);
begin
  Memo1.CutToClipboard;
end;

procedure TForm1.CopyMenuItemClick(Sender: TObject);
begin
  Memo1.CopyToClipboard;
end;

procedure TForm1.PasteMenuItemClick(Sender: TObject);
begin
  Memo1.PasteFromClipboard;
end;

procedure TForm1.NewMenuItemClick(Sender: TObject);
begin
  Memo1.Clear;
  FileName := '';
  Caption := '(Unsaved)';
end;

procedure TForm1.SelectAllMenuItemClick(Sender: TObject);
begin
  Memo1.SelectAll;
end;

procedure TForm1.WordWrapMenuItemClick(Sender: TObject);
begin
  Memo1.WordWrap := not Memo1.WordWrap;
end;

procedure TForm1.FindMenuItemClick(Sender: TObject);
begin
  FindDialog1.Execute;
end;

procedure TForm1.ReplaceMenuItemClick(Sender: TObject);
begin
  ReplaceDialog1.Execute;
end;

end.
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    It might be worth pointing out that this approach is somewhat simplified. For instance, in a real app it wouldn't be enough with a Yes/No message box, but you'd need a Yes/No/Cancel one. (Ooops, I don't want to close the app!) – Andreas Rejbrand May 02 '22 at 08:04
  • Not really *simplified*. The code is already accounting for a new document that is not saved yet and the user cancels the SaveDialog to mean don't exit. But I forgot to account for the MessageBox being canceled, too. I've added that. – Remy Lebeau May 02 '22 at 14:47