在MFC程序設計中,經常有這樣的問題:點擊一個菜單項啓動某項功能,再點擊一次取消該功能,再點擊又啓動該功能,再點擊又取消該功能.......。尤其是有多個菜單項功能的時候,如何有效組織各個菜單項各自的狀態,保證互不干擾,且實現簡練。
本文以一個三維繪圖程序爲例,介紹使用異或狀態運算實現菜單項功能的啓用與關閉。假設在三維場景中有5種場景要素:天空、地面、房屋、道路、樹木。程序要求實現這樣的功能:控制各種場景要素的顯示和不顯示。
考慮使用菜單項來實現,創建五個菜單項: ViewSky(ID_VIEW_SKY)、 ViewGround(ID_VIEW_GROUND)、ViewBuilding(ID_VIEW_BUILDING)、ViewRoad (ID_VIEW_ROAD)、ViewTree(ID_VIEW_TREE)。
通過添加事件處理程序創建菜單項的消息響應函數:
C3DView::OnViewSky()
C3DView::OnUpdateViewSky(CCmdUI *pCmdUI)
C3DView::ViewGround()
C3DView::OnUpdateViewGround(CCmdUI *pCmdUI)
C3DView::ViewBuilding()
C3DView::OnUpdateViewBuilding(CCmdUI *pCmdUI)
C3DView::ViewRoad ()
C3DView::OnUpdateViewRoad(CCmdUI *pCmdUI)
C3DView::OnViewTree()
C3DView::OnUpdateViewTree(CCmdUI *pCmdUI)
在C3DView類的頭文件中聲明一個枚舉類型的變量,並給每個變量付上十六進制的值:
enum EViewSettings
{
VIEW_SKY = 0x000001,
VIEW_GROUND = 0x000002,
VIEW_BUILDING = 0x000004,
VIEW_ROAD = 0x000008,
VIEW_TREE = 0x000010
};
聲明一個int型變量m_iViewSettings用來記錄當前渲染狀態值。
在View類構造函數中,定義m_iViewSettings = VIEW_SKY|VIEW_GROUND|VIEW_BUILDING|VIEW_ROAD |VIEW_TREE ;m_iViewSettings 是枚舉變量中各項的或運算值,表明初始場景繪製了所有要素。
下面以天空要素的控制爲例說明:
//C3DView.cpp
void C3DView::OnViewSky()
{
//把當前記錄的繪製狀態賦給局部變量
int vs = m_iViewSetttings;
//////////////將當前狀態與枚舉變量VIEW_SKY進行異或運算,如果當前狀態中標識繪製天空的位爲1,說明已經繪製了天空,異或運算後標識位變爲0,表明此次消息響應將繪製狀態中標識天空繪製的位置爲0,表明不繪製天空;同理,如果當前狀態中標識天空繪製的位爲0,說明當前沒有繪製天空,異或運算後標識爲變爲1,表明此次消息響應後將要繪製天空。
vs ^= VIEW_SKY;
m_iViewSetttings = vs;
/////////更新場景;
Invalidate();
}
void C3DView::OnUpdateViewSky(CCmdUI *pCmdUI)
{
//當天空繪製時,菜單項顯示被選中
int vs = m_iViewSetttings
pCmdUI->SetCheck((vs & VIEW_SKY) != 0);
}
//////場景繪製
void C3DView::OnDraw()
{
....
...
....
if (m_iViewSettings & VIEW_SKY )
{
//繪製天空;
}
if (m_iViewSettings & VIEW_GROUND )
{
//繪製地面;
}
if (m_iViewSettings & VIEW_BUILDING )
{
//繪製房屋;
}
if (m_iViewSettings & VIEW_ROAD )
{
//繪製道路;
}
if (m_iViewSettings & VIEW_TREE )
{
//繪製樹木;
}
}