現在有不少的軟件都有這樣的一種界面效果:當用戶單擊某一個按鈕之後,並不
是簡單地執行某種功能或彈出一個對話框,而是在按鈕旁邊彈出一個菜單,讓用
戶作更詳細地選擇,這在某種程度上就代替了簡單的對話框,而且較對話框更
為"用戶友好"。這樣的按鈕基本上有兩種類型:在按鈕上顯示文字的和在按鈕
上顯示箭頭的,顯示箭頭常見的有向右的和向下的兩種,還有向上的和向左的。
圖示為常見的風格,即向下的箭頭和在按鈕左下角彈出菜單。那麼,我們在編
程時如何實現這一功能呢?
---- 我們知道,MFC中的CButton類有一個虛函數名叫DrawItem(),若在對話框
模板中為控件指定了BS_OWNERDRAW風格,則在運行時將調用這個函數來畫按鈕,
而CMenu類的成員函數TrackPopupMenu()則可以在屏幕的任何位置彈出菜單。由
上得到啟發,只要我們合理地使用這兩個函數,就能創建出"菜單按鈕"來。
---- 下面的CMenuButton類封裝了全部的這些功能,讓我們先來看一下它的制作
原理。
---- 在取得了按鈕的矩形區域之後,取其一個角落的值傳遞給
TrackPopupMenu()函數即可實現彈出菜單,在TrackPopupMenu內部使用
TPM_RETURNCMD標志可以得到用戶選擇的菜單的命令ID,以供進一步的處理;
在重載了DrawItem()函數之後,我們可以在函數的內部使用
CDC::DrawFrameControl()函數來畫出基本的按鈕外觀,再在中間部位畫一個箭
頭即可。箭頭可以用Marlett字體來畫。也許有人會擔心,若果其他人的機器沒
裝Marlett字體怎麼辦?其實,任何一台安裝Windows的機器離開了Marlett字體
都無法正常工作,先請看下圖,這是Windows"系統工具"中自帶的"字符映射表"。
---- 看到最上面一行中的那幾個箭頭了嗎?就是要把它們畫在按鈕上。等一等,
另外的幾個符號怎麼也那麼熟悉?這不就是幾乎每個窗口上都有的"最小化"、
"還原"、"關閉"和"最大化"按鈕嗎?不錯,Windows正是使用這幾個字符在標題
欄上繪圖的。其實,Windows中的最"標准"的畫箭頭的方法就是使用Marlett字
體,無論是工具欄上的箭頭還是組合框中的箭頭,都是這樣畫出的。有時,在亂
刪了字體之後,組合框或工具欄的下拉箭頭會變成數字6或者9,為什麼?看到
狀態欄上的"擊鍵值"了嗎?--"6",往右數,那個小一點的下箭頭正好是--"9"。
---- 下面是具體的制作過程。
---- 首先,生成一個MFC AppWizard EXE 工程,最好是基於對話框的工程,當
然,利用現有的工程也可以。生成一個以CButton為基類的新類,名為
CMenuButton,然後用ClassWizard為其添加兩個成員函數:DrawItem()
和PreSubclassWidnow();手工為CMenuButton類添加BOOL類型m_bDrawFocusRect
成員變量,用於決定是否在按鈕上畫焦點矩形,添加SetDrawFocusRect()函數用
於設置這個標志,默認為畫焦點矩形;添加兩個枚舉類型的變量m_ArrowType和
m_PopupPos,用於決定所畫的箭頭的類型和菜單彈出的位置。箭頭可為右箭頭、
下箭頭、小右箭頭、小下箭頭、上箭頭和左箭頭(參見本文開始處的圖);菜單
的彈出位置可以為按鈕的左上角、右上角、左下角和右下角。最後手工添加兩
個函數,SetArrowType()和SetMenuPopupPos(),用於設置以上各種風格,其默
值分別為畫右箭頭和在左下角彈出。如果只需要菜單而不需要畫箭頭,只需置空
BS_OWNERDRAW標志位即可,添加一個SetStyle()函數,用於設置是畫箭頭還是顯
示文本,其默認值是畫箭頭。 為方便處理按鈕的BN_CLICKED通知消息,為
CMenuButton類創建一個公有的成員函數OnClick(),以便在BN_CLICKED的消息處
理器中調用。它有兩個參數,第一個是菜單資源的ID,第二個參數為子菜單的
ID,默認為0。如果只有一組子菜單,則可使用其默認值0。OnClick()函數的
返回值為所選的菜單項的命令ID,若未作任何有效選擇,則返回0。