如何解决MFC MDI 通过覆盖 FWS_ADDTOTITLE 在文档切换上获取文件路径和更新的标题?
TL;DR:如何为每个文档标题添加完整路径?
我只通过搜索 FWS_ADDTOTITLE 就看到了很多线程。我正在更新的特定旧应用程序专门使用它:
lpwndMainFrame->LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE);
我的应用程序专门处理 MP4 文件和元数据标记,作为 MDI,它可以同时打开 1 个或多个 mp4 文件进行编辑、复制/剪切/粘贴元数据等......一切正常,一切都很好.
我真正想看到的一件事是应用程序标题中 MP4 的完整路径 + 文件名,它会根据选择的文档而变化。
我可以用它来覆盖标题作为硬编码方法:
m_pMainWnd->SetWindowText(_T("My hardcoded title with no help to my topic example"));
所以我知道该机制可以在焦点上替换文档标题。
由于应用程序已经在文档之间切换标题中处理文件名就好了,我想要完全相同的功能,但在标题中包含路径。
为什么?有时我可以有两个完全相同的文件,但不同的文件夹,如果我不知道我正在修改哪一个,它会变得混乱。
所以我正在寻找应用的标题以显示如下内容:
MyApp - C:\MyHarddrive\Folder1\ThisIsMyFile1.mp4
MyApp - C:\MyHarddrive\Folder17\ThisIsMyFile2.mp4
MyApp - C:\MyHarddrive\FolderA\ThisIsMyFile1.mp4
因为我分别选择了文档 1 -3。
编辑:
我正在添加 FWS_ADDTOTITLE 在我的应用程序中的位置。我拿起了几年前废弃的代码,所以如果不重写我不想做的整个事情,我就无法控制。下面的代码位于一个名为 application.cpp 的文件中。他们在我的名为 MainFrame.cpp 或 ChildFrame.cpp 的文件中没有其他对 FWS_ADDTOTITLE 的引用。我尝试了如下所述的覆盖,但它在粘贴后从 VC 源代码文件中提供了一个 &hookpointer 未知标识符复制到覆盖函数中。无论如何,这有帮助吗?
BOOL CApplication::InitInstance()
{
CWinApp::InitInstance();
// set registry key
SetRegistryKey(_T("AppNameC"));
//CleanState();
// create document template
CMultiDocTemplate* m_pkDocTemplate;
m_pkDocTemplate = new CMultiDocTemplate(
IDR_MOVIE,RUNTIME_CLASS(CMovieDoc),RUNTIME_CLASS(CChildFrame),RUNTIME_CLASS(CMovieView));
if (!m_pkDocTemplate)
return FALSE;
AddDocTemplate(m_pkDocTemplate);
// create main window
CMainFrame *lpwndMainFrame = new CMainFrame();
lpwndMainFrame->LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE);
m_pMainWnd = lpwndMainFrame;
m_pMainWnd->DragAcceptFiles(); // Added
lpwndMainFrame->ShowWindow(m_nCmdShow);
//lpwndMainFrame->ShowWindow(SW_MAXIMIZE); // Added start full screen
//m_pMainWnd->SetWindowText(_T("History database")); // Added Valid
lpwndMainFrame->UpdateWindow();
// parse command line
return ParseCommandLine();
}
编辑 3/24/2021
所以我已经通过已经说明的帮助进行了大部分工作,但是出现了一个新问题并且不知道如何解决它。在我的 MainFrame.cpp 和 ChildFrame.cpp 中,我的 MainFrame.cpp 和 ChildFrame.cpp 都有这些完全相同的逐字重写:
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
cs.style &= ~(LONG)FWS_ADDTOTITLE;
return CMDIChildWndEx::PreCreateWindow(cs);
}
void CChildFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
// TODO: Add your specialized code here and/or call the base class
CView* pView = GetActiveView();
if (pView) {
CDocument* pDoc = pView->GetDocument();
if (pDoc) {
CString title;
title = pDoc->GetPathName();
//title.Format("My App - %s",pDoc->GetPathName());
AfxGetMainWnd()->SetWindowText(title.GetString());
}
}
CMDIChildWndEx::OnUpdateFrameTitle(bAddToTitle);
}
如图所示,我有正确的路径和标题:
但是出现了一个新的工件:Windows Active(不确定它叫什么)现在缺少通常存在的文件名:
如果我注释掉 //cs.style &= ~(LONG)FWS_ADDTOTITLE;在 CHILDFRAME ONLY..然后它恢复我的窗口菜单标题,因为它以某种方式通过 FWS_ADDTOTITLE 使用 GetTitle()。我希望路径像上面一样显示,但在显示每个文件时仍保留菜单中的标题。 - [FIL-TITLE.MP4](在图像中以红色框显示)需要去......但不知道如何实现......一件事通过覆盖让另一件事感到不安......任何关于如何的想法纠正这最后一块?除了窗口下拉的东西,它几乎是 100%。有什么想法吗?
解决方法
为此我要做的是在 MFC 源代码中搜索 FWS_ADDTOTITLE
的使用。在 VS 中,您选择 Edit->Find and Replace->Find in Files 并在“Look In”组合中选择“Visual C++ Source Directory”。
此搜索返回多个结果,但看起来相关的结果都在 winfrm.cpp 和 winmdi.cpp 中,在这两种情况下都位于 OnUpdateFrameTitle()
成员函数中。好消息是这个成员是虚拟的和公共的,即可以覆盖。因此您可以覆盖它(转到类视图并单击属性工具箱中的“覆盖”)。在函数实现中不要调用祖先实现,而是从 MFC 源复制代码并将 UpdateFrameTitleForDocument(pDocument->GetTitle())
替换为 UpdateFrameTitleForDocument(pDocument->GetPathName())
。不确定您的代码使用了这两个(winfrm.cpp 或 winmdi.cpp)的哪个实现,但是您可以调试它以找出(我猜它是 winmdi.cpp 中的一个,因为您的框架窗口派生自 {{1 }} 但最好检查一下)。
可能的问题,代码可能无法编译,如果它使用私有成员或在其他地方声明/定义的变量,但我想说试一试。
编辑:
顾名思义,CMDIFrameWnd
函数似乎是最适合重写的函数,不是吗?
做了我上面描述的,并改变了如下所示的代码 - 你的 MFC 版本可能不同,所以从你的 MFC 源复制代码并根据需要修改它,不要只是复制你在这里看到的。它是从 winmdi.cpp 中复制的,函数 OnUpdateFrameTitle()
。
CMDIFrameWnd::OnUpdateFrameTitle()
这段代码不会编译,因为正如你提到的,编译器不知道 void CMainFrame::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;
CMDIChildWnd* pActiveChild = NULL;
CDocument* pDocument = GetActiveDocument();
if (bAddToTitle &&
(pActiveChild = MDIGetActive()) != NULL &&
(pActiveChild->GetStyle() & WS_MAXIMIZE) == 0 &&
(pDocument != NULL ||
(pDocument = pActiveChild->GetActiveDocument()) != NULL))
// This was the original code: UpdateFrameTitleForDocument(pDocument->GetTitle());
// This is the modified code,and THE ONLY CHANGE in the source
{
CString sDoc = pDocument->GetPathName();
// GetPathName() returns an empty string for a newly-created document
if (sDoc.IsEmpty()) sDoc = pDocument->GetTitle();
UpdateFrameTitleForDocument(sDoc);
}
else
{
LPCTSTR lpstrTitle = NULL;
CString strTitle;
if (pActiveChild != NULL &&
(pActiveChild->GetStyle() & WS_MAXIMIZE) == 0)
{
strTitle = pActiveChild->GetTitle();
if (!strTitle.IsEmpty())
lpstrTitle = strTitle;
}
UpdateFrameTitleForDocument(lpstrTitle);
}
}
的类型。这可以解决,使用 VS 编辑器功能(例如右键单击并选择查找声明/定义)。这个变量的类型是m_pNotifyHook
,它是在oleimpl2.h中声明的——一个简单的文件/文本搜索就可以找到它。所以你需要做的是在你的源代码中包含这个标题:
COleFrameHook*
由于某种奇怪的原因,这个文件在源代码中,而不是在包含目录中,因此 VS 找不到它,即 #include "oleimpl2.h"
不起作用。因此,我使用双引号并将文件复制到我项目的源文件夹中 - 或者您可以在 #include <oleimpl2.h>
指令中指定一个完全限定的路径。
您可以使用 GetPathName()
类的 CDocument
成员(如评论中所述)。然后,您可以通过覆盖 MDI 子窗口类中的 OnMDIActivate
() 成员函数(ON_WM_MDIACTIVATE
的处理程序)手动设置主框架窗口的文本。
大致如下:
BEGIN_MESSAGE_MAP(MyChildFrame,CMDIChildWnd)
ON_WM_MDIACTIVATE()
//...
END_MESSAGE_MAP()
void MyChildFrame::OnMDIActivate(BOOL bActivate,CWnd* pActivateWnd,CWnd* pDeactivateWnd)
{
CMDIChildWnd::OnMDIActivate(bActivate,pActivateWnd,pDeactivateWnd ); // Call base class handler
if (bActivate) { // If we're activating a view,get the path and use that...
CView* pView = GetActiveView();
if (pView) {
CDocument* pDoc = pView->GetDocument();
if (pDoc) {
CString title;
title.Format("My App - %s",pDoc->GetPathName());
AfxGetMainWnd()->SetWindowText(title.GetString());
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。