C#で作るWindowsアプリ
−メニューやボタンをくっつける−


[トップ] [目次] [←前] [次→]

メニューやボタンをくっつける

前回ののっぺらぼうのウインドウじゃ面白くもなんともないのでメニューやボタンをくっつけます。
今回もコードから


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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

namespace Sample2a {
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class MyForm : Form {
        // Main
        public static void Main(string[] args) {
            MyForm frm = new MyForm();
            Application.Run(frm);
        }
        
        // コンストラクタ
        public MyForm() {
            // メインメニューを生成
            MainMenu mm = new MainMenu();
            
            // ファイルメニューを生成
            MenuItem mi = mm.MenuItems.Add("ファイル(&F)");
            mi.MenuItems.Add(new MenuItem("開く(&O)..."));
            mi.MenuItems.Add("-");
            mi.MenuItems.Add(new MenuItem("終了(&X)", null, Shortcut.CtrlQ));
            
            // ヘルプメニューを生成
            mi = mm.MenuItems.Add("ヘルプ(&H)");
            mi.MenuItems.Add(new MenuItem("バージョン情報(&A)..."));
            
            // フォームのメニューとしてセット
            this.Menu = mm;
            
            // 開くボタンを生成
            Button btn = new Button();
            btn.Text = "開く...";
            btn.Location = new Point(2, 2);    // 座標を設定
            btn.Size = new Size(100, 22);      // サイズを設定
            btn.TabIndex = 0;                  // タブ順は最初
            btn.Anchor = AnchorStyles.Top | AnchorStyles.Left;  // 左上を固定
            this.Controls.Add(btn);
            
            // テキストボックスを生成
            TextBox txt = new TextBox();
            txt.Text = "";
            txt.Location = new Point(0, 26);   // 座標を設定
            txt.Size = new Size(this.ClientSize.Width, this.ClientSize.Height - 26);
                                               // サイズを設定
            txt.Multiline = true;              // 複数行OKにする
            txt.ScrollBars = ScrollBars.Both;  // スクロールバーを表示
            txt.BackColor = Color.White;       // 背景色を白にする
            txt.TabIndex = 1;                  // タブ順は2番目
            txt.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
                                               // 上下左右とも固定
            this.Controls.Add(txt);
        }
    }
}
Sample2a.cs

コンパイル

csc /t:winexe /r:System.DLL /r:System.Windows.Forms.DLL /r:System.Drawing.DLL Sample2a.cs

これでコンパイルできるはずです。
PointクラスやColorクラスはSystem.Drawingネームスペースにあります(なので、3行目のusingを追加してあります)。 また、これらはSystem.Drawing.DLLに入ってます。ですから、コンパイルするときも/rにSystem.Drawing.DLLを追加してやる必要があります。

メニューを作る

16行目からでメニューを作ってます。
MainMenuクラスも当然System.Windows.Formsネームスペースの中にあります。
メニューの場合は、メニュー自体が階層構造になってるので、

  1. MainMenuオブジェクトを作る
  2. MainMenuのMenuItems.AddメソッドでMenuItemを作る(これがファイルメニューとかの単位になります)
  3. 作ったMenuItemのAddメソッドでメニューの項目を追加していく(メニューの項目もMenuItemクラスです)
  4. 必要なだけメニューを作ったらMainMenuをフォームのメニューとしてセットする

ってな手順です(言葉で説明するよりコードを見たほうがわかりやすい気がするけど)。

22行目のようにショートカットとかも簡単に設定できます。

ボタンやテキストボックスを作る

32行目からボタンを、41行目からテキストボックスを作ってます。
作り方はほとんど同じで、

  1. オブジェクトを作る
  2. オブジェクトのプロパティを適当に設定する
  3. フォームに結びつける(this.Controls.Add)

という手順の繰り返しです。まぁ、コードを見てもらえばわかるでしょう。

それにしてもAnchorって便利ですよね。
文字通り指定したところにいかりをおろしてくれます。 試しにサンプルを実行してウインドウのサイズを変更してみてください。 テキストボックスもちゃんとウインドウサイズにあわせてサイズが変わります。 50行目のtxt.Anchor = ...のところをコメントアウトするとどうなるか試してみると違いが良くわかると思います。

できあがり?

確かにメニューやボタンがくっつきましたが、クリックしても何もおこりません。
そりゃそうです。クリックしたときに「何をするか」をまったく書いてないんですから。 というわけで..


イベントハンドラを追加する

これもコードから


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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

