SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

デザイン性に優れた拡張メニューコントロール

LuxMenuの内部構造の詳細を理解する

デザイン性に優れた拡張メニューコントロール 第3回


CMenuItemDataクラス

 一般的なWindowsメニューコントロールであれば、GetMenuItemInfo関数でメニューに関する詳細情報を取得できますが、LuxMenuは拡張データをすべて自前で持ち、いざと言うときに引き出して描画などの処理を行わなければなりません。そこで、アイテム単位で詳細なデータを管理するためのクラスとしてCMenuItemDataの定義を行います。

 CLuxMenuまたはCLuxSubMenuのインスタンスがCMenuItemDataクラスのインスタンスを複数個(アイテムの個数分)所有する形になります。以下に示すメンバを持ちます。

CMenuItemDataクラスのメンバ一覧
メンバ名 説明
item_index メニューアイテムの位置(一番上のアイテムが0)。
dwItemID メニューアイテムのID。
str 表示する文字列。
pobj_ThisMenu このアイテムが所属するCLuxMenuクラスのインスタンスへのポインタ。
pobj_SubMenu メニューアイテムがポップアップ可能な場合の、CLuxSubMenuクラスのインスタンスへのポインタ。
hIcon アイコンハンドル。
hGrayIcon 淡色表示時のアイコンハンドル。

 また、メニューアイテムに対してWM_MEASUREITEMWM_DRAWITEMの各メッセージを処理する必要があるため、CLuxMenuの各メソッドに処理を引き渡すためのコードも用意しておきます。

 ここで、メッセージの流れをおさらいしておきましょう。

 WM_MEASURECLuxMenu.MeasureItemCMenuItemData.GetItemSizeCLuxMenu.GetItemSize

 WM_DRAWITEMCLuxMenu.DrawItemCMenuItemData.OwnerDrawCLuxMenu.OwnerDraw

CMenuItemDataクラスのGetItemSizeメソッド、OwnerDrawメソッド
'-------------------------------------------------------
' アイテムが属するメニューのサイズ取得メソッドの呼び出し
'-------------------------------------------------------
Virtual Sub GetItemSize(ByRef size As SIZE)
    pobj_ThisMenu->GetItemSize(item_index,size)
End Sub

'-------------------------------------------------------
' アイテムが属するメニューの描画メソッドの呼び出し
'-------------------------------------------------------
Virtual Sub OwnerDraw(hdc As HDC, ByRef ref_rc As RECT, bSelect As BOOL)
    pobj_ThisMenu->OwnerDraw(hdc,ref_rc,bSelect,item_index)
End Sub

COMインターフェイスの提供

 CLuxMenuクラス、CLuxSubMenuクラスを以下のようなインターフェイスとして外部から呼び出せるようにしてみましょう。

  • CLuxMenuクラス … ILuxMenuインターフェイス
  • CLuxSubMenuクラス … ILuxSubMenuインターフェイス

 Interfaceステートメントを利用して各メソッドを定義していきます。特筆することはありませんが、順番を間違えないようにしましょう。COMインターフェイスは順番を間違えるとひどい事態になりかねないので……。

 ILuxSubMenuILuxMenuと同等のメソッドを持っているため、そっくりそのまま継承してしまいましょう。また、LuxMenu_CreateInstance関数、LuxSubMenu_CreateInstance関数を定義して各インターフェイスの生成を可能にします。これらの関数はDLL用にコンパイルした場合に外部から呼び出せるよう、Export修飾子をつけてエクスポート関数に指定しておきます。

ILuxMenu、ILuxSubMenuの宣言
'----------------------------------
' ILuxMenu インターフェイス
'----------------------------------

'CLSID
Dim IID_ILuxMenu=[&H30B65E5A,&HB400,&H49A2, _
    [&HB0,&HE5,&H61,&H19,&HB7,&H53,&H4C,&H4A]] As GUID

'インターフェイス
Interface ILuxMenu
    Inherits IUnknown

    Sub ImportMenu(hMenu As HMENU)
    Function GetMenuHandle() As HMENU

    Function MeasureItem(lParam As LPARAM) As BOOL
    Function DrawItem(lParam As LPARAM) As BOOL

    Function CreateNewMenu() As BOOL
    Function EnableItem(itemIDorPosition As DWord,
        fEnable As DWord) As BOOL
    Function CheckItem(itemIDorPosition As DWord,
        fCheck As DWord) As BOOL
    Function IsChecked(itemIDorPosition As DWord,
        fByPosition As DWord) As BOOL
    Function RemoveItem(itemIDorPosition As DWord,
        fByPosition As DWord) As BOOL
    Function InsertItem(item_index As Long, pszText As LPSTR,
        dwItemID As DWord) As BOOL
    Function InsertPopupItem(item_index As Long, pszText As LPSTR,
        pobj_SubMenu As *ILuxSubMenu) As BOOL

    Function SetIcon(dwItemID As DWord, hIcon As HICON) As BOOL

End Interface

'インスタンス生成用の関数
Function Export LuxMenu_CreateInstance() As *ILuxMenu
    Dim pobj_Menu As *CLuxMenu
    pobj_Menu=New CLuxMenu()

    pobj_Menu->QueryInterface(IID_ILuxMenu,
        VarPtr(LuxMenu_CreateInstance))
End Function

'----------------------------------
' ILuxSubMenu インターフェイス
'----------------------------------

'CLSID
Dim IID_ILuxSubMenu=[&HDAD2F3BA,&HD34B,&H4fc2,
    [&H8A,&HDF,&H8C,&HD9,&H3F,&H05,&H0B,&HA6]] As GUID

'インターフェイス(ILuxMenuと同様)
Interface ILuxSubMenu
    Inherits ILuxMenu
End Interface

'インスタンス生成用の関数
Function Export LuxSubMenu_CreateInstance() As *ILuxSubMenu
    Dim pobj_SubMenu As *CLuxSubMenu
    pobj_SubMenu=New CLuxSubMenu()

    pobj_SubMenu->QueryInterface(IID_ILuxSubMenu,
        VarPtr(LuxSubMenu_CreateInstance))
End Function

まとめ

 今回、説明した内容がLuxMenuコントロールのすべてです。クラスの設計、独自描画モジュールの設計、インターフェイスの提供など、一連の流れにていねいに触れていきましたが、いかがだったでしょうか?

 これをお読みになって、ABを用いてCOMコンポーネントの開発をされる方が増えれば筆者としては嬉しい限りです。また、今回LuxMenuを通じてCOMコンポーネントについて説明しましたが、COMはまだまだ奥が深く、ABが提供するCOM機能もこれから向上していく可能性のある分野です。今後、COMコンポーネントを開発される皆さまのフィードバッグを受け止め、よりコンポーネント開発に特化した開発環境を提供できればと考えています。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
デザイン性に優れた拡張メニューコントロール連載記事一覧

もっと読む

この記事の著者

山本 大祐(ヤマモト ダイスケ)

普段はActiveBasicと周辺ツールの開発を行っています。最近は諸先輩方を見習いながら勉強中の身。AB開発日記

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/514 2008/08/26 13:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー