MFC状态栏梳理
MFC状态栏,觉得挺简单的,但是用的时候总是不得劲,梳理了一下代码。理解通透些。
先说状态栏窗口怎么来的
在MainFrame里面会有一个成员变量,状态栏 m_wndStatusBar
protected: // 控件条嵌入成员
CMFCMenuBar m_wndMenuBar;
CMFCToolBar m_wndToolBar;
CMFCStatusBar m_wndStatusBar; //状态栏窗口
CMFCToolBarImages m_UserImages;
CFileView m_wndFileView;
CClassView m_wndClassView;
COutputWnd m_wndOutput;
CPropertiesWnd m_wndProperties;
在创建的时候,好好仔细的创建出来,大意是根据数组指示器,将状态栏分为指示器数组个数窗口,每一个窗口的含义由指示器指定,可以自己分状态栏。
static UINT indicators[] =
{
ID_SEPARATOR, // 状态行指示器
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
创建的时候其实很关键,在create函数里面有一个资源的id,状态栏运行机制其实全靠这个资源id来实现,而由于create函数资源id又是默认参数,导致看代码的时候死活有转不过弯,信息是如何发送到状态栏的。
if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -1; // 未能创建
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
关键的最后一个参数,函数声明太长,还显示不出来,我调整一下
BOOL Create(CWnd* pParentWnd,
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,
UINT nID = AFX_IDW_STATUS_BAR);
BOOL CreateEx(CWnd* pParentWnd,
DWORD dwCtrlStyle = 0,
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,
UINT nID = AFX_IDW_STATUS_BAR);
MFC运行通过资源ID AFX_IDW_STATUS_BAR 来操作状态栏
典型的函数就是
CWnd* CFrameWnd::GetMessageBar()
{
return GetDescendantWindow(AFX_IDW_STATUS_BAR, TRUE);
}
就是如此,通过在子孙窗口里面一通乱找,反正有资源ID就能找到对应的创建的窗口,最后就能设置信息了。
说一下这个就绪怎么来的
如果你在多文档程序里面想在程序搞定以后设置一个准备好了,你会发现非常诡异的总是显示就绪,好坑爹。
比如你在mainframe的创建函数里面,不管你是直接设置
SetMessageText 还是POSTMessage 还是SendMessage都不好使
这里面有一个设置时机的问题。
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if (CWnd::OnCreate(lpcs) == -1)
return -1;
// create special children first
if (!OnCreateClient(lpcs, pContext))
{
TRACE(traceAppMsg, 0, "Failed to create client pane/view for frame.\n");
return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized
RecalcLayout();
return 0; // create ok
}
AFX_IDS_IDLEMESSAGE就是 【就绪字符串】
通过梳理代码我们可以知道,在CFrameWnd::OnCreateHelper每次都会发送设置状态信息,就绪。那就可以知道了。
由于子框架也是继承CFrameWnd,那么他也会发送设置状态信息。
所以时机应该在子框架设置完以后再设置就可以实现。
不能改MFC的原代码吧,可以改字符串,但是得知道怎么回事。
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
PostMessage(WM_SETMESSAGESTRING, 0, (LPARAM)"准备好了");
return 0;
}
这里面还有一个坑爹的是需要发送消息来设置
由于在MFC框架源代码里面是发送消息,而且是POST,那么我们也只能POST,不然你搞定以后,MFC框架代码在处理的时候又来设置一顿,是不是白搞了。
哈,那就是这样子了。
主要就是解决两个疑惑:
1 问:MFC如何通过SetMessageText之类的函数来设置状态信息的?
答:通过一个叫AFX_IDW_STATUS_BAR 的标准资源ID来找到状态栏窗口再操纵他设置信息。
2 问 多文档程序中在MainFrame的Create函数里面设置状态信息,为什么不起作用。
答:因为子框架的create函数里面会重新设置一番,覆盖了。如果程序启动没有子框架是不会覆盖的。