【.NET】ボタンにラベルを重ねて表示する

  • 2
    いいね
  • 0
    コメント

はじめに

これは、Visual Basic Advent Calendar 2016の12/1日の記事。

お仕事でメニューとして4つボタンがあり、各ボタンをクリックすると別画面が起動するというよくある仕様書をいただきました。その内の2つのメニューのボタン上には表示名とは別に注釈コメントも一緒に書かれていました。
仕様書はExcel方眼紙で画面が作成されており、ボタンの表示名と注釈コメントのフォントの大きさが違っています。

実現方法

ボタンのテキスト(Text)プロパティに表示名と注釈コメントを改行文字を含めて一緒に表示する方法も考えたのですが、注釈コメントが無い他のボタンと比べると見た目が良くありません。
やはり見た目を考慮すると、ボタンの上に注釈コメントのラベルコントロールを重ねる方法を思いつきました。これなら注釈コメントだけフォントを小さくして表示することができます。

これを実現する上で3つ問題が発生しましたが、無事解決することが出来ました。

ButtonOnLabel.png

問題点1

ボタンの上にラベルを貼り付けることは出来ましたが、ラベルの背景色(BackColor)を透明(Transparent)にしても透明にならない。

解決方法1

PictureBoxコントロールの上に配置したLabelコントロールはBackColorプロパティをTransparentにしても透明になったようには見えません。これはLabelコントロールの親コントロールがフォームであり、フォームにあわせてLabelコントロールの背景が設定されるためです。
よってこの問題を解決するには、Labelの親コントロールをPictureBoxにすればよい訳です。
出展:PictureBox上のLabelの背景が透明にならない問題の解決法

PictureBoxの例でしたが、Buttonでも同じ方法で解決することが出来ました。

' ラベルの親コントロールをボタンにする
Me.btnTest.Controls.Add(Me.lblComment)
' 表示位置を調整
Me.lblComment.Top = Me.lblComment.Top - Me.btnTest.Top
Me.lblComment.Left = Me.lblComment.Left - Me.btnTest.Left

問題点2

注釈コメントの部分をクリックしても何も反応しない。

解決方法2

これは単純に、注釈コメントであるラベルコントロールのクリックイベントを設定して、ボタンのクリックと同じ処理を呼ぶようにします。

問題点3

ボタンはマウスオーバー時にデフォルトで背景色とボーダーが青っぽく変わるのですが、注釈コメントの部分にマウスに合わせてもボタンの背景色は何も変わらない。

解決方法3

注釈コメントはラベルコントロールであるため、マウスオーバー時は何もしません。
これを実現するには、注釈コメントのラベルコントロールのマウスエンターイベントでボタンのマウスエンター処理を呼んであげればいいのですが、OnMouseEnterメソッドは、プロテクト(Protected)メソッドになっていて、通常では外部クラスからは呼び出すことができません。
Buttonクラスの派生クラスを作ればできるのですが、また面倒だな思っていたところで下記サイトを見つけました。

リフレクションを使用して、DoClickメソッドを呼び出す
「隠蔽されている非パブリックメンバを呼び出す」で紹介している方法を使えば、プロテクトメソッドであるDoClickメソッドも外部から呼び出すことができます。しかしこの方法はかなり強引な方法ですので、できれば避けた方が良いです。
出展:Buttonのクリックイベントを発生させる

Clickの例でしたがMouseEnterでも同じ方法で解決することが出来ました。
ラベルコントロールのマウスエンターイベントで下記処理を実行しています。

Me.btnTest.GetType().InvokeMember("OnMouseEnter",
                    System.Reflection.BindingFlags.InvokeMethod Or
                    System.Reflection.BindingFlags.NonPublic Or
                    System.Reflection.BindingFlags.Instance,
                    Nothing,
                    Me.btnTest,
                    New Object() {EventArgs.Empty})

最後に

参考にしたサイトは目的のものとは違う内容でしたが、中身を理解していれば他にも応用が出来るわけです。