ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MFC学习:设置窗口标题

2022-05-07 22:31:43  阅读:348  来源: 互联网

标签:OnUpdateFrameTitle MFC 窗口 CDocument SetTitle 标题 WindowText szText


默认情况下,MFC的主窗口标题由文档标题和Frame标题组成,格式为:file - frame

设置标题

设置窗口标题用 CWnd::SetWindowText 方法。

设置文档标题

新建一个文档时,MFC 会使用字符串资源AFX_IDS_UNTITLED作为文档的默认标题,接着会触发 CDocument::OnNewDocument 方法,我们可以在文件新建成功后使用 CDocument::SetTitle 方法来设置标题。

BOOL CMFCApplication2Doc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    this->SetTitle(_T("新文件"));
    return TRUE;
}

如果是打开文档就不能在 CDocument::OnOpenDocument 中处理,因为 MFC 在打开文档后会使用文件名作为标题

...
TCHAR szTitle[_MAX_FNAME];
if (AfxGetFileTitle(szFullPath, szTitle, _MAX_FNAME) == 0)
    SetTitle(szTitle);
...

最早的修改时机是在 CDocument::SetPathName 中,我们可以重载它

void SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU) override
{
    CDocument::SetPathName(lpszPathName, bAddToMRU);
    this->SetTitle(_T("new title"));
}

但是更建议在 CDocument::OnDocumentEvent 中处理

void OnDocumentEvent(DocumentEvent deEvent) override
{
    if (deEvent == onAfterNewDocument || deEvent == onAfterOpenDocument) {
        this->SetTitle(_T("new title"));
    }
}

固定窗口标题

我们有时候希望应用程序标题是固定的,不会随着文档变化,可以通过以下几种方式来做。

方式一

因为文档在设置标题后会触发 CFrameWndEx::OnUpdateFrameTitle 方法,而这个方法会改变窗口标题,所以我们覆盖它即可避免被影响。
CFrameWndEx::OnCreate 中设置固定标题

this->SetWindowText(_T("title"));

重载 CFrameWndEx::OnUpdateFrameTitle 方法,不调用父类操作。

void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    // Ignore
}

方式二

跟进OnUpdateFrameTitle后:

void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    if ((GetStyle() & FWS_ADDTOTITLE) == 0)
        return;     // leave it alone!

    // allow hook to set the title (used for OLE support)
    if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
        return;

    CDocument* pDocument = GetActiveDocument();
    if (bAddToTitle && pDocument != NULL)
        UpdateFrameTitleForDocument(pDocument->GetTitle());
    else
        UpdateFrameTitleForDocument(NULL);
}

这里发现了一个新东西FWS_ADDTOTITLE,如果窗口样式不包含它的话就退出函数了,所以我们也可以在创建Frame时去除这个Flag

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if (!CFrameWndEx::PreCreateWindow(cs))
        return FALSE;

    cs.style &= ~FWS_ADDTOTITLE;
    return TRUE;
}

所以这个方式和方式一是一样的,本质上就是忽略OnUpdateFrameTitle的默认行为。

方式三

继续跟进源码

void CFrameWnd::UpdateFrameTitleForDocument(LPCTSTR lpszDocName)
{
    CString WindowText;

    if (GetStyle() & FWS_PREFIXTITLE)
    {
        // get name of currently active view
        if (lpszDocName != NULL)
        {
            WindowText += lpszDocName;

            // add current window # if needed
            if (m_nWindow > 0)
            {
                TCHAR szText[32];

                // :%d will produce a maximum of 11 TCHARs
                _stprintf_s(szText, _countof(szText), _T(":%d"), m_nWindow);
                WindowText += szText;
            }
            WindowText += _T(" - ");
        }
        WindowText += m_strTitle;
    }
    else
    {
        // get name of currently active view
        WindowText += m_strTitle;
        if (lpszDocName != NULL)
        {
            WindowText += _T(" - ");
            WindowText += lpszDocName;

            // add current window # if needed
            if (m_nWindow > 0)
            {
                TCHAR szText[32];

                // :%d will produce a maximum of 11 TCHARs
                _stprintf_s(szText, _countof(szText), _T(":%d"), m_nWindow);
                WindowText += szText;
            }
        }
    }

    // set title if changed, but don't remove completely
    // Note: will be excessive for MDI Frame with maximized child
    AfxSetWindowText(m_hWnd, (LPCTSTR) WindowText);
}

逻辑很简单,只要我们将OnUpdateFrameTitle方法唯一的参数设置为FALSE,就可以让Frame控件标题 作为窗口标题。
首先设置Frame的控件标题,通过 CFrameWnd::SetTitle 方法。

this->SetTitle(_T("title"));

然后将OnUpdateFrameTitle的参数设置为FALSE

void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    __super::OnUpdateFrameTitle(FALSE);
}

Frame 默认标题从哪来?

如果我们不做任何设置,Frame 始终会有一个默认标题,这个标题字符串从哪来?还是看源码

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
    CWnd* pParentWnd, CCreateContext* pContext)
{
...
    CString strFullString;
    if (strFullString.LoadString(nIDResource))
        AfxExtractSubString(m_strTitle, strFullString, 0);    // first sub-string
...
}

原来在创建 MFC 工程时,资源文件中生成了它

STRINGTABLE
BEGIN
    IDR_MAINFRAME    "MFCApplication2\n\nMFCApplication2\n\n\nMFCApplication2.Document\nMFCApplication2.Document"
END

这是一个用\n分隔的字符串列表,第一个子串就是默认标题。
关于其他子串的解释可以查看 CDocTemplate::GetDocString 的解释。

标签:OnUpdateFrameTitle,MFC,窗口,CDocument,SetTitle,标题,WindowText,szText
来源: https://www.cnblogs.com/cyds/p/16244353.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有