namespace Sample2b {
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class MyForm : Form {
        // Main
        public static void Main(string[] args) {
            MyForm frm = new MyForm();
            Application.Run(frm);
        }
        
        // コンストラクタ
        public MyForm() {
            // メインメニューを生成
            MainMenu mm = new MainMenu();
            
            // ファイルメニューを生成
            MenuItem mi = mm.MenuItems.Add("ファイル(&F)");
            mi.MenuItems.Add(new MenuItem("開く(&O)...", new EventHandler(this.FileOpen_Clicked)));
            mi.MenuItems.Add("-");
            mi.MenuItems.Add(new MenuItem("終了(&X)", new EventHandler(this.FileExit_Clicked), Shortcut.CtrlQ));
            
            // ヘルプメニューを生成
            mi = mm.MenuItems.Add("ヘルプ(&H)");
            mi.MenuItems.Add(new MenuItem("バージョン情報(&A)...", new EventHandler(this.HelpAbout_Clicked)));
            
            // フォームのメニューとしてセット
            this.Menu = mm;
            
            // 開くボタンを生成
            Button btn = new Button();
            btn.Text = "開く...";
            btn.Location = new Point(2, 2);    // 座標を設定
            btn.Size = new Size(100, 22);      // サイズを設定
            btn.TabIndex = 0;                  // タブ順は最初
            btn.Anchor = AnchorStyles.Top | AnchorStyles.Left;  // 左上を固定
            btn.Click += new EventHandler(this.OpenButton_Clicked);
            this.Controls.Add(btn);
            
            // テキストボックスを生成
            TextBox txt = new TextBox();
            txt.Text = "";
            txt.Location = new Point(0, 26);   // 座標を設定
            txt.Size = new Size(this.ClientSize.Width, this.ClientSize.Height - 26);
                                               // サイズを設定
            txt.Multiline = true;              // 複数行OKにする
            txt.ScrollBars = ScrollBars.Both;  // スクロールバーを表示
            txt.BackColor = Color.White;       // 背景色を白にする
            txt.TabIndex = 1;                  // タブ順は2番目
            txt.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
                                               // 上下左右とも固定
            Controls.Add(txt);
        }
        
        // ファイル−開くメニューのイベントハンドラ
        private void FileOpen_Clicked(object sender, EventArgs e) {
            MessageBox.Show("ファイル−開くメニューがクリックされました.");
        }
        
        // ファイル−終了メニューのイベントハンドラ
        private void FileExit_Clicked(object sender, EventArgs e) {
            this.Close();
        }
        
        // ヘルプ−バージョン情報メニューのイベントハンドラ
        private void HelpAbout_Clicked(object sender, EventArgs e) {
            MessageBox.Show("Sample2bプログラム Ver 0.1");
        }
        
        // 開くボタンのイベントハンドラ
        private void OpenButton_Clicked(object sender, EventArgs e) {
            MessageBox.Show("開くボタンがクリックされました.");
        }
    }
}
Sample2b.cs

コンパイル

コンパイルはSample2aと同じです(ファイル名がSample2bとなっただけ)。

イベントハンドラの追加

イベントハンドラなんて呼んでますが、どうってことありません。 単なるメソッドです。で、それを「メニューがクリックされたらこのメソッドを呼んでね」といった感じで登録するだけです。
20行目なんかのnew EventHandler(this.FileOpen_Clicked)なんて風に追加した引数がそれです。
new EventHandlerで囲んでるのは「そういうもの」と思ってもらっていいです(delegateっていう仕組みなんですが、説明すると長くなるので)。 要は「クリックされたらFileOpen_Clickedメソッドを呼んでね」っていうことです(thisを付けてるのは「このクラスの」っていうのがわかりやすくなるようにしてるだけです。省略してもまったく問題ありません)。

メニューはコンストラクタに引数を追加するという形でしたが、ボタンなどはちょっと違います。
38行目のようにClickプロパティにイベントハンドラを追加するって形になります。これも、こういう書き方をするってことでいいと思います。
リファレンスを見てもらうとわかるようにClick以外にも「キーが押されたとき」「フォーカスを得たとき」「フォーカスを失ったとき」などなどたくさんのイベントが用意されています。

イベントハンドラ自体は?

56行目以降のように普通のメソッドとして書くだけです。
みんなprivate void メソッド名(object sender, EventArgs e)という形になってますが、これはイベントごとに決まってます。 といっても変わるのはEventArgsの部分だけです。 たとえば、KeyPressイベント(「キーが押されたとき」)の場合EventArgsではなくKeyPressEventArgsになります。 これもちゃんとリファレンスに載ってます。

1番目の引数senderには「そのイベントが発生したオブジェクト自体」が渡されます。 なので、たとえば、複数のボタンのイベントを1つのイベントハンドラで受けるようなことができます。


private void Buttons_Clicked(object sender, EventArgs e) {
    Button btn = sender as Button;
    if (btn.Text == "開く...") {
        MessageBox.Show("開くボタン");
    } else {
        MessageBox.Show("それ以外のボタン");
    }
}

こんな風にキャストしてやって適当なプロパティを調べればいいわけです(キャストにはas演算子を使ってます)。

2番目の引数eには「そのイベントの内容」が渡されます。 ただ、ClickイベントのようにEventArgsの場合はほとんど意味がありません。 まぁ、これは、イベント自体が「クリックされた」ことを表していて内容も何もないので当然でしょう。
KeyPressイベントのKeyPressEventArgsのような場合だと「なんのキーが押されたのか」などの情報が入っています。 これを使って処理すればいいわけです。

ちなみに、イベントハンドラのメソッド名は何でも構いません。 VB6では厳密にイベントハンドラの名前が決まってましたが(というか、名前でイベントハンドラかどうかを判断してた)、 C#の場合は自分で登録するのでどんな名前でもOKなわけです(VB.NETがどうなってるのかは知りません)。
ただ、もちろん、わかりやすい名前にしておいたほうがいいでしょう。


[トップ] [目次] [←前] [次→]

株式会社ディーバ 青柳 臣一
2002/03/05