ソース内にコンテキストメニューの設定を記述する
表示する内容及び表示位置が完全に固定であるならば、デザイナ上でコントロールをセットする形でもよいかと思います。
ただ・・・
マウスクリック位置により
「メニューの表示内容を変更したい」
「表示位置を変更したい」
という場合にはデザイナで対応するよりは、C#のソース側でセットするほうが楽です。
Sponsored LinkContextMenuStripを使用する
まず、フォームのTreeViewロードのタイミングでContextMenuStripを作成します。
// ContextMenuStripの宣言
ContextMenuStrip sampleMenu = new ContextMenuStrip();
// コンテキストメニュー一番目
sampleMenu.Items.Add("一番目のメニュー", makeImage(1), (s, e) => {
// このコンテキストメニュー実行時の処理を記述
MessageBox.Show("一番目");
});
// コンテキストメニュー二番目
sampleMenu.Items.Add("二番目のメニュー", makeImage(2), (s, e) => {
// このコンテキストメニュー実行時の処理を記述
MessageBox.Show("二番目");
});
宣言したContextMenuStripオブジェクトに対して、Items.Addでメニューを追加していきます。
Items.Addの書き方はいくつかありますが、今回は3つの引数をセットする形で対応します。
一番目の引数は「メニューの表示文字列」
二番目の引数は「そのメニュー左側に表示する画像」
三番目の引数は「そのメニューをクリックした際に実行する処理」
となります。
上のソース例では「一番目のメニュー」という文字列のメニューが表示され、そのメニューをクリックした際に実行されるのは「一番目」というメッセージボックスが表示される、という単純な処理です。
実際には別画面を表示させたり、より複雑な処理を記述させることになるかと思います。
二番目の引数の「画像」ですが、実際にはResourcesに画像を事前に登録し、それを参照するのが一番楽かと思います。今回は、後述の画像オブジェクトを生成してセットする形とします。
Sponsored LinkImageオブジェクト生成
コンテキストメニューの左側にセットする画像、Imageオブジェクトをセットしますが、本来いちいちソース内で生成する必要はありません。
が、今回はImageオブジェクトをソースで生成し、セットします。
private Image makeImage(int pattern)
{
Bitmap canvas = new Bitmap(16, 16);
// Graphicsオブジェクトを生成
using (Graphics g = Graphics.FromImage(canvas))
{
// 文字から画像にします。Arial 11ポイントのフォント。
Font fnt = new Font("Arial", 11);
switch (pattern)
{
case 1:
// 引数に「1」が渡された場合 ⇒ ★
g.DrawString("★", fnt, Brushes.Blue, 0, 0);
break;
case 2:
// 引数に「2」が渡された場合 ⇒ ▼
g.DrawString("▼", fnt, Brushes.Red, 0, 0);
break;
}
// リソース解放
fnt.Dispose();
g.Dispose();
}
return canvas;
}
この関数は、文字列を画像にして返しています。引数の値により表示画像文字列を変える形です。
もちろんこれ以外の形でImageオブジェクトを生成して返してもよいかと思います。
Sponsored Linkクリックした場所により、表示位置・メニュー内容を変えたい
まず、表示位置。
これは単純に対象のContextMenuStripのShowメソッドの引数に「Point」を渡すだけです。
マウス位置の取得はTreeViewオブジェクトの「MouseDown」イベントで取得可能です。
treeView1.MouseDown += (s, e) => {
// マウス右クリック時のみ
if (e.Button == MouseButtons.Right)
{
// マウスカーソル位置
Point p = Cursor.Position;
// ContextMenuStripのShowメソッドにPointを渡して表示
sampleMenu.Show(p);
コンテキストメニューを表示させるのは「右クリック」時が多いかと思います。そのため、条件として「MouseButtons.Right(右クリック)」の場合のみとし、それ以外は処理は行わないものとします。
Cursor.Positionでその時点のPointを取得し、Showメソッドに渡してコンテキストメニュー表示です。
そして、メニュー内容。
クリックした位置によってメニュー内容を変えたい、などあるかと思います。なので、TreeViewのどの部分をクリックしているかを判定します。
treeView1.MouseDown += (s, e) => {
// マウス右クリック時のみ
if (e.Button == MouseButtons.Right)
{
// 右クリックをした箇所により処理を変える
switch (treeView1.HitTest(e.Location).Location)
{
case TreeViewHitTestLocations.Label:
// ラベル=テキスト部分の位置
TreeNode node = treeView1.GetNodeAt(e.X, e.Y);
switch (node.Level)
{
case 0:
// 親(トップ)ノード
break;
case 1:
// 子ノード
break;
default:
// もっと階層がある場合はそれに合わせて記述
break;
}
break;
case TreeViewHitTestLocations.PlusMinus:
// ノード折り畳みのプラスマイナスの位置
break;
case TreeViewHitTestLocations.RightOfLabel:
// TreeViewのテキスト領域の右側の位置
break;
case TreeViewHitTestLocations.None:
// ノードやノードの一部では無い位置
break;
case TreeViewHitTestLocations.BelowClientArea:
// TreeViewの下側の位置
break;
}
HitTest.Locationを使用して、どの部分がクリックされているかを確認します。
TreeViewHitTestLocationsのオプションはいくつかありますが、そのうち主に使われるであろうオプション項目のみ記述します。
- Label → TreeViewのラベル(テキスト)自体
- PlusMinus → TreeViewの左側「+」マーク部分
- RightOfLabel → TreeViewの右側余白部分
- BelowClientArea → TreeViewの下部余白部分
Labelをクリックした際には、「親ノード」「子ノード」など、どのレベルのノードがクリックされたかを確認したい場合があるかと思います。
その場合には「GetNodeAt」でTreeNodeオブジェクトを取得し、「Level」を参照することでどのレベルノードがクリックされたか判定することができます。
上から「0」「1」「2」・・・となります。
Sponsored Linkまとめ
treeView1.MouseDown += (s, e) => {
// マウス右クリック時のみ
if (e.Button == MouseButtons.Right)
{
Point p = Cursor.Position;
ContextMenuStrip sampleMenu = new ContextMenuStrip();
sampleMenu.Items.Add("一番目のメニュー", makeImage(1), (ss, ee) => {
// このコンテキストメニュー実行時の処理を記述
MessageBox.Show("一番目");
});
sampleMenu.Items.Add("二番目のメニュー", makeImage(2), (ss, ee) => {
// このコンテキストメニュー実行時の処理を記述
MessageBox.Show("二番目");
});
// 右クリックをした箇所により処理を変える
switch (treeView1.HitTest(e.Location).Location)
{
case TreeViewHitTestLocations.Label:
// ラベル=テキスト部分の位置
TreeNode node = treeView1.GetNodeAt(e.X, e.Y);
switch (node.Level)
{
case 0:
// 親(トップ)ノード
sampleMenu.Items.Add("親用メニュー", null, (ss, ee) => {
// このコンテキストメニュー実行時の処理を記述
MessageBox.Show("親メニュー");
});
break;
case 1:
// 子ノード
break;
default:
// もっと階層がある場合はそれに合わせて記述
break;
}
break;
case TreeViewHitTestLocations.PlusMinus:
// ノード折り畳みのプラスマイナスの位置
break;
case TreeViewHitTestLocations.RightOfLabel:
// TreeViewのテキスト領域の右側の位置
break;
case TreeViewHitTestLocations.None:
// ノードやノードの一部では無い位置
break;
case TreeViewHitTestLocations.BelowClientArea:
// TreeViewの下側の位置
break;
}
// コンテキストメニュー表示
sampleMenu.Show(p);
}
};
private Image makeImage(int pattern)
{
Bitmap canvas = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(canvas))
{
Font fnt = new Font("Arial", 11);
switch (pattern)
{
case 1:
g.DrawString("★", fnt, Brushes.Blue, 0, 0);
break;
case 2:
g.DrawString("▼", fnt, Brushes.Red, 0, 0);
break;
}
fnt.Dispose();
g.Dispose();
}
return canvas;
}
この例では「MouseDown」のタイミングでContextMenuStripを生成していますが、コンテキストメニューのパターンがそんなに多くないのであれば、事前に生成しておき、クリック箇所によってContextMenuStripオブジェクトを単純にShowする形のほうがすっきりするかと思います。