簡易テキストエディタを作ろうその2

前回までで、最低限のエディタっぽい外見が完成したので 今度はメニューをつけます。 早速つけてみましょう。
メニューの追加
open System;;
open System.Windows.Forms;;

//Editorクラス
type Editor() as this = class
    inherit Form()
    let edit = new RichTextBox()
    do
        edit.Dock <- DockStyle.Fill;
        this.Controls.Add(edit);
        let ms = new MenuStrip() in 
        let mi = new ToolStripMenuItem("ファイル(&F)") in
        let mis = new ToolStripMenuItem("ファイルを開く(&o)") in
        let mie = new ToolStripMenuItem("終了(&x)") in
        mi.DropDownItems.Add(mis) |> ignore;
        mi.DropDownItems.Add(mie) |> ignore;
        mie.Click.Add(fun _ -> this.Close());
        ms.MdiWindowListItem <- mi;
        ms.Items.Add(mi) |> ignore;
        this.MainMenuStrip <- ms;
        this.Controls.Add(ms);
end;;
[<STAThread>]
do Application.Run(new Editor());;
メニューの追加(軽量構文)
open System;;
open System.Windows.Forms;;

//Editorクラス
type Editor() as this =
    inherit Form()
    let edit = new RichTextBox()
    do
        edit.Dock <- DockStyle.Fill;
        this.Controls.Add(edit);
        let ms = new MenuStrip()
        let mi = new ToolStripMenuItem("ファイル(&F)")
        let mis = new ToolStripMenuItem("ファイルを開く(&o)")
        let mie = new ToolStripMenuItem("終了(&x)")
        mi.DropDownItems.Add(mis) |> ignore
        mi.DropDownItems.Add(mie) |> ignore
        mie.Click.Add(fun _ -> this.Close())
        ms.MdiWindowListItem <- mi
        ms.Items.Add(mi) |> ignore
        this.MainMenuStrip <- ms
        this.Controls.Add(ms)

[<STAThread>]
do Application.Run(new Editor())
これはファイルを開くと終了をメニューにもつプログラムです。 終了だけ実装してあってファイルを開くは次で実装します。 以前は次のような構造になっていましたが、MainMenuクラスは.Net Core3.1から使用できなくなりました MainMenuクラス MenuItemクラス(ファイル) MenuItemクラス(ファイルを開く) MenuItemクラス(終了) 上のサイトの言う通りMainMenuの代わりにMenuStripクラスを使用します。 ここではメニューは次のような構造になっています MenuStripクラス ToolStripMenuItemクラス(ファイル) ToolStripMenuItemクラス(ファイルを開く) ToolStripMenuItemクラス(終了) プログラムの通り、親クラスのAddメソッドで子メニューを追加していけば メニューが完成します。 クリックした際の動作は、Click.Addメソッドに 1引数の関数を渡すことでプログラムすることが出来ます。 ここでは簡略化のため、終了を選んだ際の動作だけを記述しています。 また、メニューアイテムの名前の最後に(&アルファベット)とすれば ショートカットキーとして反応するようになります。 このプログラムを起動して、Alt+F、xと打つと プログラムが終了することを確かめてみてください。 それでは、ファイルを開くほうの動作も作成してみましょう。
ファイルを開く機能を追加
open System;
open System.IO;
open System.Windows.Forms;;

//Editorクラス
type Editor() as this = class
    inherit Form()
    let edit = new RichTextBox();
    do
        edit.Dock <- DockStyle.Fill;
        this.Controls.Add(edit);
        let ms = new MenuStrip() in
        let mi = new ToolStripMenuItem("ファイル(&F)") in
        let mio = new ToolStripMenuItem("ファイルを開く(&o)") in
        let mie = new ToolStripMenuItem("終了(&x)") in
        mi.DropDownItems.Add(mio) |> ignore;
        mi.DropDownItems.Add(mie) |> ignore;
        mie.Click.Add(fun _ -> this.Close());
        mio.Click.Add(this.openfile);
        ms.MdiWindowListItem <- mi;
        ms.Items.Add(mi) |> ignore;
        this.MainMenuStrip <- ms;
        this.Controls.Add(ms);
    member this.openfile _ =
        let ofd = new OpenFileDialog() in
        ofd.Filter <- "text files *.txt|*.txt|All files *.*|*.*";
        ofd.FilterIndex <- 1;
        if ofd.ShowDialog() = DialogResult.OK then
            let str  = new StreamReader(ofd.FileName) in
            let text = str.ReadToEnd () in
            edit.Text <- text;
            str.Close();
    end;;
[<STAThread>]
do Application.Run(new Editor());;
ファイルを開く機能を追加(軽量構文)
open System
open System.IO
open System.Windows.Forms

//Editorクラス
type Editor() as this =
    inherit Form()
    let edit = new RichTextBox()
    do
        edit.Dock <- DockStyle.Fill
        this.Controls.Add(edit)
        let ms = new MenuStrip()
        let mi = new ToolStripMenuItem("ファイル(&F)")
        let mio = new ToolStripMenuItem("ファイルを開く(&o)")
        let mie = new ToolStripMenuItem("終了(&x)")
        mi.DropDownItems.Add(mio) |> ignore
        mi.DropDownItems.Add(mie) |> ignore
        mie.Click.Add(fun _ -> this.Close())
        mio.Click.Add(this.openfile)
        ms.MdiWindowListItem <- mi
        ms.Items.Add(mi) |> ignore
        this.MainMenuStrip <- ms
        this.Controls.Add(ms)
    member this.openfile _ =
        let ofd = new OpenFileDialog()
        ofd.Filter <- "text files *.txt|*.txt|All files *.*|*.*"
        ofd.FilterIndex <- 1
        if ofd.ShowDialog() = DialogResult.OK then
            let str  = new StreamReader(ofd.FileName)
            let text = str.ReadToEnd ()
            edit.Text <- text
            str.Close()
