# mfc_sdi **Repository Path**: lujianfei/mfc_sdi ## Basic Information - **Project Name**: mfc_sdi - **Description**: 用于解析MFC单文档的代码结构 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2020-02-02 - **Last Updated**: 2021-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MFC SDI 单文档工程 #### 界面演示 img ![img](https://images.gitee.com/uploads/images/2020/0202/210318_54702906_411238.png) #### 介绍 用于解析MFC单文档的代码结构 #### 工程文件结构 ``` │ .gitignore │ ChildFrm.cpp │ ChildFrm.h │ ClassView.cpp │ ClassView.h // 左侧类视图 │ FileView.cpp │ FileView.h // 左侧文件视图 │ MainFrm.cpp │ MainFrm.h │ mfc_sdi.cpp │ mfc_sdi.h │ mfc_sdi.rc │ mfc_sdi.sdf │ mfc_sdi.sln │ mfc_sdi.vcxproj │ mfc_sdi.vcxproj.filters │ mfc_sdiDoc.cpp │ mfc_sdiDoc.h │ mfc_sdiView.cpp │ mfc_sdiView.h │ OutputWnd.cpp │ OutputWnd.h │ PropertiesWnd.cpp │ PropertiesWnd.h // 右侧属性空格 │ README.en.md │ README.md │ ReadMe.txt │ Resource.h │ stdafx.cpp │ stdafx.h │ targetver.h │ UserImages.bmp │ ViewTree.cpp │ ViewTree.h ``` #### 左侧类列表代码 ClassView.h ```C++ class CClassView : public CDockablePane { ... protected: ... CClassToolBar m_wndToolBar; CViewTree m_wndClassView; CImageList m_ClassViewImages; ... void FillClassView(); ... } ``` ClassView.cpp ```C++ int CClassView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; CRect rectDummy; rectDummy.SetRectEmpty(); // 创建视图: const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; if (!m_wndClassView.Create(dwViewStyle, rectDummy, this, 2)) { TRACE0("未能创建类视图\n"); return -1; // 未能创建 } // 加载图像: m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_SORT); m_wndToolBar.LoadToolBar(IDR_SORT, 0, 0, TRUE /* 已锁定*/); OnChangeVisualStyle(); m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() | CBRS_TOOLTIPS | CBRS_FLYBY); m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() & ~(CBRS_GRIPPER | CBRS_SIZE_DYNAMIC | CBRS_BORDER_TOP | CBRS_BORDER_BOTTOM | CBRS_BORDER_LEFT | CBRS_BORDER_RIGHT)); m_wndToolBar.SetOwner(this); // 所有命令将通过此控件路由,而不是通过主框架路由: m_wndToolBar.SetRouteCommandsViaFrame(FALSE); CMenu menuSort; menuSort.LoadMenu(IDR_POPUP_SORT); m_wndToolBar.ReplaceButton(ID_SORT_MENU, CClassViewMenuButton(menuSort.GetSubMenu(0)->GetSafeHmenu())); CClassViewMenuButton* pButton = DYNAMIC_DOWNCAST(CClassViewMenuButton, m_wndToolBar.GetButton(0)); if (pButton != NULL) { pButton->m_bText = FALSE; pButton->m_bImage = TRUE; pButton->SetImage(GetCmdMgr()->GetCmdImage(m_nCurrSort)); pButton->SetMessageWnd(this); } // 填入一些静态树视图数据(此处只需填入虚拟代码,而不是复杂的数据) FillClassView(); return 0; } void CClassView::OnChangeVisualStyle() { m_ClassViewImages.DeleteImageList(); UINT uiBmpId = theApp.m_bHiColorIcons ? IDB_CLASS_VIEW_24 : IDB_CLASS_VIEW; CBitmap bmp; if (!bmp.LoadBitmap(uiBmpId)) { TRACE(_T("无法加载位图: %x\n"), uiBmpId); ASSERT(FALSE); return; } BITMAP bmpObj; bmp.GetBitmap(&bmpObj); UINT nFlags = ILC_MASK; nFlags |= (theApp.m_bHiColorIcons) ? ILC_COLOR24 : ILC_COLOR4; // Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow) m_ClassViewImages.Create(16, bmpObj.bmHeight, nFlags, 0, 0); m_ClassViewImages.Add(&bmp, RGB(255, 0, 0)); m_wndClassView.SetImageList(&m_ClassViewImages, TVSIL_NORMAL); m_wndToolBar.CleanUpLockedImages(); m_wndToolBar.LoadBitmap(theApp.m_bHiColorIcons ? IDB_SORT_24 : IDR_SORT, 0, 0, TRUE /* 锁定*/); } void CClassView::FillClassView() { HTREEITEM hRoot = m_wndClassView.InsertItem(_T("FakeApp 类"), 0, 0); m_wndClassView.SetItemState(hRoot, TVIS_BOLD, TVIS_BOLD); HTREEITEM hClass = m_wndClassView.InsertItem(_T("CFakeAboutDlg"), 1, 1, hRoot); m_wndClassView.InsertItem(_T("CFakeAboutDlg()"), 3, 3, hClass); m_wndClassView.Expand(hRoot, TVE_EXPAND); // CTreeCtrl::InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) hClass = m_wndClassView.InsertItem(_T("CFakeApp"), 1, 1, hRoot); m_wndClassView.InsertItem(_T("CFakeApp()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("InitInstance()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("OnAppAbout()"), 3, 3, hClass); hClass = m_wndClassView.InsertItem(_T("CFakeAppDoc"), 1, 1, hRoot); m_wndClassView.InsertItem(_T("CFakeAppDoc()"), 4, 4, hClass); m_wndClassView.InsertItem(_T("~CFakeAppDoc()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("OnNewDocument()"), 3, 3, hClass); hClass = m_wndClassView.InsertItem(_T("CFakeAppView"), 1, 1, hRoot); m_wndClassView.InsertItem(_T("CFakeAppView()"), 4, 4, hClass); m_wndClassView.InsertItem(_T("~CFakeAppView()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("GetDocument()"), 3, 3, hClass); m_wndClassView.Expand(hClass, TVE_EXPAND); hClass = m_wndClassView.InsertItem(_T("CFakeAppFrame"), 1, 1, hRoot); m_wndClassView.InsertItem(_T("CFakeAppFrame()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("~CFakeAppFrame()"), 3, 3, hClass); m_wndClassView.InsertItem(_T("m_wndMenuBar"), 6, 6, hClass); m_wndClassView.InsertItem(_T("m_wndToolBar"), 6, 6, hClass); m_wndClassView.InsertItem(_T("m_wndStatusBar"), 6, 6, hClass); hClass = m_wndClassView.InsertItem(_T("Globals"), 2, 2, hRoot); m_wndClassView.InsertItem(_T("theFakeApp"), 5, 5, hClass); m_wndClassView.Expand(hClass, TVE_EXPAND); } ``` 类视图相关资源 ##### 树状图资源处理 IDB_CLASS_VIEW_24 如下所示 ![img](https://images.gitee.com/uploads/images/2020/0202/212129_d2bbdf24_411238.png) IDB_CLASS_VIEW_ ![img](https://images.gitee.com/uploads/images/2020/0202/212558_bd97af6f_411238.png) #### 类左上角排序 ![img](https://images.gitee.com/uploads/images/2020/0202/233636_193b4a3b_411238.png) ![img](https://images.gitee.com/uploads/images/2020/0202/233844_247c0409_411238.png) ```c++ int CClassView::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... CMenu menuSort; menuSort.LoadMenu(IDR_POPUP_SORT); m_wndToolBar.ReplaceButton(ID_SORT_MENU, CClassViewMenuButton(menuSort.GetSubMenu(0)->GetSafeHmenu())); ... return 0; } ``` ![img](https://images.gitee.com/uploads/images/2020/0202/234606_985d8a9f_411238.png) #### 下拉菜单图标对应关系 toolbar资源 和 menu 菜单的 id 相对应 ![img](https://images.gitee.com/uploads/images/2020/0203/004402_9673e74c_411238.png) ![img](https://images.gitee.com/uploads/images/2020/0203/004551_7afdad5d_411238.png) MainFrm.cpp ```c++ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... // 加载菜单项图像(不在任何标准工具栏上): CMFCToolBar::AddToolBarForImageCollection(IDR_MENU_IMAGES, theApp.m_bHiColorIcons ? IDB_MENU_IMAGES_24 : 0); } ``` #### 被引用的位置 MainFrm,h ```c++ class CMainFrame : public CMDIFrameWndEx { ... protected: // 控件条嵌入成员 ... CClassView m_wndClassView; ... } ``` MainFrm.cpp ```c++ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... // 创建停靠窗口 if (!CreateDockingWindows()) { TRACE0("未能创建停靠窗口\n"); return -1; } ... } BOOL CMainFrame::CreateDockingWindows() { BOOL bNameValid; // 创建类视图 CString strClassView; bNameValid = strClassView.LoadString(IDS_CLASS_VIEW); ASSERT(bNameValid); if (!m_wndClassView.Create(strClassView, this, CRect(0, 0, 200, 200), TRUE, ID_VIEW_CLASSVIEW, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI)) { TRACE0("未能创建“类视图”窗口\n"); return FALSE; // 未能创建 } ... return TRUE; } ``` #### 左侧文件列表代码 FileView.h ```c++ class CFileView : public CDockablePane { ... // 特性 protected: CViewTree m_wndFileView; CImageList m_FileViewImages; CFileViewToolBar m_wndToolBar; protected: void FillFileView(); } ``` FileView.cpp ```c++ int CFileView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; CRect rectDummy; rectDummy.SetRectEmpty(); // 创建视图: const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS; if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4)) { TRACE0("未能创建文件视图\n"); return -1; // 未能创建 } // 加载视图图像: m_FileViewImages.Create(IDB_FILE_VIEW, 16, 0, RGB(255, 0, 255)); m_wndFileView.SetImageList(&m_FileViewImages, TVSIL_NORMAL); m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_EXPLORER); m_wndToolBar.LoadToolBar(IDR_EXPLORER, 0, 0, TRUE /* 已锁定*/); OnChangeVisualStyle(); m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() | CBRS_TOOLTIPS | CBRS_FLYBY); m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() & ~(CBRS_GRIPPER | CBRS_SIZE_DYNAMIC | CBRS_BORDER_TOP | CBRS_BORDER_BOTTOM | CBRS_BORDER_LEFT | CBRS_BORDER_RIGHT)); m_wndToolBar.SetOwner(this); // 所有命令将通过此控件路由,而不是通过主框架路由: m_wndToolBar.SetRouteCommandsViaFrame(FALSE); // 填入一些静态树视图数据(此处只需填入虚拟代码,而不是复杂的数据) FillFileView(); AdjustLayout(); return 0; } void CFileView::FillFileView() { HTREEITEM hRoot = m_wndFileView.InsertItem(_T("FakeApp 文件"), 0, 0); m_wndFileView.SetItemState(hRoot, TVIS_BOLD, TVIS_BOLD); HTREEITEM hSrc = m_wndFileView.InsertItem(_T("FakeApp 源文件"), 0, 0, hRoot); // CTreeCtrl::InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) m_wndFileView.InsertItem(_T("FakeApp.cpp"), 1, 1, hSrc); m_wndFileView.InsertItem(_T("FakeApp.rc"), 1, 1, hSrc); m_wndFileView.InsertItem(_T("FakeAppDoc.cpp"), 1, 1, hSrc); m_wndFileView.InsertItem(_T("FakeAppView.cpp"), 1, 1, hSrc); m_wndFileView.InsertItem(_T("MainFrm.cpp"), 1, 1, hSrc); m_wndFileView.InsertItem(_T("StdAfx.cpp"), 1, 1, hSrc); HTREEITEM hInc = m_wndFileView.InsertItem(_T("FakeApp 头文件"), 0, 0, hRoot); m_wndFileView.InsertItem(_T("FakeApp.h"), 2, 2, hInc); m_wndFileView.InsertItem(_T("FakeAppDoc.h"), 2, 2, hInc); m_wndFileView.InsertItem(_T("FakeAppView.h"), 2, 2, hInc); m_wndFileView.InsertItem(_T("Resource.h"), 2, 2, hInc); m_wndFileView.InsertItem(_T("MainFrm.h"), 2, 2, hInc); m_wndFileView.InsertItem(_T("StdAfx.h"), 2, 2, hInc); HTREEITEM hRes = m_wndFileView.InsertItem(_T("FakeApp 资源文件"), 0, 0, hRoot); m_wndFileView.InsertItem(_T("FakeApp.ico"), 2, 2, hRes); m_wndFileView.InsertItem(_T("FakeApp.rc2"), 2, 2, hRes); m_wndFileView.InsertItem(_T("FakeAppDoc.ico"), 2, 2, hRes); m_wndFileView.InsertItem(_T("FakeToolbar.bmp"), 2, 2, hRes); m_wndFileView.Expand(hRoot, TVE_EXPAND); m_wndFileView.Expand(hSrc, TVE_EXPAND); m_wndFileView.Expand(hInc, TVE_EXPAND); } void CFileView::OnChangeVisualStyle() { m_wndToolBar.CleanUpLockedImages(); m_wndToolBar.LoadBitmap(theApp.m_bHiColorIcons ? IDB_EXPLORER_24 : IDR_EXPLORER, 0, 0, TRUE /* 锁定*/); m_FileViewImages.DeleteImageList(); UINT uiBmpId = theApp.m_bHiColorIcons ? IDB_FILE_VIEW_24 : IDB_FILE_VIEW; CBitmap bmp; if (!bmp.LoadBitmap(uiBmpId)) { TRACE(_T("无法加载位图: %x\n"), uiBmpId); ASSERT(FALSE); return; } BITMAP bmpObj; bmp.GetBitmap(&bmpObj); UINT nFlags = ILC_MASK; nFlags |= (theApp.m_bHiColorIcons) ? ILC_COLOR24 : ILC_COLOR4; // Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow) m_FileViewImages.Create(16, bmpObj.bmHeight, nFlags, 0, 0); m_FileViewImages.Add(&bmp, RGB(255, 0, 255)); m_wndFileView.SetImageList(&m_FileViewImages, TVSIL_NORMAL); } ``` #### 文件树相关资源 ![img](https://images.gitee.com/uploads/images/2020/0202/232638_e9333ae2_411238.png) ![img](https://images.gitee.com/uploads/images/2020/0202/233153_0a30c53d_411238.png) #### 属性空格代码 视觉预览 ![img](https://images.gitee.com/uploads/images/2020/0203/121806_a3190bc4_411238.png) ```c++ void CPropertiesWnd::InitPropList() { SetPropListFont(); m_wndPropList.EnableHeaderCtrl(FALSE); m_wndPropList.EnableDescriptionArea(); m_wndPropList.SetVSDotNetLook(); m_wndPropList.MarkModifiedProperties(); CMFCPropertyGridProperty* pGroup1 = new CMFCPropertyGridProperty(_T("外观")); pGroup1->AddSubItem(new CMFCPropertyGridProperty(_T("三维外观"), (_variant_t) false, _T("指定窗口的字体不使用粗体,并且控件将使用三维边框"))); CMFCPropertyGridProperty* pProp = new CMFCPropertyGridProperty(_T("边框"), _T("对话框外框"), _T("其中之一:“无”、“细”、“可调整大小”或“对话框外框”")); pProp->AddOption(_T("无")); pProp->AddOption(_T("细")); pProp->AddOption(_T("可调整大小")); pProp->AddOption(_T("对话框外框")); pProp->AllowEdit(FALSE); pGroup1->AddSubItem(pProp); pGroup1->AddSubItem(new CMFCPropertyGridProperty(_T("标题"), (_variant_t) _T("关于"), _T("指定窗口标题栏中显示的文本"))); m_wndPropList.AddProperty(pGroup1); CMFCPropertyGridProperty* pSize = new CMFCPropertyGridProperty(_T("窗口大小"), 0, TRUE); pProp = new CMFCPropertyGridProperty(_T("高度"), (_variant_t) 250l, _T("指定窗口的高度")); pProp->EnableSpinControl(TRUE, 50, 300); pSize->AddSubItem(pProp); pProp = new CMFCPropertyGridProperty( _T("宽度"), (_variant_t) 150l, _T("指定窗口的宽度")); pProp->EnableSpinControl(TRUE, 50, 200); pSize->AddSubItem(pProp); m_wndPropList.AddProperty(pSize); CMFCPropertyGridProperty* pGroup2 = new CMFCPropertyGridProperty(_T("字体")); LOGFONT lf; CFont* font = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT)); font->GetLogFont(&lf); lstrcpy(lf.lfFaceName, _T("宋体, Arial")); pGroup2->AddSubItem(new CMFCPropertyGridFontProperty(_T("字体"), lf, CF_EFFECTS | CF_SCREENFONTS, _T("指定窗口的默认字体"))); pGroup2->AddSubItem(new CMFCPropertyGridProperty(_T("使用系统字体"), (_variant_t) true, _T("指定窗口使用“MS Shell Dlg”字体"))); m_wndPropList.AddProperty(pGroup2); CMFCPropertyGridProperty* pGroup3 = new CMFCPropertyGridProperty(_T("杂项")); pProp = new CMFCPropertyGridProperty(_T("(名称)"), _T("应用程序")); pProp->Enable(FALSE); pGroup3->AddSubItem(pProp); CMFCPropertyGridColorProperty* pColorProp = new CMFCPropertyGridColorProperty(_T("窗口颜色"), RGB(210, 192, 254), NULL, _T("指定默认的窗口颜色")); pColorProp->EnableOtherButton(_T("其他...")); pColorProp->EnableAutomaticButton(_T("默认"), ::GetSysColor(COLOR_3DFACE)); pGroup3->AddSubItem(pColorProp); static const TCHAR szFilter[] = _T("图标文件(*.ico)|*.ico|所有文件(*.*)|*.*||"); pGroup3->AddSubItem(new CMFCPropertyGridFileProperty(_T("图标"), TRUE, _T(""), _T("ico"), 0, szFilter, _T("指定窗口图标"))); pGroup3->AddSubItem(new CMFCPropertyGridFileProperty(_T("文件夹"), _T("c:\\"))); m_wndPropList.AddProperty(pGroup3); CMFCPropertyGridProperty* pGroup4 = new CMFCPropertyGridProperty(_T("层次结构")); CMFCPropertyGridProperty* pGroup41 = new CMFCPropertyGridProperty(_T("第一个子级")); pGroup4->AddSubItem(pGroup41); CMFCPropertyGridProperty* pGroup411 = new CMFCPropertyGridProperty(_T("第二个子级")); pGroup41->AddSubItem(pGroup411); pGroup411->AddSubItem(new CMFCPropertyGridProperty(_T("项 1"), (_variant_t) _T("值 1"), _T("此为说明"))); pGroup411->AddSubItem(new CMFCPropertyGridProperty(_T("项 2"), (_variant_t) _T("值 2"), _T("此为说明"))); pGroup411->AddSubItem(new CMFCPropertyGridProperty(_T("项 3"), (_variant_t) _T("值 3"), _T("此为说明"))); pGroup4->Expand(FALSE); m_wndPropList.AddProperty(pGroup4); } ``` #### 输出空格代码 ![img](https://images.gitee.com/uploads/images/2020/0203/170321_e81008c8_411238.png) OutputWnd.h ```c++ #pragma once ///////////////////////////////////////////////////////////////////////////// // COutputList 窗口 class COutputList : public CListBox { // 构造 public: COutputList(); // 实现 public: virtual ~COutputList(); protected: afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); afx_msg void OnEditCopy(); afx_msg void OnEditClear(); afx_msg void OnViewOutput(); DECLARE_MESSAGE_MAP() }; class COutputWnd : public CDockablePane { // 构造 public: COutputWnd(); void UpdateFonts(); // 特性 protected: CMFCTabCtrl m_wndTabs; COutputList m_wndOutputBuild; COutputList m_wndOutputDebug; COutputList m_wndOutputFind; protected: void FillBuildWindow(); void FillDebugWindow(); void FillFindWindow(); void AdjustHorzScroll(CListBox& wndListBox); // 实现 public: virtual ~COutputWnd(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); DECLARE_MESSAGE_MAP() }; ``` OutputWnd.cpp ```c++ #include "stdafx.h" #include "OutputWnd.h" #include "Resource.h" #include "MainFrm.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // COutputBar COutputWnd::COutputWnd() { } COutputWnd::~COutputWnd() { } BEGIN_MESSAGE_MAP(COutputWnd, CDockablePane) ON_WM_CREATE() ON_WM_SIZE() END_MESSAGE_MAP() int COutputWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; CRect rectDummy; rectDummy.SetRectEmpty(); // 创建选项卡窗口: if (!m_wndTabs.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, 1)) { TRACE0("未能创建输出选项卡窗口\n"); return -1; // 未能创建 } // 创建输出窗格: const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL; if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_wndTabs, 2) || !m_wndOutputDebug.Create(dwStyle, rectDummy, &m_wndTabs, 3) || !m_wndOutputFind.Create(dwStyle, rectDummy, &m_wndTabs, 4)) { TRACE0("未能创建输出窗口\n"); return -1; // 未能创建 } UpdateFonts(); CString strTabName; BOOL bNameValid; // 将列表窗口附加到选项卡: bNameValid = strTabName.LoadString(IDS_BUILD_TAB); ASSERT(bNameValid); m_wndTabs.AddTab(&m_wndOutputBuild, strTabName, (UINT)0); bNameValid = strTabName.LoadString(IDS_DEBUG_TAB); ASSERT(bNameValid); m_wndTabs.AddTab(&m_wndOutputDebug, strTabName, (UINT)1); bNameValid = strTabName.LoadString(IDS_FIND_TAB); ASSERT(bNameValid); m_wndTabs.AddTab(&m_wndOutputFind, strTabName, (UINT)2); // 使用一些虚拟文本填写输出选项卡(无需复杂数据) FillBuildWindow(); FillDebugWindow(); FillFindWindow(); return 0; } void COutputWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); // 选项卡控件应覆盖整个工作区: m_wndTabs.SetWindowPos (NULL, -1, -1, cx, cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); } void COutputWnd::AdjustHorzScroll(CListBox& wndListBox) { CClientDC dc(this); CFont* pOldFont = dc.SelectObject(&afxGlobalData.fontRegular); int cxExtentMax = 0; for (int i = 0; i < wndListBox.GetCount(); i ++) { CString strItem; wndListBox.GetText(i, strItem); cxExtentMax = max(cxExtentMax, (int)dc.GetTextExtent(strItem).cx); } wndListBox.SetHorizontalExtent(cxExtentMax); dc.SelectObject(pOldFont); } void COutputWnd::FillBuildWindow() { m_wndOutputBuild.AddString(_T("生成输出正显示在此处。")); m_wndOutputBuild.AddString(_T("输出正显示在列表视图的行中")); m_wndOutputBuild.AddString(_T("但您可以根据需要更改其显示方式...")); } void COutputWnd::FillDebugWindow() { m_wndOutputDebug.AddString(_T("调试输出正显示在此处。")); m_wndOutputDebug.AddString(_T("输出正显示在列表视图的行中")); m_wndOutputDebug.AddString(_T("但您可以根据需要更改其显示方式...")); } void COutputWnd::FillFindWindow() { m_wndOutputFind.AddString(_T("查找输出正显示在此处。")); m_wndOutputFind.AddString(_T("输出正显示在列表视图的行中")); m_wndOutputFind.AddString(_T("但您可以根据需要更改其显示方式...")); } void COutputWnd::UpdateFonts() { m_wndOutputBuild.SetFont(&afxGlobalData.fontRegular); m_wndOutputDebug.SetFont(&afxGlobalData.fontRegular); m_wndOutputFind.SetFont(&afxGlobalData.fontRegular); } ///////////////////////////////////////////////////////////////////////////// // COutputList1 COutputList::COutputList() { } COutputList::~COutputList() { } BEGIN_MESSAGE_MAP(COutputList, CListBox) ON_WM_CONTEXTMENU() ON_COMMAND(ID_EDIT_COPY, OnEditCopy) ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) ON_COMMAND(ID_VIEW_OUTPUTWND, OnViewOutput) ON_WM_WINDOWPOSCHANGING() END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COutputList 消息处理程序 void COutputList::OnContextMenu(CWnd* /*pWnd*/, CPoint point) { CMenu menu; menu.LoadMenu(IDR_OUTPUT_POPUP); CMenu* pSumMenu = menu.GetSubMenu(0); if (AfxGetMainWnd()->IsKindOf(RUNTIME_CLASS(CMDIFrameWndEx))) { CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu; if (!pPopupMenu->Create(this, point.x, point.y, (HMENU)pSumMenu->m_hMenu, FALSE, TRUE)) return; ((CMDIFrameWndEx*)AfxGetMainWnd())->OnShowPopupMenu(pPopupMenu); UpdateDialogControls(this, FALSE); } SetFocus(); } void COutputList::OnEditCopy() { MessageBox(_T("复制输出")); } void COutputList::OnEditClear() { MessageBox(_T("清除输出")); } void COutputList::OnViewOutput() { CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetOwner()); CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, GetTopLevelFrame()); if (pMainFrame != NULL && pParentBar != NULL) { pMainFrame->SetFocus(); pMainFrame->ShowPane(pParentBar, FALSE, FALSE, FALSE); pMainFrame->RecalcLayout(); } } ```