「ほっ」と。キャンペーン

<   2010年 01月 ( 33 )   > この月の画像一覧

結局C#とはどういうものか

Visual C# で簡単なプログラムを作り、.cs ファイルの記述がどうなっているのかを探索して、C#のプログラムの雰囲気を調べてきた。

それでは C#/.NET とはどういうプログラム言語なのかということになるが、使ってみた感じや、マイクロソフトのチュートリアルなどを見ると、プログラムの部品化できるものは徹底的に部品化しようとしている方針のように見える。GUIなどは、極力GUIで基本的に動くものを作り、コーディングの手間を省くことができる。

たとえば、基本的な機能が既にプログラムされたコンポーネントを使うと、簡単なテキストエディタのようなものはほとんどGUIで設計できる。また、GUI に限らず、データベースとのアクセスや、ウェブアプリの開発も、使い回しのきくプログラムの部品は極力使い回して使用するという考え方だ。

基本的な機能はかなりのものまで、コンポーネントが既に持っている。たとえば、テキストボックスはそのままで、Ctr-C, Ctr-V などのショートカットキーによるコピーアンドペーストに対応している。そうして、個々のプログラムの細かいチューニングについてはオブジェクトのプロパティの変更で対応している。それを、可能にしているのが、.NET の完全にオブジェクト指向化したクラスライブラリだ。

C#は、.NET のクラスライブラリを最も簡潔に取り扱えるように設計されているとともに、オブジェクト指向プログラムで発生しやすいオーバーヘッドなどの問題を解決しようとしている。

コンポーネントを使ったプログラムは誰が作っても同じようなプログラムになりやすいが、プログラムそのものの表現力より、多少画一的ではあっても目的の情報処理を効率的に作ることを優先している。良くも悪くも実務的な印象を受ける。プログラミングをアートととらえたい人には物足りないかもしれない。

こういうC#の特色については、実際の事例を使って、何ができるのか、何を目的としてどういう使い方をするものなのかなどという議論をすべきだが、それは、管理人には荷が重い。

Visual C#は日曜大工的で作る本棚のようなプログラムも書けるが、高層ビルディングも建てることができる。このような高層ビルディング的なプログラムを作るためには、別の知識がいるが、日曜大工をやっている限りは必要ないし、現場にいないと学習も難しい。

そいう訳で、管理人のC#関連の記事の最後として、C#とは何かがわかるサイトを紹介する。いずれにせよ、Visual C# のような開発環境が簡単に手に入るようになったおかげで、コンピュータ大好き人間にとって Windows OS の魅力が倍増したことは間違いない。

Visual C# デベロッパーセンター: マイクロソフトの公式サイト

.NET Framework ラーニング: 同じくマイクロソフトのサイト

私がJavaからC#に乗り換えた10の理由: 開発者から見たC#の特色

C# によるプログラミング入門: C#の言語仕様の実例入りの解説
[PR]
by tnomura9 | 2010-01-31 08:43 | C# | Comments(0)

プログラムファイルの構成

Visual C# で、新しいプロジェクトを作り、フォームの上にボタンをひとつだけ貼付け、そのボタンをダブルクリックして、イベントハンドラ button1_Click () を作成した時のプログラムファイルの構成を再度概観してみた。

ファイルは分割されているが、統合されて一本のプログラムリストとして扱われる。インクルード文でファイルを読み込むわけではないので、分割ファイル間の依存関係は namespace (名前空間)で判別される。

まずはファイルの依存関係。

Program.cs
  Form1.cs
    Form1.Designer.cs

名前空間の階層構造。

namespase Learn
{
  static class Program
  {
    [STAThread]
    static void Main() { Application.Run(new Form1()) }
  }

  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e) { ... }
  }

  public partial class Form1
  {
    private System.ComponentModel.IContainer components = null;
    protected override void Dispose(bool disposing) {}
    private void InitializeComponent() { ... }

    this.button1 = new System.Windows.Forms.Button();
    System.Windows.Forms.Button button1;
  }
}

