状況に応じて、メニュー項目が変化してほしい場合があります。
この章では、メニューによりクライアント領域に表示されるイメージを変更するプログラムを作ります。まずは、次のようなgif画像を用意します。
![]()  | ![]()  | 
| cat1.gif | cat2.gif | 
まず、できあがりのプログラムの動作を見てみましょう。
クライアント領域に画像が表示されていないとき、メニューの「ファイル」をクリックすると「猫1」「猫2」「終了」のメニュー項目が見えます。
メニューから「猫1」を選択すると、cat1.gifの画像がクライアント領域に表示されます。その後、メニューの「ファイル」をクリックすると、「猫2」「画像なし」「終了」のメニュー項目が見えます。「猫1」の画像が見えているのに、メニューに「猫1」があっても意味が無いので、「猫1」は非表示になっています。代わりに「画像なし」のメニュー項目が出てきました。
画像2が表示されているときは、メニュー項目「画像2」が非表示になっています。
では、どのようにして実現するかを見ていきましょう。
まず、メニュー項目を非表示にするには、MenuItemのVisibleプロパティをfalseに設定します。
public bool Visible { get; set; }
では、いつMenuItem.Visibleをfalseにすれば、よいのでしょうか。これは、「ファイル」メニュー項目に、ポインタが来たときに、行うのが最適です。
メニュー項目にポインタが置かれると、MenuItem.Selectイベントが発生します。
public event EventHandler Selectこれで、大まかな仕組みはわかったと思います。
で、画像をクライアント領域に表示するにはどうしたらよいのでしょうか。実は、これはすでにもう第25章でやっています。Graphics.DrawImageメソッドを使えばよいですね。描画のタイミングは、もちろんPaintイベントが発生したときです。
では、プログラムを見てみましょう。
// menuselect01.cs
using System;
using System.Drawing;
using System.Windows.Forms;
class menuselect01 : Form
{
    Bitmap bmp, bmp1, bmp2;
    int nBmp;
    MenuItem miCat1, miCat2, miZero; 
    public static void Main()
    {
        menuselect01 ms = new menuselect01();
        Application.Run(ms);
    }
    public menuselect01()
    {
        Text = "猫でもわかるC#プログラミング";
        BackColor = SystemColors.Window;
        bmp1 = new Bitmap(GetType(), "menuselect01.cat1.gif");
        bmp2 = new Bitmap(GetType(), "menuselect01.cat2.gif");
        bmp = null;
        nBmp = 0;
        miCat1 = new MenuItem("猫1");
        miCat1.Click += new EventHandler(miCat1_Click);
        miCat2 = new MenuItem("猫2");
        miCat2.Click += new EventHandler(miCat2_Click);
        miZero = new MenuItem("画像なし");
        miZero.Click += new EventHandler(miZero_Click);
        MenuItem miLine = new MenuItem("-");
        MenuItem miExit = new MenuItem("終了(&X)");
        miExit.Click += new EventHandler(miExit_Click);
        MenuItem miFile = new MenuItem("ファイル(&F)",
            new MenuItem[] { miCat1, miCat2, miZero, miLine, miExit });
        miFile.Select += new EventHandler(miFile_Select);
        Menu = new MainMenu(new MenuItem[] { miFile });
    }
    void miFile_Select(object sender, EventArgs e)
    {
        miCat1.Visible = true;
        miCat2.Visible = true;
        miZero.Visible = true;
        switch (nBmp)
        {
            case 0:
                miZero.Visible = false;
                break;
            case 1:
                miCat1.Visible = false;
                break;
            case 2:
                miCat2.Visible = false;
                break;
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (nBmp != 0)
        {
            Graphics g = e.Graphics;
            
            Rectangle rc = new Rectangle();
            rc.X = (ClientRectangle.Width - bmp.Width) / 2;
            rc.Y = (ClientRectangle.Height - bmp.Height) / 2;
            rc.Width = bmp.Width;
            rc.Height = bmp.Height;
            g.DrawImage(bmp, rc);
        }
    }
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        Invalidate();
    }
    void miCat1_Click(object sender, EventArgs e)
    {
        bmp = bmp1;
        nBmp = 1;
        Invalidate();
    }
    void miCat2_Click(object sender, EventArgs e)
    {
        bmp = bmp2;
        nBmp = 2;
        Invalidate();
    }
    void miZero_Click(object sender, EventArgs e)
    {
        nBmp = 0;
        Invalidate();
    }
    void miExit_Click(object sender, EventArgs e)
    {
        Close();
    }
}
Mainメソッドの存在するmenuselect01クラスは、Formクラスを継承しています。bmp, bmp1, ...などのインスタンスフィールドが存在することに注意してください。 これは、このクラスのどのメソッドからもこれらを参照したり、書き込んだりできるようにするためです。(あるメソッドが書き込んで、他のメソッドが参照したりする)
Mainメソッドは、いつも通り簡単な物です。
コンストラクタでは、Bitmapオブジェクトを作成し、その参照をインスタンスフィールドに代入しています。bmpには、メニューで選択した内容に応じてbmp1やbm2の値が代入されます。初期段階ではnullにしています。
nBmpには、現在どのイメージが表示してあるかを示す値が代入されます。0は何も表示されていない、1はcat1.gifのイメージが表示されている、2はcat2.gifのイメージが表示されていることを表しています。
次に、今まで通りメニューを作成しています。
「ファイル」メニュー項目に対して、これがポイントされた時に発生するSelectイベントに対するハンドラがインストールされている点に注意してください。
miFile_Selectメソッドは、「ファイル」メニュー項目がポイントされた時に、呼び出されます。
ここでは、いったん「猫1」「猫2」「画像なし」のメニュー項目を「表示」に設定してその後、nBmpに応じて非表示項目を決めています。
OnPaintメソッドでは、実際のイメージ描画を行っています。nBmpが0でないときは、bmpを表示しています。bmpの中身は、メニューからどの画像を選択したかで異なっています。 また、イメージの表示がクライアント領域の中央に来るようにしてあります。ClientRectangleは、Formクラスのプロパティで、クライアント領域を表す四角形を取得します。
public Rectangle ClientRectangle { get; }
フォームのサイズが変更されたとき(OnSizeChanged)は、Invalidateメソッドを呼んでいます。これで、サイズ変更時にPaintイベントが発生して画像がクライアント領域の中央になるように再描画が起こります。 OnSizeChangedメソッドはSystem.Windows.Forms名前空間で定義されています。
protected virtual void OnSizeChanged ( EventArgs e )xxx_Clickは、それぞれのメニュー項目がクリックされたときに呼び出される自作ハンドラです。「猫1」メニュー項目がクリックされたら、bmpをbmp1に設定します。そして、nBmpを1にします。そして、Invalidateメソッドを呼び出すと、再描画が起こりクライアント領域にcat1.gifのイメージが表示されます。
ひとつ、ひとつ見ていくと大して難しくないことがわかりますね。
Update 11/Nov/2006 By Y.Kumei