課題の進め方

基本的には適当なプロジェクト/ソリューションを作って課題を進めた上で,MainForm.csを提出する.

採点はコマンドラインからdotnet new etoappを実行した上でMainForm.csを提出されたもので上書きすることにより行う. 採点者は基本的に採点者自身の環境で動作確認を行うことに注意する.

第6回課題においてMainForm.cs以外に提出に含めたいものがある場合(たとえば画像ファイル等)は事前にメール(メールアドレスはClassroom内「受講者用案内」を参照)で相談のこと.

他の人(受講者・非受講者両方)に解答内容(一部でも)を見せない,そして他の人の解答内容(一部でも)を見ないようお願いします.特に, 公開の場所に解答を置かないようお願いします.githubやbitbucket等は使える人は使えばよいと思いますが,privateレポジトリにするようにお願いします.

プロジェクト/ソリューションの作成

Note

再掲:プロジェクトは一つの実行形式やライブラリを作成するためのコード等を全てまとめたものであり,ソリューションは関連するプロジェクトをまとめたもの(参考:What are solutions and projects in Visual Studio?).

指定された名前(課題5ではQ5,課題6ではQ6とする)の空のフォルダを適当な場所に新規作成し, VSCodeで作成したフォルダを開く.そして,VSCode内のターミナルで以下を実行する.

dotnet new etoapp -sln

課題の実施

MainForm.cs を問題文の指示の通りに編集する(提出・採点手続きの簡略化のため提出する.csファイルは一つのみ).作成した.csファイルには先頭部分に学籍番号と名前をコメントとして含めること.また,自身のプログラムの動作確認を行ったプラットフォームの情報(Mac, Gtk, Wpfの別.複数可.わからないならOS名)も含めるものとする.こちらの情報はあくまで念のためであり,基本的には採点者は自身の環境で動作を確認を行う.なので,たとえば学籍番号Z0TB9999の東北 大学さんの提出ファイルは,もし当人が動作確認をプロジェクト名.Macを用いて行ったのであれば

// Z0TB9999
// 東北 大学
// 動作確認:Mac 

という行から始まる.

提出

できあがった MainForm.csをClassroom内の当該回の「課題」より提出する.また問題文に指示がある場合はそのファイル(例:課題6で提出物に含めたいリソースがある場合)も提出する.提出前には以下を確認しよう.

基本課題

その1

ラベルを

Label

ボタンを

(Button)

テキストボックスを

[          ]

テキストエリアを

+-------------+
|             |
|             |
+-------------+

というアスキーアートとして図示することにする.

このとき,Eto.Formsを用いて以下のようにコントロールが配置されているウィンドウを作成しなさい. ただし,テンプレートから生成されたコードのうち,MainForm.cs のみ変更すること.

File: [                       ]  (Load) 
+-------------------------------------+
|                                     |
|                                     |
|                                     |
|                                     |
|                                     |
+-------------------------------------+
Ready

ただし,以下を満たすこと.

その2

便宜上,上記で"Ready"と書かれている部分を「ステータス行」と呼ぶことにする.

上記のアプリケーションに以下の機能を実装せよ.

ただし,相対パスを用いて「ドキュメント」内(Windowsの場合.Windows 8以前は「マイ ドキュメント」)や「書類」(~/Documents)内(Mac等の場合で.NET 8以降.7以前はホームディレクトリ.以降の説明は.NET 8以降を想定)のファイルを開けるようにするために,以下をMainFormのコンストラクタに含めるなどせよ(フォームの関心毎ではないのでMain等で実行すべきだが,3箇所のファイルを修正するのは大変なので).

// 現在の(作業)ディレクトリを,プラットフォーム毎の「ドキュメント」的なディレクトリに設定する
// Windowsだと「ドキュメント」,Macで.NET 8以降だと「書類」(~/Documents/),7以前はホームディレクトリ.他の環境は未確認.
// 
// より安全には,Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) が空文字列かどうか
// を検査してから Environment.CurrentDirectory に代入したほうがよい.
Environment.CurrentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

上記の設定により,「ドキュメント」フォルダ(Windowsの場合)や「書類」(Macの場合)フォルダの直下のファイルにファイル名のみでアクセスできるようになる(より正確には相対パスの基準がこれらのフォルダになる).より具体的には:

Tip

ファイルを置く場所を確認してみるには以下を実行してみるのもよい.

Console.WriteLine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));

当方の環境(Mac)では以下が表示される.

/Users/kztk/Documents

当該パスはホームディレクトリを表す~を用いて書くと~/Documents/

Caution

Mac含めUnix環境では.NET 8以降とそれ以前で挙動が異なるので注意(参考:https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/8.0/getfolderpath-unix

Tip

テキストボックスに入力されたテキストを取得するにはTextプロパティを用いる.テキストエリアにテキストを設定するには,当該オブジェクトのTextを用いる.

例外処理については前回参照.

Tip

ファイルが存在するかどうかを確認するには File クラスの static メソッド Exists(string) を利用する.より具体的には,File.Exists(path)path が有効なパスで,指す先にファイルが存在しているときに,trueを返し,そうでないときにはfalseを返す.(指す先に存在しているのがディレクトリであるときもfalseとなることに注意する.)

Note

なお,File.Exists(path)true を返した場合にも,ファイルの読み取りが行えない場合はある.たとえば,当該ファイルの read パーミッション がない場合にはUnauthorizedAccessExceptionが発生する.

発展課題

Important

本課題を完了できたのならば本課題の解答のみを提出すればよく,基本課題の解答は提出する必要はない.

上記アプリケーションを拡張し,"Save"ボタンを追加せよ.コントロールの配置は以下のようにせよ.

File: [                ]  (Load) (Save)
+-------------------------------------+
|                                     |
|                                     |
|                                     |
|                                     |
|                                     |
+-------------------------------------+
Ready

"Save"ボタンが押されたときには,その時点でのテキストエリアの内容を,その時点でのテキストボックスに入力されたパスのファイルとして保存する機能を実装せよ.ただし,

Tip

File.WriteAllTextを実行し,適当な例外処理をしたので十分.どんな例外が発生しうるかは, 当該メソッドのリファレンスを参照.

もっと親切なエラーメッセージをステータス行に表示したい場合は File.ExistsDirectory.Exists や,File.GetAttributes などを利用するとよいかもしれない(参考:.NET API リファレンスのFlieクラスの説明

注意(2022-05-25追記):どうやらWindows環境(.NET 5.0.408,6.0.201で確認)では,ArgumentExceptionPathTooLongExceptionが上記リファレンスの記述通りには発生しない模様.また,FileInfoのコンストラクタも記述通りの例外を投げない模様.たとえば,fi = new FileInfo("./test???.txt")は例外を投げず,fi.CreateText()などとしたときにIOExceptionが発生する.