どういう事を実行しているかというと、
1. System.Windows.Forms.Form クラスから導出して Form1 クラスを作る。
2. Form1 の上にボタンを作成し、ボタンのクリックをイベントハンドラと関連付ける InitializeComponent() メソッドを作る。
2. button1 ボタンが参照出来るように、フィールド button1 を作る
3. ボタンがClick された時のイベントハンドラ button_Click を定義する。
4. Learn.Program.Main() を呼び出す。
5. Learn.Program.Main() は、System.Forms.Application.Run() を呼び出す。
6. System.Forms.Application.Run は引数に Learn.Form1 のインスタンスを必要とするので new Form1() で作る。
7. Form1 クラスのコンストラクタ Form1() は Learn.Form1.InitializeComponent()
で、フォームのコンポーネントの初期化をする。
8. InitializeComponent() が実行されたら、Application.Run() の中でプログラムがイベント待ちの待機状態になる。

これだけのことをするプログラムがフォームデザイナで自動生成されていたので、イベントハンドラを記述するだけでプログラムが出来上がってしまうような、安易な印象を持ってしまったのだ。逆に言うとその分プログラム作成の効率が劇的に上がっている事になる。

C#のプログラムをスクラッチからつくるのは容易ではない。Visual C#でプログラムを作ると、定型的な部分はプログラムが作ってくれるので、プログラマの仕事はきちんと動くプログラムを改造するだけになる。しかし、どの部分の改造を自分がやっているのかは、自覚的しておく必要がある。

C# や .NET を全て理解してからプログラムを作ることは不可能ではないが事実上は無理なので、こういう自動作成されたプログラムの改造に頼らなければならないが、自動作成されたプログラムの不可解な部分をできるだけ少なくする努力は必要だろう。
[PR]
by tnomura9 | 2010-01-30 07:57 | C# | Comments(0)

イベントハンドラの引数

Visual C# で新しいプロジェクトを作って、フォームデザイナで何もないフォームの上にツールボックスからボタンを一個だけ貼り付けてみよう。作製された button1 を選択してダブルクリックすると、Form1.cs が開かれてbutton1 の Click に対応するシグラナルハンドラ、

private void button1_Click(object sender, EventArgs e)

が、自動的に作成されている。ここに、ボタンがクリックされた時のプログラムを記述していけばいいのだが、このイベントハンドらには、object 型の sender と EventArgs 型の e という二つの引数が渡されている。

どんな引数が返されているかを調べるには、オブジェクトのToString() メソッドを利用するのが便利だ。

例えば、sender の内容を知るためには、Form1 に texBox を追加したあと、、button1 のイベントハンドラに、

textBox1.Text = sender.ToString();

とプログラムして、[デバッグ] - [デバッグ開始] メニューでプログラムを実行する。ボタンをクリックすると、textBox1 に、

System.Windows.Forms.Button, Text: button1

と表示される。どうやら、button1 のオブジェクトが渡されているらしい。しかし、Button オブジェクトとしてではなく、object 型で渡されているため、

textBox1.Text = sender.Text;

としてもビルドエラーがでてしまう。派生クラスが抽象クラスとして扱われているときは、キャストすれば派生クラスを取り出すことができる。 button1_Click() イベントハンドラに、

textBox1.Text = ((Button)sender).Text;

と記述すると、ボタンのクリックでテキストボックスに button1 の文字が表示される。

イベントハンドラのような汎用性のあるメソッドに渡す引数は、抽象クラスのオブジェクトで渡した方が汎用性を保てるのだろう。こういうときは、プログラムする方で型変換を行わなければならないが、抽象クラスから派生クラスを取り出すのは、C# では単にキャストするだけでよいようだ。

もう一つの変数 EventArgs e についても調べてみた。

イベントハンドラのプログラムが、

textBox1.Text = e.ToString();

のときは、テキストボックスに System.Windows.Forms.MouseEventArgs と表示されたので、

textBox1.Text = ((MouseEventArgs)e).Button.ToString();

で、試すと Left と表示された。Left を調べてみたら、System.Windows.Form.MouseButtons 列挙型のメンバだったので、button1_Click イベントハンドラに次のようなプログラムを書き込んだらビルドエラーになった。

