在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 )
{
//绘制树木;
}
}