アプリケーションを終了して次回起動したとき、前回終了した位置にフォーム(ウィンドウ)を表示させたい場合があるかもしれません。たとえばアプリケーションが動作している様子をキャプチャして動画にしたいときが考えられます。さてどうすればいいでしょうか?
フォームの位置やサイズはプロパティを調べれば簡単にわかります。
フォームの大きさが変更されるとOnResizeメソッドが呼び出され、移動したときはOnMoveメソッドが呼び出されます。そこでフォームのX座標とY座標、幅、高さをタイトルバーに表示するメソッドを作成して、OnResizeメソッドとOnMoveメソッドのなかで呼び出せば現在のフォームのX座標とY座標、幅、高さが表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } void ShowFormInfo() { int x = this.Location.X; // フォーム(ウィンドウ)のX座標 int y = this.Location.Y; // フォームのY座標 int width = this.Size.Width; // 幅 int height = this.Size.Height; // 高さ // つなげてひとつの文字列にしてタイトルバーに表示する Text = String.Format("X={0} Y={1} Width={2} Height={3}", x, y, width, height); } protected override void OnResize(EventArgs e) { ShowFormInfo(); base.OnResize(e); } protected override void OnMove(EventArgs e) { ShowFormInfo(); base.OnMove(e); } } |
実際にやってみるとたしかに表示されているのがわかります。
ではアプリケーションを終了して次回起動したとき、前回終了したときに位置にフォームを表示させたい場合はどうすればいいでしょうか?
終了するときのフォームの座標とサイズを取得してファイルに保存しておけばいいですね。次回の起動時にはこのファイルに保存されている情報からフォームを表示させればいいですね。
ではやってみましょう。
まずこんなクラスをつくります。X座標とY座標をここに保存します。これならあとで気が変わって他の情報(幅、サイズ、最大化されているかどうかなど)を追加したくなったときもすぐに追加できます。
1 2 3 4 5 |
public class Doc { public int StartPositionX = 0; public int StartPositionY = 0; } |
次にForm1クラスですが、まず終了時の情報を保存するファイルを決めないといけません。ここでは実行ファイルがあるフォルダのなかにstart.xmlというファイルを生成してそこに保存します。
コンストラクタ内でファイルのパスを生成します。そして保存されているであろうファイルのなかから情報を読み取るのですが、この処理は自作メソッド MoveStartPositionのなかでおこないます。MoveStartPositionメソッドに関しては後まわしにして、先にファイルに情報を保存する処理を考えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form1 : Form { string startFilePath = ""; public Form1() { InitializeComponent(); startFilePath = Application.StartupPath + "\\start.xml"; MoveStartPosition(); // 後述 } protected override void OnClosed(EventArgs e) { SaveLastPosition(); base.OnClosed(e); } } |
フォームが閉じられたときにはOnClosedメソッドが呼び出されます。OnClosedメソッド内で自作メソッド SaveLastPositionを呼び出して処理をしています。
SaveLastPositionメソッドではDocクラスからインスタンスを生成して、StartPositionXとStartPositionYにフォームのX座標とY座標を代入しています。フォームのX座標とY座標はForm.Locationプロパティをみればわかります。そのあとXmlSerializerクラスとStreamWriterクラスをつかってXMLファイルとして座標を保存しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.IO; using System.Xml.Serialization; public partial class Form1 : Form { protected override void OnClosed(EventArgs e) { SaveLastPosition(); base.OnClosed(e); } void SaveLastPosition() { Doc doc = new Doc(); doc.StartPositionX = Location.X; doc.StartPositionY = Location.Y; XmlSerializer xml = new XmlSerializer(typeof(Doc)); StreamWriter sw = new StreamWriter(startFilePath); xml.Serialize(sw, doc); sw.Close(); } } |
次に起動時です。初回起動の場合は「前回の終了」というものがないのでファイルも存在しません。またファイルを自分で編集してしまった場合などファイルの情報をうまく読み出せない場合もあるかもしれません。そこでここでは例外処理をつかいます。
ファイルが存在しない場合や読み取りに失敗した場合は「MoveStartPosition()内で例外発生」と書かれたメッセージボックスが表示されます。ファイルを開くことができたにもかかわらず例外が発生した場合はfinally節でファイルを閉じる処理がおこなわれます。
フォームのXY座標を指定する場合はForm.FormStartPosition.ManualプロパティをManualにしてからForm.Locationプロパティに座標をセットします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public partial class Form1 : Form { string startFilePath = ""; public Form1() { InitializeComponent(); startFilePath = Application.StartupPath + "\\start.xml"; MoveStartPosition(); } void MoveStartPosition() { StreamReader sr = null; try { XmlSerializer xml = new XmlSerializer(typeof(Doc)); sr = new StreamReader(startFilePath); Doc doc = (Doc)xml.Deserialize(sr); this.StartPosition = FormStartPosition.Manual; this.Location = new Point(doc.StartPositionX, doc.StartPositionY); } catch { MessageBox.Show("MoveStartPosition()内で例外発生"); } finally { if(sr != null) sr.Close(); } } } |
もうちょっと次数を稼ぎたいので、フォームの大きさや最大化がされているかどうかも保存できるようにします。また中央に表示させる方法も考えます。
最初にDocクラスにフィールド変数を追加します。
1 2 3 4 5 6 7 8 9 10 |
public class Doc { public int StartPositionX = 0; public int StartPositionY = 0; public int Width = 0; public int Height = 0; public bool Maximized = false; public bool CenterScreen = false; } |
次に中央に表示するかどうかですが、ユーザーにどうするのか選択させる手段が必要です。ここは安易かもしれませんが、フォームにチェックボックスを貼り付けてチェックされているなら中央に表示する、されていない場合はしないことにします。
最大化されているかどうかとチェックボックスがチェックされているかを保存するのですが、最大化されている状態や最小化されている状態では座標とサイズに意味はありません。最大化されている場合や最小化されている状態で終了するときは直前の通常の状態であったときの座標とサイズが必要です。
そこでふたつのフィールド変数を用意します。そして位置やサイズが変更されたときはここに現在の状態を保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public partial class Form1 : Form { Point LastLocation = Point.Empty; Size LastSize = Size.Empty; protected override void OnLoad(EventArgs e) { if (WindowState == FormWindowState.Normal) { LastLocation = this.Location; LastSize = this.Size; } base.OnLoad(e); } protected override void OnResize(EventArgs e) { if(WindowState == FormWindowState.Normal) LastSize = this.Size; base.OnResize(e); } protected override void OnMove(EventArgs e) { if (WindowState == FormWindowState.Normal) LastLocation = this.Location; base.OnMove(e); } } |
終了時の処理です。最後に取得できたLastLocationとLastSizeを保存します。そして最大化されているかどうかとチェックボックスがチェックされているかどうかを調べてその状態を保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public partial class Form1 : Form { void SaveLastPosition() { Doc doc = new Doc(); // 最後に取得できたLastLocationとLastSizeを保存する doc.StartPositionX = LastLocation.X; doc.StartPositionY = LastLocation.Y; doc.Width = LastSize.Width; doc.Height = LastSize.Height; // 現在、最大化されているか? されているならtrue、そうでないならfalse doc.Maximized = WindowState == FormWindowState.Maximized ? true : false; // チェックボックスがチェックされているならtrue、そうでないならfalse doc.CenterScreen = CheckBoxCenter.Checked ? true : false; XmlSerializer xml = new XmlSerializer(typeof(Doc)); StreamWriter sw = new StreamWriter(startFilePath); xml.Serialize(sw, doc); sw.Close(); } } |
起動したらファイルを読み込んで取得できたデータをもとにフォームを適切な状態で表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public partial class Form1 : Form { void MoveStartPosition() { StreamReader sr = null; try { XmlSerializer xml = new XmlSerializer(typeof(Doc)); sr = new StreamReader(startFilePath); Doc doc = (Doc)xml.Deserialize(sr); // 中央に表示するのであればStartPositionにCenterScreenをセットして // チェックボックスにもチェックをいれる if (doc.CenterScreen) { this.StartPosition = FormStartPosition.CenterScreen; this.CheckBoxCenter.Checked = true; } else this.StartPosition = FormStartPosition.Manual; this.Location = new Point(doc.StartPositionX, doc.StartPositionY); this.Size = new Size(doc.Width, doc.Height); if(doc.Maximized) this.WindowState = FormWindowState.Maximized; } catch { MessageBox.Show("MoveStartPosition()内で例外発生"); } finally { if(sr != null) sr.Close(); } } } |
はじめまして、ナルシーと申します。
昨年末からC#を始めたばかりの初心者です。
閉じたときのフォームの位置を再現させようとテキストファイルに記録しておこうか考えながら検索していたらここに辿り着きました。
こちらのコードをコピペしていったら、なんと簡単に動きました。
ありがとうございます。
コードの意味を理解せずにコピペしましたので、今後勉強してみようと思います。
XmlSerializerって便利ですね。