if (((MouseEventArgs)e).Button == MouseButtons.Left)
{
    textBox1.Text = "OK";
{

そこで、MouseButtons.Left をフルパス表記して、

if (((MouseEventArgs)e).Button == System.Windows.Forms.MouseButtons.Left)

にしたら、無事にビルドできて button1 のクリックでテキストボックスに OK が表示された。using 文を使っても定数についてはフルパス表記しないといけないらしい。

using を使っても定数はフルパス表記しないとビルドできないなどとはマニュアルにも書いてないので、実験して始めて分かった。これが大きいプログラムを書いた後だったら頭を抱えてしまったかもしれない。こういう単純なプログラムについて十分実験してみるというのは、新しいプログラム言語に挑戦するときには有効な方法だ。

プログラム言語を習得するときには、文法について学ぶだけでなく、言語の作者がどういう意図でそのような文法をつくったかという発想にまで思い至らないとなかなか使いこなせない。きちんと動いている小さいプログラムについてこういう風にいろいろと実験をしかけてみるのは、プログラム言語の発想を知るためによい方法だと思う。
[PR]
by tnomura9 | 2010-01-29 10:54 | C# | Comments(0)

メニューを作る

C#でフォームを作れるようになったし、その上にボタンなどのコントロールを配置できるようになり、コントロールに対するマウス操作で発生したイベントに対するイベントハンドラを記述できるようになった。あとは、メニューを作れるようになれば、簡単なアプリケーションを作ることができる。

Visual C# ではメニューは簡単に作ることができる。フォームデザイナでツールボックスの「メニューとツールバー」を開き MenuStrip をダブルクリックするだけだ。すると、フォームのタイトルバーのすぐ下にメニューの項目を入力するテキストボックスが開くので、メニューの項目に、「ファイル」、メニューリストの項目に「終了」などと入力するだけだ。

入力がすんだらいったんメニュー以外のところをクリックすると、アプリケーションで見える形になる。そこで、普通にアプリケーションを使う感じでメニューの項目をえらびドロップダウンリストの項目を選んでダブルクリックするとイベントハンドらをプログラムできるように、Form1.cs が開かれる。今の場合、

private void 終了ToolStripMenuItem_Click(object sender, EventArgs e)

というイベントハンドラが作成されて、編集を待っている。そこで、キャレットの位置に、次の命令文を入力する。

Application.Exit();

これだけで、実際に機能するメニューをプログラムすることができる。Visucal C# のメニューから、[デバッグ] - [デバッグ開始] を選ぶと、ウィンドウが表示され、メニューの [ファイル] - [終了] を選択すると、アプリケーションが終了する。

イベントハンドラが、Form1.cs の 終了ToolStripMenuItem_Click() なのは分かったので、フォームの上のメニューアイテムがどうプログラムされているかをのぞいてみたら、次のような命令文が追加されていた。(Location) は() を外して考えてください。

#region Windows フォーム デザイナで生成されたコード

///
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
///

private void InitializeComponent()
{
    this.menuStrip1 = new System.Windows.Forms.MenuStrip();
    this.ファイルToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.終了ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.menuStrip1.SuspendLayout();
    this.SuspendLayout();
    //
    // menuStrip1
    //
    this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    this.ファイルToolStripMenuItem});
    this.menuStrip1.(Location) = new System.Drawing.Point(0, 0);
    this.menuStrip1.Name = "menuStrip1";
    this.menuStrip1.Size = new System.Drawing.Size(284, 26);
    this.menuStrip1.TabIndex = 0;
    this.menuStrip1.Text = "menuStrip1";
    //
    // ファイルToolStripMenuItem
    //
    this.ファイルToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
    this.終了ToolStripMenuItem});
    this.ファイルToolStripMenuItem.Name = "ファイルToolStripMenuItem";
    this.ファイルToolStripMenuItem.Size = new System.Drawing.Size(68, 22);
    this.ファイルToolStripMenuItem.Text = "ファイル";
    //
    // 終了ToolStripMenuItem
    //
    this.終了ToolStripMenuItem.Name = "終了ToolStripMenuItem";
    this.終了ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
    this.終了ToolStripMenuItem.Text = "終了";
    this.終了ToolStripMenuItem.Click += new System.EventHandler(this.終了ToolStripMenuItem_Click);
    //
    // Form1
    //
    (省略)
    this.MainMenuStrip = this.menuStrip1;
    (省略)
    this.menuStrip1.ResumeLayout(false);
    this.menuStrip1.PerformLayout();
    this.ResumeLayout(false);
    this.PerformLayout();

}

#endregion

private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem ファイルToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem 終了ToolStripMenuItem;
    }

