┏弟5号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜メニュー ■注意事項 ■.NET Tips ・メニューにアイコンを表示する2 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 ─────────────────────────────── ■注意事項 ─────────────────────────────── 今回はコードが長いため、VB.NETのコードのみを紹介します。ご了承 ください。C#のコードについては、私のサイトで紹介するかもしれま せん。 ─────────────────────────────── ■ピンポイントリンク ─────────────────────────────── ●メニューにアイコンを表示する2 前回メニュにアイコンを表示する方法についてその基礎を説明しまし たが、結局いくつかの問題が残ってしまいました。今回は前回作成し たImageMenuItemクラスをより使えるものに改善させます。 前回のImageMenuItemクラスの欠点として主に次の2点が挙げられます。 1.メニュー項目が無効になっているとき(EnabledがFalseになってい  るとき)の処理 2.チェックが付いているとき(CheckedがTrueのとき)の処理 まず1番目の問題ですが、これには文字列を立体的に灰色表示する方法 と、画像を立体的に灰色表示する方法の2つのテクニックが必要になり ます。 多分これが一般的なのではないかと思いますが、まずはAPIを使う方法 を紹介します。Win32 APIのDrawState関数を使うことにより、無効状 態の文字列や画像を描画できます。以下にDrawState関数を使った簡単 な使用例を示します。 (下記コード内のDrawStateString関数で描画した文字列の位置は、同 じ位置にGraphics.DrawStringメソッドで描画した文字列の位置よりわ ずかに左側にずれてしまいます。DrawState関数を使うのであれば、す べてにおいてDrawState関数を使って描画すべきかもしれません。) '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ 'API宣言 Private Declare Function DrawState Lib "user32" Alias "DrawStateA" _ (ByVal hDC As IntPtr, _ ByVal hBrush As Integer, _ ByVal lpDrawStateProc As Integer, _ ByVal lParam As IntPtr, _ ByVal wParam As Integer, _ ByVal n1 As Integer, _ ByVal n2 As Integer, _ ByVal n3 As Integer, _ ByVal n4 As Integer, _ ByVal un As Integer) As Integer Private Declare Function DrawStateString Lib "user32" _ Alias "DrawStateA" (_ ByVal hDC As IntPtr, _ ByVal hBrush As Integer, _ ByVal lpDrawStateProc As Integer, _ ByVal lpString As String, _ ByVal cbStringLen As Integer, _ ByVal n1 As Integer, _ ByVal n2 As Integer, _ ByVal n3 As Integer, _ ByVal n4 As Integer, _ ByVal un As Integer) As Integer Private Const DST_COMPLEX = &H0 Private Const DST_TEXT = &H1 Private Const DST_PREFIXTEXT = &H2 Private Const DST_ICON = &H3 Private Const DST_BITMAP = &H4 Private Const DSS_NORMAL = &H0 Private Const DSS_UNION = &H10 Private Const DSS_DISABLED = &H20 Private Const DSS_MONO = &H80 Private Const DSS_RIGHT = &H8000 'メニュー項目に表示させるアイコン Private _icon As New Icon("open.ico") 'メニュー項目の描画 Private Sub MenuItem2_DrawItem(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) _ Handles MenuItem2.DrawItem '無効状態のアイコンを描画 Dim hdc As IntPtr = e.Graphics.GetHdc() If Not (_icon Is Nothing) Then DrawState(hdc, 0, 0, _icon.Handle, 0, e.Bounds.Left + 2, _ e.Bounds.Top + (e.Bounds.Height - _icon.Height) \ 2, _ 16, 16, DST_ICON Or DSS_DISABLED) End If '無効状態の文字列を描画 DrawStateString(hdc, 0, 0, sender.Text, LenB(sender.Text), _ e.Bounds.Left + 22, _ e.Bounds.Top + _ (e.Bounds.Height - SystemInformation.MenuFont.Height) \ 2, _ e.Bounds.Width, e.Bounds.Height, _ DST_PREFIXTEXT Or DSS_DISABLED) '開放 e.Graphics.ReleaseHdc(hdc) End Sub 'VB6のLenBの代わりになるかもしれない関数 Private Function LenB(ByVal strString As String) As Integer 'Shift JISに変換したときに必要なバイト数を返す Return System.Text.Encoding.GetEncoding(932). _ GetByteCount(strString) End Function '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ APIを使わずに同じことができないものか調べたところ、それらしいメ ソッドを見つけました。それは、ControlPaintクラスの DrawImageDisabledメソッドとDrawStringDisabledメソッドです。いか にも「ビンゴ!」という感じの名前をしています。次にこれらのメソ ッドの使用例を示します。 '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ '無効状態のアイコンを描画 ControlPaint.DrawImageDisabled(e.Graphics, _ _image, x, y, SystemColors.Menu) '無効状態の文字列を描画 ControlPaint.DrawStringDisabled(e.Graphics, _ text, SystemInformation.MenuFont, _ SystemColors.ControlLightLight, _ New RectangleF(point.X, point.Y, _ e.Bounds.Width, e.Bounds.Height), _ sf) '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ これで期待通りの結果が得られるかといいますと、そううまくは行き ません。ControlPaint.DrawImageDisabledメソッドで描画された画像 は立体的ではなく、平面的な画像で描画されます。ControlPaint. DrawStringDisabledメソッドで描画された文字列は立体的にはなりま すが、よく見ると文字の色がちょっとだけ違います。(ControlPaint. DrawStringDisabledメソッドの4番目のパラメータ「文字列を描画する ためのColor」にどの値を入れても同じにならないようです。) こうなったら自分でなんとかすることにしましょう。無効状態の文字 列は影を縦横に1ドットずらして描画すればいいだけなので、簡単です。 問題は画像の方です。ここでは確実に、元の画像を1ドットずつ調べて、 新しく無効状態の画像を作成する方法を考えます。次にその例を示し ます。 (ここでは白のみを透明にしていますが、これには何の根拠もありま せん。 bmp.GetPixel(x, y).GetBrightness < 1.0F の1.0Fを別の値にしたほうがいいのかもしれません。どの値が適当な のかご存知の方がいらっしゃいましたら、ぜひ教えてください。) '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ '無効状態の画像を作成する Private Function CreateDisanabledImage(ByVal img As Image) _ As Image Dim x, y As Integer If img Is Nothing Then Return Nothing End If '無効状態の画像 元の画像より縦横1ドットずつ大きくなる Dim dbmp As New Bitmap(img.Width + 1, img.Height + 1) 'もとの画像 Dim bmp As New Bitmap(img) '1ドットずつ調べる For y = 0 To bmp.Height - 1 For x = 0 To bmp.Width - 1 '元の色が透明か、白を透明にする If bmp.GetPixel(x, y).A = &HFF AndAlso _ bmp.GetPixel(x, y).GetBrightness < 1.0F Then dbmp.SetPixel(x, y, SystemColors.ControlDark) dbmp.SetPixel(x + 1, y + 1, _ SystemColors.ControlLightLight) End If Next Next bmp.Dispose() Return dbmp End Function '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ 次に2番目の問題に移りたいところですが、予想以上に長くなってしま いましたので、今回はこの辺で終わりにさせていただき、続きはまた 次回とさせて頂きます。次回こそは完成させたいですね。 =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  http://dobon.net  dobon@bigfoot.com ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/bbs ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 DOBON! All rights reserved. ===============================