キャッシングValue

フォームコードを解析!

 「C#基本事項」もここらで一段落です。今までの基本事項講座は、「ゲームプログラムテクニック」のゲームループの回で必要な知識を解説してきました。今回はその最後、VC#によるWindowsプログラムの動作の流れと仕組みを説明します。細かく解説していると、今までの知識では全く通用しないので、ゲームループ製作に必要な大まかな流れを紹介します。

Form1.cs

Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace Code1
{
	/// 
	/// Form1 の概要の説明です。
	/// 
	public class Form1 : System.Windows.Forms.Form
	{
		/// 
		/// 必要なデザイナ変数です。
		/// 
		private System.ComponentModel.Container components = null;

		public Form1()
		{
			//
			// Windows フォーム デザイナ サポートに必要です。
			//
			InitializeComponent();

			//
			// TODO: InitializeComponent 呼び出しの後に、
			// コンストラクタ コードを追加してください。
			//
		}

		/// 
		/// 使用されているリソースに後処理を実行します。
		/// 
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		private void InitializeComponent()
		{
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
			this.ClientSize = new System.Drawing.Size(292, 266);
			this.Name = "Form1";
			this.Text = "Form1";
			this.Load += new System.EventHandler(this.Form1_Load);

		}
		
		
		/// 
		/// アプリケーションのメイン エントリ ポイントです。
		/// 
		static void Main() 
		{
			Application.Run(new Form1());
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{
		
		}
	}
}

 「//」やら「///」はコメントなので、読み飛ばしてください。これが最初に自動生成されるソースコードです。操作法説明の回で少し触れましたが、VC#でフォームをデザインするとこのコードに自動的にその変更されたコードが追加されます。

 それでは、大まかな説明を始めます。先ずは、最初の「using〜」の部分ですが…

ネームスペース
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace Code1
{
	/// Form1 の記述。
}

 これは、名前空間(namespace)と呼ばれるものです。あまり深く触れたくないので、ここでは簡単に説明をしておきます。C言語では、「#include 〜」とやって標準のライブラリを読み込んでいましたが、C#ではその代わりに「using 〜」とやると思っておいてください。「using 〜」とやると、そのnamespaceに書かれたプログラム(クラス)を呼び出すことができるようになります。ちなみに、今回のForm1は「Code1」というnamespaceに書かれています。Form1クラス全体が「namespace Code1」のカッコでくくられていますね。namespaceはこのように定義されます。

Form1クラスの定義
	/// 
	/// Form1 の概要の説明です。
	/// 
	public class Form1 : System.Windows.Forms.Form
	{
		private System.ComponentModel.Container components = null;

		/// 
		/// コンストラクタ
		/// 
		public Form1()
		{
			InitializeComponent();
		}

		/// 
		/// 使用されているリソースに後処理を実行します。
		/// 
		protected override void Dispose( bool disposing )
		{
			// 
			// 後処理
			// 
		}

		private void InitializeComponent()
		{
			// 
			// 初期化
			// 
		}
				
		/// 
		/// アプリケーションのメイン エントリ ポイントです。
		/// 
		static void Main() 
		{
			Application.Run(new Form1());
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{
		
		}
	}

 これが、Form1クラスの定義です。メソッド内の処理は省略してあります。さっと読むと、ソッコウで分からない部分が出てきますね。


	public class Form1 : System.Windows.Forms.Form
	{
	}

 「: 〜」はまだ説明してませんね…これがオブジェクト指向プログラムの3大特徴のひとつ「継承」です。クラスは最初から全てを定義することもできますが、以前に作った(もしくはすでにある)クラスの機能を引き継ぐことができます。それが継承です。継承はクラス名の後に「: 継承したいクラス名」と書くと、そのクラスの機能を使えます。

 継承もとのクラスに「System.Windows.Forms.Form」とありますが、これは名前空間「System」の中の名前空間「Windows」の中の名前空間「Forms」に定義されている「Form」というクラスを継承しています。Form1.csの最初に「using System.Windows.Forms;」と書いてあるので、ここまで書く必要は無いのですが、名前空間を宣言しなくても、こうやって「.」でつないでいけば目的のクラスを探すことができます。

 さて、今回定義した「Form1」は「Form」というクラスの機能を引き継いでいるため、「Form1」はWindowsのフォームとして機能します。きっと、フォーム(ウィンドウ)の描画なり終了なりの記述が「Form」クラスの中には色々と書かれていると思うのですが、そんなこと気にしなくても、継承のおかげでWindowsプログラムを作ることができます。「継承」については非常に抽象的に、しかも簡単に説明しましたが、実際はものすごく機能があるので本格的に必要になったときに説明しようと思います。とりあえず、今は「機能が使える」程度の感覚でいいと思います。

 あとは、「protected override void Dispose( bool disposing )」が説明していない部分を多少含んでいると思います。オーバーライドやらまたまた継承関係で面倒なことが多いので、ここは飛ばします。とりあえず、最初のコメントどおり終了の処理が書かれていると思っておいてください。

 それ以外のコンストラクタやメソッド、静的メソッドはすでに説明済みですね。

動作の流れを追う

 コードの解説はこのくらいにしておいて、実際にプログラムの動作の流れを追っていきましょう。

 えっと、とりあえずこんな感じです。
 クラス(基本A)の回でも説明しましたが、C#のプログラムは静的「Main」メソッドから開始されます。Mainメソッドで「Application.Run(new Form1());」が実行されます。この文章でさっき定義した「Form1」クラスから「Form1」インスタンスを生成します。まぁ「new」演算子が書いてあるのでそのままですね。インスタンスが生成された時点でForm1のコンストラクタが呼び出され、「InitializeComponent」を実行します。

 次に、生成されたインスタンスをプログラムのメインスレットとして処理を渡しています。Applicationというクラスは、Windowsプログラムを作るように最初から用意されているクラスです。その中の静的メソッド「Run」を呼んでいます。この文章以降はForm1インスタンスの何や良く分からないところで処理が行われています…この時点で、目でプログラムの流れを追うことができなくなります…(きっと、継承もとのFormクラスに書かれているのでしょう…)

 ここから先がWindowsプログラム独特の構造になっています。プログラム自体はForm1インスタンス内のどっかのメソッドでループしています。ここで、Formに対して、ユーザーから何らかのアクションがあったとしましょう。すると、Windows側から「メッセージ」と言うものが渡されます。Form1インスタンスはそのメッセージを受け取り、メッセージにあった「イベント」を発生させます。例えば、Form1が表示された際にも「Load」イベントが発生します。イベントが発生するとそのイベントに合ったメソッドを呼び出します。今回は「Form1_Load」というメソッドが登録されているので、それが呼ばれます。ちなみに、イベントに対してメソッドを登録している文章は、「InitializeComponent」内に書いてあります。

 Form1が終了すると、終了処理が行われ、Mainメソッドへ処理が戻ります。Mainメソッド内には他に文章が無いのでMainメソッドが終了し、このままプログラムを終了します。

 普通のWindowsプログラムをC#で組む場合、処理のループ構造はほとんど考える必要はありません。発生するイベントに対して、対応する処理を書いていけばいいだけです。ボタンをクリックしても、キーボードを押しても、何をしても(大体は)イベントが発生します。操作法の説明の例でも、「private void button1_Click(object sender, System.EventArgs e)」というメソッドに書き込みましたね。これは、Button1のクリックイベントが発生した際に、自動的に呼び出されるように設定されたメソッドです。イベントに対して、設定されているメソッドを見るには、「InitializeComponent」を見るか、VisualC#のオブジェクトプロパティの中の「イベント」を見ると確認できます。

まとめ

 操作法説明の回から今回のフォームコードの解析まで、色々と誤魔化しつつ説明してきましたが、C言語でコンソールプログラムを組むのと、C#でWindowsプログラムを組む違いを多少なり(ってか、結構?)感じていただけたと思います。Windowsプログラムはループ構造が見えない分、流れを追いにくいと思いますが、細かなことを考えなくても作りたいものを組み上げる事ができます。コツとしては、すべてを理解しようとしないことです。オブジェクト指向プログラムは、プログラムの部品を組み合わせて作っていくものです。今回継承した「Form」クラスも、フォームに貼り付けた「ボタン」もすべてMicrosoftの技術者が作ってくれたプログラムの部品です。そんなものをすべて理解しようなんて絶対に無理です。C#でWindowsプログラムを作るには、理解するよりも、使い方を覚えることが必要でしょう。

 今回で、VisualC#理解編(今、命名)は終了です。今後の「C#基本事項」は、クラスの残りの機能説明と、C#に組み込まれているクラスの使い方説明がメインになると思います。