何が記述されているかというと、InitializeComponent() メソッドの中で、MunuStrip オブジェクト menuStrip1 とToolMenuItem オブジェクトの ファイルToolStripMenuItem と 終了ToolStripMenuItem が作られて、終了ToolStripMenuItem の Click プロパティに、System.EventHandler(終了ToolStripItem_Click) イベントハンドラオブジェクトが登録されている。

Visual C# の GUI 部分のプログラミングは、このようにフォームデザイナで作成したあとに、Form1.cs と Form1.designer.cs の中をのぞいて何が追加されているかを調べるのが便利だ。GUIのプログラムはイベント駆動型プログラムされているので、定型的に、

1. 何というコントロールが作成されているか
2. そのコントロールのプロパティには何が割り当てられているか
3. そのコントールで捕捉されるイベントの種類は何か
4. そのイベントハンドらは何か

について見ていくとプログラムの意味が分かる。フォームデザイナでコントロールを作ってはプログラムを確認の作業を繰り返していけば、コントロールを使ったプログラミングについては、参考書を読んでもそう悩まないで済む。

今までに、統合環境でプログラムを作ったことがなかったので、便利さに驚いている。なんで、早く覚えなかったのだろうと思うが、そこが独学の非能率的な所でもあり、発見の喜びを味わう楽しみのあるところでもある。
[PR]
by tnomura9 | 2010-01-28 07:45 | C# | Comments(0)

コールバック

GUIのプログラミングはイベント駆動型のプログラム様式が使われる。イベント駆動型のプログラムでは、イベントが発生すると、そのイベントに対応した関数が呼び出されて処理が行われる。

この方式のプログラミング環境では、プログラマは発生するイベントの種類とイベントが発生したオブジェクトの情報に応じて、イベントハンドラとなる関数を記述するだけだ。したがって、常に全体を考えてプログラムするフロー駆動型のプログラミング様式と比べて負担が少ない。また、きちんと動いているプログラムを土台に、それに改良を加えていくという方法も簡単にできる。プログラムの一部を変更したために全体が動かなくなってしまうという事態を引き起こすことも少なくなる。

しかし、便利なイベント駆動型のプログラミング様式だが、C言語でプログラムを書ければ、すぐにイベント駆動型のプログラムを書けるという訳ではない。C言語を習ってすぐに書けるのは、フロー駆動型のプログラミングであって、イベント駆動型のプログラムではない。イベント駆動型のプログラムは、イベント駆動型のプログラミングを提供する環境がないと書けない。C言語で書くことはできるが、そのためには、イベント駆動型の環境を提供するライブラリを使うか、自分で作るかしなければならない。

C言語でプログラムを書くときも、最初から最後まで続く長いプログラムを書いていくことはない。まず、部品となる小さい関数を作ったり、ライブラリを利用したりして基本的なプログラムの部品を作っておき、その部品を組み合わせてさらに大きなモジュールを作り、最後にそれをメイン関数にまとめ上げるという作業をする。

このようなフロー駆動型のプログラムでは、部品となる下層の関数から、それを利用する上層の関数が呼ばれたりすることはない。ところが、イベント駆動型のプログラミングでは、インフラとなるライブラリからそれを利用する上層の関数を呼ばないとプログラムできないのだ。

イベントの発生を検知するのは下層のライブラリの関数のしごとだ。しかし、その関数がイベントを検知した場合それに対応するイベントハンドラとなる関数は、上層でプログラミングされていなければならない。

たとえば、サービスステーションに電話で注文するときのことを考えてみよう。あの製品を送って下さい、とか、この製品に加工して下さいとか、ユーザは電話で注文することができる。しかし、それらの加工はステーション側で行われるので、ユーザに加工の依頼がくることはない。しかし、どうしてもユーザの方でも加工をしたいときがある。そういう時はどうするかというと、ユーザの電話番号をステーションに知らせておき、ユーザの手が必要になったときステーションから電話をかけてもらうようにするのだ。

このようにサービスステーションから連絡をもらうために電話番号を教えておくことをコールバックという。イベント駆動型プログラミングでよく出てくるコールバック関数は手続きがこれとよく似ているためにそう呼ばれている。下層のライブラリに上層の関数のアドレスを入れたポインタを引数としてわたして、下層のライブラリから上層の関数を必要に応じて呼び出すことができるようにする仕組みだ。

