如果想自定义 CDialog的输入焦点,一种办法是可以通过VC自带的资源编辑器,设置Tab Order来指定哪个控件是在Tab order的顺序是第一。这种方法的好处是简单方便,但是无法动态指定输入焦点。
如果要根据一些运行时的情况来判断输入焦点,我们很容易想到调用空间的SetFocus函数,但是一般情况下这样是不管用的,输入焦点仍然是在Tab order排第一的那个控件上,为什么?因为MFC在初始化对话框时,会调用OnInitDialog函数,大多数情况下我们自定义一个对话框,都会覆写这个方法,如:
CDialog::OnInitDialog();
// todo: 插入你自己的初始化对话框的代码
return TRUE;
注意最后一句:return TRUE
原因就在这一句上。我们看一下MFC的框架代码:
LRESULT CDialog::HandleInitDialog(WPARAM, LPARAM)
{
PreInitDialog();
#ifndef _AFX_NO_OCC_SUPPORT
// create OLE controls
COccManager* pOccManager = afxOccManager;
if ((pOccManager != NULL) && (m_pOccDialogInfo != NULL))
{
BOOL bDlgInit;
if (m_lpDialogInit != NULL)
bDlgInit = pOccManager->CreateDlgControls(this, m_lpDialogInit,
m_pOccDialogInfo);
else
bDlgInit = pOccManager->CreateDlgControls(this, m_lpszTemplateName,
m_pOccDialogInfo);
if (!bDlgInit)
{
TRACE(traceAppMsg, 0, "Warning: CreateDlgControls failed during dialog init./n");
EndDialog(-1);
return FALSE;
}
}
#endif
// Default will call the dialog proc, and thus OnInitDialog
LRESULT bResult = Default();
#ifndef _AFX_NO_OCC_SUPPORT
if (bResult && (m_nFlags & WF_OLECTLCONTAINER))
{
CWnd* pWndNext = GetNextDlgTabItem(NULL);
if (pWndNext != NULL)
{
pWndNext->SetFocus(); // UI Activate OLE control
bResult = FALSE;
}
}
#endif
return bResult;
}
看最底下的代码
LRESULT bResult = Default();
#ifndef _AFX_NO_OCC_SUPPORT
if (bResult && (m_nFlags & WF_OLECTLCONTAINER))
{
CWnd* pWndNext = GetNextDlgTabItem(NULL);
if (pWndNext != NULL)
{
pWndNext->SetFocus(); // UI Activate OLE control
bResult = FALSE;
}
}
#endif
在调用完初始化函数后,会判断OnInitDialog的返回值,如果返回的是TRUE,会继续调用设置输入焦点的代码,这个输入焦点就是根据Tab order中指定的第一个输入焦点的控件。
所以,要想在OnInitDialog中指定的输入焦点生效,那么我们就把OnInitDialog的返回值设成FALSE就行了。