[<STAThread>]
do Application.Run(new Editor())
若干作業量が多くなるため ファイルを開く機能は、メソッドとして別途定義しています。 追加した部分はファイルを開くためのメソッドとmis.Click.Add(this.openfile)の二箇所です。 openfile関数でやっていることは 1.OpenFileDialog(ファイルを開くダイアログボックス)の生成 2.ダイアログボックスのフィルタの設定 3.デフォルトで選択されるフィルタを決定(拡張子.txtを持つものが表示される) 4.ダイアログの表示 5.ファイルを読み込み、テキストボックスに設定 となります。 そのままなので、さほど難しくは無いことと思います。 このように、ダイアログボックスなどは .Netライブラリの機能がそのまま使えるので 非常にプログラミングが楽です。 最後に、ファイルの保存機能をつけます。 完成版が以下のプログラムです。
簡易エディタ完成版
module editor
open System;
open System.IO;
open System.Text;
open System.Windows.Forms;;

//Editorクラス
type Editor() as this = class
    inherit Form()
    let edit = new RichTextBox()
    do
        edit.Dock <- DockStyle.Fill;
        this.Controls.Add(edit);
        let ms = new MenuStrip() in
        let mi = new ToolStripMenuItem("ファイル(&F)") in
        let mio = new ToolStripMenuItem("ファイルを開く(&o)") in
        let mis = new ToolStripMenuItem("ファイルを保存(&s)") in
        let mie = new ToolStripMenuItem("終了(&x)") in
        mi.DropDownItems.Add(mio) |> ignore;
        mi.DropDownItems.Add(mis) |> ignore;
        mi.DropDownItems.Add(mie) |> ignore;
        mio.Click.Add(this.openfile);
        mis.Click.Add(this.savefile);
        mie.Click.Add(fun _ -> this.Close());
        ms.MdiWindowListItem <- mi;
        ms.Items.Add(mi) |> ignore;
        this.MainMenuStrip <- ms;
        this.Controls.Add(ms);
    member this.openfile _ =
        let ofd = new OpenFileDialog() in
        ofd.Filter <- "text files *.txt|*.txt|All files *.*|*.*";
        ofd.FilterIndex <- 1;
        if ofd.ShowDialog() = DialogResult.OK then
            let str  = new StreamReader(ofd.FileName) in
            let text = str.ReadToEnd () in
            edit.Text <- text;
            str.Close();
     member this.savefile _ =
        let sfd = new SaveFileDialog() in
        sfd.Filter <- "text files *.txt|*.txt|All files *.*|*.*";
        sfd.FilterIndex <- 1;
        sfd.FileName <- "新規テキスト.txt";
        sfd.InitialDirectory <- ".";
        if sfd.ShowDialog() = DialogResult.OK then
            let sw = new StreamWriter(sfd.FileName,false,Encoding.GetEncoding(65001)) in //65001はutf-8のID
            sw.Write(edit.Text)
            sw.Close()
    end;;
[<STAThread>]
do Application.Run(new Editor());;

簡易エディタ完成版(軽量構文)
module editor
open System
open System.IO
open System.Text
open System.Windows.Forms

//Editorクラス
type Editor() as this =
    inherit Form()
    let edit = new RichTextBox()
    do
        edit.Dock <- DockStyle.Fill
        this.Controls.Add(edit)
        let ms = new MenuStrip()
        let mi = new ToolStripMenuItem("ファイル(&F)")
        let mio = new ToolStripMenuItem("ファイルを開く(&o)")
        let mis = new ToolStripMenuItem("ファイルを保存(&s)")
        let mie = new ToolStripMenuItem("終了(&x)")
        mi.DropDownItems.Add(mio) |> ignore
        mi.DropDownItems.Add(mis) |> ignore
        mi.DropDownItems.Add(mie) |> ignore
        mio.Click.Add(this.openfile)
        mis.Click.Add(this.savefile)
        mie.Click.Add(fun _ -> this.Close())
        ms.MdiWindowListItem <- mi
        ms.Items.Add(mi) |> ignore
        this.MainMenuStrip <- ms
        this.Controls.Add(ms)
    member this.openfile _ =
        let ofd = new OpenFileDialog()
        ofd.Filter <- "text files *.txt|*.txt|All files *.*|*.*"
        ofd.FilterIndex <- 1
        if ofd.ShowDialog() = DialogResult.OK then
            let str  = new StreamReader(ofd.FileName)
            let text = str.ReadToEnd ()
            edit.Text <- text
            str.Close()
     member this.savefile _ =
        let sfd = new SaveFileDialog()
        sfd.Filter <- "text files *.txt|*.txt|All files *.*|*.*";
        sfd.FilterIndex <- 1;
        sfd.FileName <- "新規テキスト.txt";
        sfd.InitialDirectory <- ".";
        if sfd.ShowDialog() = DialogResult.OK then
            let sw = new StreamWriter(sfd.FileName,false,Encoding.GetEncoding(65001)) //65001はutf-8のID
            sw.Write(edit.Text)
            sw.Close()
[<STAThread>]
do Application.Run(new Editor())
ファイルを開く処理と同様にして ファイルを保存する処理(savefile)を追加しています。 また、ファイルを保存するためのToolStripMenuItemを追加して クリック時のメソッドにsavefileを指定しました。 これで、UTF-8のみに対応した ファイルのオープンと保存が可能なエディタができあがりました。