イベントの発生を監視するのは下層のライブラリの仕事だが、イベントが発生したとき、上層の関数を呼び出せれば、ユーザの方はイベント監視の細かいことについては、ライブラリに任せたままで、イベントが発生した時のプログラムだけに集中できる。C#の場合、.NET のクラスライブラリがそういうイベントの処理を分担してくれている。

便利なイベント駆動型のプログラム様式だが、これを使いこなすためにはポイントがふたつある。ひとつは、ライブラリで処理できるイベントの種類を知らなければならないということ。もうひとつは、コールバック関数をイベントハンドラとしてライブラリに登録する方法を知っておくことだ。

Visual C# のフォームデザイナでプログラミングするとき、ボタンなどのコントロールを選択し、プロパティウィンドウのイベントボタンをクリックしてイベントの種類をダブルクリックすると、Form1.cs が開いてカーソルがコールバックルーチンを編集できるようにして待機するが、このときどういう事が起こっているかというと、たとえば、button1 を選択し、イベントの Click をダブルクリックすると、自動的に

private void button1_Click(object sender, EventArgs e)

というコールバック関数のひな形がForm1.csに作成される。しかし、button1_Click を記述しただけでは、クリックイベントが発生しても button1_Click () が実行されることはない。button1がクリックされたときにこの関数がイベントハンドラーとして働くことをあらかじめ .NET に通知しておかなくてはならない。実は、イベントのフィールドをダブルクリックしたときには見えないところで、Form.designer.cs の InitializeComponent () メソッドに次の文が挿入されているのだ。

this.button1.Click += new System.EventHandler(this.button1_Click);

これは、button1のClickプロパティに、System.EventHandlerクラスの button1_Click 関数を登録したオブジェクトを追加しているという意味がある。これをやっておくと、button1 がクリックされたときに、button1_Click というイベントハンドラーが呼び出されて処理が行われる。

予定していなかったイベントに対するコールバック関数を作ってしまったとき、Form1.cs でその関数を削除してもビルドエラーになる場合、それに対応するコールバック関数を登録する文を Form1.designer.cs で消去するとビルドに成功する。

このように、Form1.designer.cs の中で、button1 などのコントロールの Click などのような、イベント名と同じプロパティに、System.EventHandler オブジェクトを追加するという操作さえ知っておけは、イベントに対応するコールバック関数をプログラムするだけでいいというイベント駆動型プログラム様式のお気楽さを堪能することができる。

イベントに対応するコールバック関数を書き、それをイベントハンドラで登録するという .NET のイベント駆動型プログラミングの基本を理解しておけば、C#でするプログラミングは非常に楽をできるのだということがわかるだろう。
[PR]
by tnomura9 | 2010-01-27 07:07 | C# | Comments(0)

オブジェクトをマウスで動かす

GUI のプログラムを作る時にどうしてもやってみたいことがある。それは、ドローツールの場合のようにオブジェクトをマウスでドラッグして動かすことだ。基本的なテクニックだが、参考書にもあまりないし、ネットで検索してもなかった。いちおう次のようにすると動いたが、他のプログラムを参考にしたわけではないので、これでいいのかどうかは分からない。

プログラムの作成はまずプロジェクトを作成したら、フォームの上にボタンを一つだけ貼り付ける。

つぎに、ボタンの上で、MouseDown イベント、MouseMove イベント、MouseUp イベントを捕捉して動作させるようにした。

下のプログラムは、Form1.cs に書き込むが、下のソースを動かすためには、イベントハンドラーをボタンオブジェクトに追加しておかなくてはならない。

イベントハンドラーの追加は、Form1.Designer.cs のInitializeComponent() メソッドの中で行うが、Form1.Designer.cs を直接編集するよりは、フォームデザイナーでやった方がいい。フォームデザイナーでボタンを選択しておいてプロパティウィンドウの稲妻印のイベントアイコンをクリックすると、使えるイベントのリストが表示される。そこで、MouseDown などのイベント名のラベルをダブルクリックするとコールバックルーチンを記述することができる。このとき同時にForm1.Designer.cs にはMouseDown のイベントハンドラーを追加する記述が挿入されている。

また、マウスのドラッグ操作関連で使うので、Form1オブジェクトに、pointOffset と isActive のふたつのインスタンス変数を追加しておく。

public partial class Form1 : Form
{
  private bool isActive = false;
  private Point pointOffset;

  public Form1()
  {
    InitializeComponent();
  }

