消息WM_POPMESSAGESTRING用来重新设置状态栏。
这两个消息对应的消息处理函数分别是OnSetMessageString和OnPopMessageString,OnSetMessageString和OnPopMessageString分别实现如下:
OnSetMessageString
LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM lParam)
{
//最近一次被显示的消息字符串IDS(一个消息对应的字符串)
UINT nIDLast = m_nIDLastMessage;
m_nFlags &= ~WF_NOPOPMSG;
//得到状态栏
CWnd* pMessageBar = GetMessageBar();
if (pMessageBar != NULL)
{
LPCTSTR lpsz = NULL;
CString strMessage;
//设置状态栏文本
if (lParam != 0) //指向一个字符串
{
ASSERT(wParam == 0); // can't have both an ID and a string
lpsz = (LPCTSTR)lParam; // set an explicit string
}
else if (wParam != 0)//一个字符串资源IDS
{
//打印预览时映射SC_CLOSE成AFX_IDS_PREVIEW_CLOSE;
if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc != NULL)
wParam = AFX_IDS_PREVIEW_CLOSE;
//得到资源ID所标识的字符串
GetMessageString(wParam, strMessage);
lpsz = strMessage;
}
//在状态栏中显示文本
pMessageBar->SetWindowText(lpsz);
// 根据最近一次选择的消息更新状态条所属窗口的有关记录
CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame();
if (pFrameWnd != NULL)
{
//记录最近一次显示的消息字符串
pFrameWnd->m_nIDLastMessage = (UINT)wParam;
//记录最近一次Tracking的命令ID和字符串IDS
pFrameWnd->m_nIDTracking = (UINT)wParam;
}
}
m_nIDLastMessage = (UINT)wParam; // new ID (or 0)
m_nIDTracking = (UINT)wParam; // so F1 on toolbar buttons work
return nIDLast;
}OnSetMessageString函数直接或者从ID从字符串资源中得到字符串指针。如果是从ID得到字符串指针,则函数GetMessageString被调用。
和命令ID对应的字符串由两部分组成,前一部分用于在状态栏显示,后一部分用于Tooltip显示,分隔符号是“”。例如,字符串ID_APP_EXIT(对应“退出”菜单、按钮)是“Exit ApplicationExit”,当鼠标落在“退出”按钮上时,状态栏显示“Exit Application”,Tooltip显示“Exit”。根据这种格式,GetMessageString分离出第一部分的文本信息。至于第二部分的用途将在讨论Tooltip的章节将用到。
[责任编辑:cndownzcom]
得到了字符串之后,OnSetMessageString调用状态栏的SetWindowText函数。SetWindowText导致消息WM_SETTEXT消息发送给状态栏,状态栏的消息处理函数OnSetText被调用,实际上等于调用了SetPaneText(0, lpsz),即在状态栏的第0格中显示字符串lpsz的信息。对于工具栏来说,SetWindowText可以认为是SetPaneText(0, lpsz)的简化版本。
顺便指出,pMessageBar->GetParentFrame()返回主边框窗口,即使pMessageBar指向漂浮的工具条。关于泊位和漂浮,见后面13.2.5节的描述。
关于OnSetText,其实现如下:
LRESULT CStatusBar::OnSetText(WPARAM, LPARAM lParam)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
int nIndex = CommandToIndex(0); //返回0
if (nIndex < 0)
return -1;
return SetPaneText(nIndex, (LPCTSTR)lParam) ? 0 : -1;
}
OnPopMessageString
LRESULT CFrameWnd::OnPopMessageString(WPARAM wParam,
LPARAM lParam)
{
//WF_NOPOPMSG表示边框窗口不处理WM_POPMESSAGESTRING
if (m_nFlags & WF_NOPOPMSG)
return 0;
//调用OnSetMessageString
return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);
}一般,在清除状态栏消息时,发送WM_POPMESSAGESTRING,通过消息参数wParam指定一个字符串资源,其ID 为AFX_IDS_IDLEMESSAGE,对应的字符串是“Ready”。
状态栏显示菜单项的提示信息
状态栏的一个重要作用是显示菜单命令或者工具条按钮的提示信息。本节讨论如何显示菜单命令的提示信息,关于工具条按钮在这方面的讨论见后面13.2.4.4章节。
显示菜单命令的提示信息,就是每当一个菜单项被选中之后,在状态栏显示该菜单的功能、用法等信息。这些信息以字符串资源的形式保存,字符串ID对应于菜单项的命令ID。
所以,必须处理菜单选择消息WM_MENUSELECT。CFrameWnd实现了消息处理函数OnMenuSelect,其实现如下:
void CFrameWnd::OnMenuSelect(UINT nItemID,
UINT nFlags, HMENU /*hSysMenu*/)
{
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
//跟踪被选中的菜单项
if (nFlags == 0xFFFF)
{
//取消菜单操作
m_nFlags &= ~WF_NOPOPMSG;
if (!pFrameWnd->m_bHelpMode)
m_nIDTracking = AFX_IDS_IDLEMESSAGE;
else
m_nIDTracking = AFX_IDS_HELPMODEMESSAGE;
//在状态栏显示
SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
ASSERT(m_nIDTracking == m_nIDLastMessage);
// update right away
CWnd* pWnd = GetMessageBar();
if (pWnd != NULL)
pWnd->UpdateWindow();
}
else
{
//选中分隔栏、Popup子菜单或者没有选中一个菜单项
if (nItemID == 0 || nFlags & (MF_SEPARATOR|MF_POPUP))
{
// nothing should be displayed
m_nIDTracking = 0;
}
else if (nItemID >= 0xF000 && nItemID < 0xF1F0) // max of 31 SC_s
{
//系统菜单的菜单项被选中
m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);
ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST &&
m_nIDTracking < AFX_IDS_SCFIRST + 31);
}
else if (nItemID >= AFX_IDM_FIRST_MDICHILD)
{
//如果选中的菜单项表示一个MDI子窗口
m_nIDTracking = AFX_IDS_MDICHILD;
}
else
{
//选中了一个菜单项
m_nIDTracking = nItemID;
}
pFrameWnd->m_nFlags |= WF_NOPOPMSG;
}
// when running in-place, it is necessary to cause a message to
// be pumped through the queue.
if (m_nIDTracking != m_nIDLastMessage && GetParent() != NULL)
PostMessage(WM_KICKIDLE);
}OnMenuSelect的作用在于跟踪当前选中的菜单项,把菜单项对应的ID保存在CFrameWnd的成员变量m_nIDTracking中。
[责任编辑:cndownzcom]
如果菜单项没有选中,或者选中的是一个子菜单,则设置nIDTracking为0。
如果选中的是系统菜单,则把系统菜单ID转换成一个对应的命令ID;保存该值到nIDTracking中。
如果选中的菜单是MDI子窗口创建时添加的(用来表示MDI子窗口),则转换菜单ID为AFX_IDS_MDICHILD,所有对应MDI子窗口的菜单项都使用AFX_IDS_MDICHILD,保存该值到nIDTracking中。
其他情况,就是选中菜单项的ID,把它保存到nIDTracking中。
跟踪被选择的菜单项并保存其ID在m_nIDTracking中,OnEnterIdle将用到m_nIDTracking。OnEnterIlde是消息WM_ENTERIDLE的处理函数,CFrameWnd的实现如下。
void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho)
{
CWnd::OnEnterIdle(nWhy, pWho);
//若不是因为菜单选择进入该函数
//或者当前跟踪到的菜单项ID是最近一次处理的,则返回
if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
return;
//将发送消息WM_SETMESSAGETEXT
//在状态栏显示m_nIDTracking对应的字符串
SetMessageText(m_nIDTracking);
ASSERT(m_nIDTracking == m_nIDLastMessage);
}当一个对话框或者菜单被显示的时候,Windows发送WM_ENTERIDLE消息。消息参数wParam取值为MSGF_DIALOGBOX或者MSGF_MENU。前者表示显示对话框时发送该消息,这时消息参数lParam表示对话框的句柄;后者表示显示菜单时发送该消息,这时消息参数lParam表示菜单的句柄。
经过消息映射,wParam的值传递给OnEnterIdle的参数nWhy,参数lParam的值传给参数who。如果参数1取值为MSGF_MENU,并且OnEnterIdle最近一次在菜单显示被调用时的菜单ID不同于这一次,则调用SetMessageText在状态栏显示对应ID命令的字符串,并且记录当前菜单ID到变量m_nIDTracking中(见消息处理函数OnSetMessageText)。
这样,在菜单选择期间,用户选择的菜单项ID被OnMenuSelect记录,在消息WM_ENTERIDLE处理时在状态栏显示ID命令的提示。
控制条的消息分发处理
工具条(包括对话框工具条)是一个子窗口,它们可以响应各种消息。如果按标准的Windows消息和命令消息的分发途径,一些消息不能送到拥有工具条的边框窗口,因为这些消息都将被工具条(对话框工具条)处理掉。所以,CControlBar覆盖了虚拟函数PreTranslateMessage和WindowProc以便实现特定的消息
【中国下载站】【设为主页】【收藏本页】【打印本文】【回到顶部】【关闭此页】