  private void button1_MouseDown(object sender, MouseEventArgs e)
  {
    pointOffset = new Point(this.PointToClient(Cursor.Position).X - button1.(Location).X,
this.PointToClient(Cursor.Position).Y - button1.(Location).Y);
    isActive = true;
  }

  private void Form1_MouseMove(object sender, MouseEventArgs e)
  {
    if (isActive == true)
    {
         button1.(Location) = new Point(this.PointToClient(Cursor.Position).X - pointOffset.X,
         this.PointToClient(Cursor.Position).Y - pointOffset.Y);
    }
  }

  private void button1_MouseUp(object sender, MouseEventArgs e)
  {
    isActive = false;
  }
}

* ブログの制限の関係で(Location)にしていますが、()をとって使ってください。

MouseDown イベントで、カーソルの位置とボタンのLocationの差を計算し、isActive フラグをtrue にする。MouseMove イベントで isActive フラグが true ならマウスカーソルの位置からボタンのLocationを計算しLocationの値を設定しなおす。MouseUp イベントで isActive フラグを false にする。

たったこれだけの操作で、ボタンをマウスで自由にドラッグして動かすことができるようになった。

どこからか引用したものではないのでバグがあるかもしれないが、自分でつかうプログラムなら問題ないし、他のソースを読むときも理解しやすいのではないだろうか。
[PR]
by tnomura9 | 2010-01-25 17:12 | C# | Comments(0)

フリック入力に慣れた

フリック入力に慣れた。

最近フリック入力にだいぶ慣れてきた。片手で日本語を入力するのをこんなに快適に感じたのは初めての経験だ。いつもiPodを持ち歩いて、暇さえあれは何かを書き込んでいる。

先日も講演会に持っていってメモを取ってきた。話しのスピードについて行けるほどには速く打てなかったが、備忘のためのメモは十分取る事ができた。フリック入力が楽しいので、講演も楽しめた。

練習を始めて二週間だから、学習の効果の上がり方はタッチタイピングのときより速い。この記事も、iPodのメモ帳に入力してメールで送ったものを使っている。

フリック入力のことを教えて戴いたにゃおさんに感謝。
[PR]
by tnomura9 | 2010-01-24 21:52 | NetWalker | Comments(0)

C#アプリケーション作成への戦略

今までの記事で、Visual C# の操作で、どんなソースファイルが作成されるかが分かった。あとは、アイコンなどのリソースの管理や、開発のバージョンのコントロールなどの知識がいるようだがそれは後でできるとして、一応フォームデザインを使ってプログラムを作った時にどのようなソースファイルができるかはわかったので、ビルドに失敗してもどこを修正すればいいのかがわかる。

つぎは、自分の頭の中にあるイメージのプログラムを作れるようになるために、どのような方針で調べていけばいいかということだ。それには、C#でプログラムを作るということの構造を考えてみるとよい。

.NET でプログラムを作る時は、Visual Basic を使おうと、Visual C# を使おうと同じようなプログラムができあがるはずだ。したがって、プログラムを作るための知識は、プログラム言語そのものよりも、クラスライブラリをどのように活用できるかということになる。

.NET のライブラリはすべてクラス化されている。したがって、それらのクラスライブラリを使ってのプログラミングの作業では、ほとんどが、クラスまたはインスタンスメソッドを呼び出して作業させたり、それらから情報を得たりというオブジェクトの操作になる。したがって、Ruby などでオブジェクト指向プログラムを作るのに慣れていれば、プログラミング言語を理解するための努力はそう必要ないことが分かる。必要なのは、どこの名前空間にどんなクラスがあって、そのクラスがどんなメソッドやプロパティを提供しているかという知識だ。

しかし、それだけでは、ライブラリの中の膨大な数のクラスのどれを使えばいいのか迷ってしまう。したがって、自分がどんなプログラムを作りたいのかというイメージを整理しておく必要がある。ただ、アプリケーションの共通点はあるはずで、そのプロトタイプとなるようなプログラムを作っていけばいいことになる。また、そのようなプログラムの情報はネットや本から比較的検索しやすいだろう。

そのようなプログラムとしては次のようなものが考えられる。

1.テキストエディタ
2.ペイント
3.ドロー

これらは精緻なものがフリーソフトウェアで存在するし、いまさら作る必要もないかもしれないが、メニュー操作、検索、コピーアンドペースト、オブジェクトをマウスで動かすなどの基本的なアルゴリズムの使い方を学ぶことができる。

そのときのポイントとしては、すべてのアプリケーションにせよ、オブジェクトのメソッドにせよ、入力とその処理と出力があるということだ。入力と出力に注目することでどのような情報が必要でどのような処理をし、どのように出力すればよいか分かるようになる。

たとえば、オブジェクトをマウスで動かしたいときは、左ボタンを押した時のマウスの位置情報とオブジェクトの位置情報を取得する。その時のマウスの位置情報とオブジェクトの相対距離を計算しておいて、マウスの新しい位置についてオブジェクトの位置のプロパティを設定する。それをマウスボタンが押されている間続けるというプログラムを組まなくてはならない。

こういうプログラムをいきなり組めるようにはならないが、この操作をするためにマウスの位置情報の取得が大切であることが分かる。そうすると、マウスの位置情報を取得するのは、System.Cursor.Positionプロパティを取得すればよいことが分かる。

そこで、Visual C#でプロジェクトを作り、Label コントロールを3個ほど張り付けた後、フォームを選択する。プロパティウィンドウでイベントを表示させ、Click イベントをダブルクリックする。そうしてコードエディタに次のコールバックメソッドを作成すると、フォームの中をクリックしたときの情報を表示させることができる。

private void Form1_Click(object sender, EventArgs e)
{
    label1.Text = Cursor.Position.ToString();
    label2.Text = Cursor.Position.X.ToString();
    label3.Text = Cursor.Position.Y.ToString();
}

こういうマウスコントロールに基本的なプログラムをいくつか作って感触を見ておけば、オブジェクトをマウスで移動させるなどのテクニックが分かってくる。

GUIプログラムを作るときに基本となるテクニックは、カーソル位置特にフォームとの相対位置の取得だ。Cursor.Position ではスクリーンでの位置が得られるだけなので、Formオブジェクトの、PointToClient() メソッドで相対位置に変換しなければならない。たとえば、次のようにする。

Point relPoint = this.PointToClient( Cursor.Position );

アプリケーションを作るためには、このような定石のようなスニペットがあるだろう。いまは、C#の学習を始めたばかりなのでよくわからないが、情報が集まったら、このブログでもまとめてみたい。
[PR]
by tnomura9 | 2010-01-24 12:49 | C# | Comments(0)

フォームにボタンを配置する。

Learn プロジェクトはフォームだけのプロジェクトで、何の仕事もやらせることができない。このフォームの上でプログラムを動かすためには、いろいろなコントロールを配置して使う必要がある。

そこで、Visual C# のツールボックスからボタンをクリックして、フォームの上でドラッグし、フォームの上にボタンを一つ配置した。そうすると、Form1.Designer.cs のコードが次のように変わる。

#region Windows フォーム デザイナで生成されたコード

///
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
///

private void InitializeComponent()
{
    this.button1 = new System.Windows.Forms.Button();
    this.SuspendLayout();
    //
    // button1
    //
    this.button1.(Location) = new System.Drawing.Point(79, 95);
    this.button1.Name = "button1";
    this.button1.Size = new System.Drawing.Size(137, 49);
    this.button1.TabIndex = 0;
    this.button1.Text = "button1";
    this.button1.UseVisualStyleBackColor = true;
    //
    // Form1
    //
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(284, 262);
    this.Controls.Add(this.button1);
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.Button button1;

ボタンを配置するためのコードが InitializeComponent() メソッドに追加され、System.Windows.Forms.Button 型のインスタンス変数 button1 が追加されている。

これだけでは、ボタンをクリックしても何も起こらないので、ボタンをクリックしたというイベントが発声したときに呼ばれるコールバックルーチンを記述する。フォームデザイナでボタンをダブルクリックするとコードエディターが現れてコードを入力する場所にカーソルが表示される。

フォームデザイナの操作で変更されたのは、今度は Form1.cs のファイルで次のようになる。

namespace Learn
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }
    }
}

コンストラクタの Form1() 以外に、コールバックメソッドの button1_Click() が新たに作られている。button1_Click() はイベントの発生したウィジェットとイベントの種類の情報が引数としてとるようだ。しかし、このコードではボタンをクリックした時のイベントと button1_Click() メソッドを結びつけるコードがない。この結びつきのコードは、Form1.Designer.cs の button1 を初期化するところに

this.button1.Click += new System.EventHandler(this.button1_Click);

と記述してあった。

(Form1.Designer.cs の抜粋)
//
// button1
//
this.button1.(Location) = new System.Drawing.Point(79, 95);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(137, 49);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);

button1 がクリックされた時のイベントのとコールバックメソッドを関連付けるには、button1 オブジェクトのClick プロパティに System.EventHnadler(this.button_Click) オブジェクトを追加することで行われているようだ。

button_Click 以外のイベントのコールバックを記述したいときは、フォームデザイナでボタンを選択して、プロパティウィンドウのツールバーのイナズマのアイコンのあるイベントボタンをクリックし、表示されたイベントをダブルクリックすればいい。

C#ではイベント処理のルーチンは .NET が System.Forms.Application.Run() メソッドで処理するため、コードの記述のなかには現れない。書くウィジェットで発生するイベントとコールバックルーチンとの関連付けは、ウィジェットのイベント関連のプロパティにイヴェントハンドラオブジェクトを登録することで行われる。
[PR]
by tnomura9 | 2010-01-24 08:22 | C# | Comments(0)

Form1.cs

フォームのクラスを記述している、Form1.cs の using 文を省略したものが次の部分だ。

namespace Learn
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

.NET の Form (System.Windows.Forms.Form) クラスから導出して、自分のアプリケーション用の Form1 を作るようになっている。Form1 クラスと同じ名前のメソッド、Form1() はコンストラクタで、 new Form1() で Form1 のインスタンスを生成するときに、最初に実行される。インスタンスの初期化を行うメソッドだ。ここでは、InitializeComponent() メソッドを実行するようになっている。

クラスの定義は partial キーワードを使うとファイルがわかれていても同じクラスについてのプログラムができるから、InitializeComponent() メソッドは別のファイル、Form1.Desiner.cs に記述されている。

namespace Learn
{
    partial class Form1
    {
        /// <summary>
        /// 必要なデザイナ変数です。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows フォーム デザイナで生成されたコード

        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }

        #endregion
    }
}

上のプログラムで、Dispose メソッドはおそらくデストラクタだ。もう一つの InitializeComponent() が、Form1.cs のコンストラクタで呼び出されていたメソッドだ。InitializeComponent() の中では、components 属性に、System.components.ComponentModes.Container クラスのインスタンスを収め、Text 属性に "Forn1" を収めてフォームの属性を設定しているが、フォームの属性全部を記述する必要はなく、他はデフォールト値が使えるようだ。

ただし、componets インスタンス変数は

private System.ComponentModel.IContainer components = null;

で初期化しておく必要があるようだが、理由は今のところわからない。フォームのプロパティを変更したらこの InitializeComponent() の部分のコードが変化するのだろうと思ったので、Form1 をデザインビューで表示して、プロパティウィンドウで FormBorderStyle を Fixed3D に変更してみたら、次のように変わっていた。

private void InitializeComponent()
{
    this.SuspendLayout();
    //
    // Form1
    //
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(284, 263);
    this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
    this.Name = "Form1";
    this.Text = "Form1";
    this.Load += new System.EventHandler(this.Form1_Load);
    this.ResumeLayout(false);

}

FormBorderStyle プロパティを変更しただけでこれだけの記述変更が行われるのだから、デザインビューであれこれコントロールを張り付けていたらどれくらいの記述になるのだろうと感動した。デザインビューでフォームをいじるのは立派なプログラミングの作業だったのだ。

そうなると、.NET のウィジェット関連のクラスの名前やプロパティの名前を覚えたりという作業はあまり必要がないということになる。デザインビューで直観的に作業したり、プロパティウィンドウでプロパティの設定をしたことがすべてプログラムとして記述されていくからだ。何の気もなくマウスで作業していたことが、実際はすごい量のプログラムを記述する作業だった。

実際、個人的に使いたいアプリケーションの大半は、フォームに入出力用の数個のTextBox を配置して計算用のボタンを配置したらそれをダブルクリックしてコールバック関数を記述するくらいのプログラミングで済んでしまう。実用的には、Visual C# の入門書をちょっと読むだけでもう立派なC#プログラマだ。
[PR]
by tnomura9 | 2010-01-23 16:40 | C# | Comments(0)