VS中,经常会使用到窗口的拆分技术,下面以treeview和listview来拆分窗口
使用工具:VS2008
使用语言:C++
开发步骤:
1.新建单文档程序应用程序
2.新建一个treeview并设置属性和需要显示的数据架构
MyTreeView.h
#pragma once // CMyTreeView 视图 //View1 #define VIEW1_ROOT 0x10 #define VIEW1_SUB 0x11 //View2 #define VIEW2_ROOT 0x20 #define VIEW2_SUB 0x21 class CMyTreeView : public CTreeView { DECLARE_DYNCREATE(CMyTreeView) protected: CMyTreeView(); // 动态创建所使用的受保护的构造函数 virtual ~CMyTreeView(); public: #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: DECLARE_MESSAGE_MAP() public: HTREEITEM m_TreeItem1; HTREEITEM m_TreeItem2; virtual void OnInitialUpdate(); void UpdateTree(void); void UpdateTree1(void); void UpdateTree2(void); afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult); void ShowView(HTREEITEM select_item); };
MyTreeView.cpp
// MyTreeView.cpp : 实现文件 // #include "stdafx.h" #include "TreeListViewDemo.h" #include "MyTreeView.h" #include "MainFrm.h" // CMyTreeView IMPLEMENT_DYNCREATE(CMyTreeView, CTreeView) CMyTreeView::CMyTreeView() { } CMyTreeView::~CMyTreeView() { } BEGIN_MESSAGE_MAP(CMyTreeView, CTreeView) ON_NOTIFY_REFLECT(NM_CLICK, &CMyTreeView::OnNMClick) END_MESSAGE_MAP() // CMyTreeView 诊断 #ifdef _DEBUG void CMyTreeView::AssertValid() const { CTreeView::AssertValid(); } #ifndef _WIN32_WCE void CMyTreeView::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif #endif //_DEBUG // CMyTreeView 消息处理程序 void CMyTreeView::OnInitialUpdate() { CTreeView::OnInitialUpdate(); // TODO: 在此添加专用代码和/或调用基类 //属性 CTreeCtrl& tree = GetTreeCtrl(); DWORD dwStyle = GetWindowLong(tree,GWL_STYLE); dwStyle |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS; SetWindowLong(tree,GWL_STYLE,dwStyle); CFont font; font.CreateFont( 20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("宋体")); tree.SetFont(&font); UpdateTree(); } void CMyTreeView::UpdateTree(void) { CTreeCtrl& tree = GetTreeCtrl(); tree.DeleteAllItems(); UpdateTree1(); UpdateTree2(); } void CMyTreeView::UpdateTree1(void) { CTreeCtrl& tree = GetTreeCtrl(); CString str = _T(""); int i=0, cnt = 0; HTREEITEM root,sub; str = _T("View1"); root = tree.InsertItem(str,0,0,TVI_ROOT); tree.SetItemData(root,VIEW1_ROOT); m_TreeItem1 = root; cnt = 2; for(i=0; i<cnt; i++) { str.Format(_T("View1 %d"),i); sub = tree.InsertItem(str,1,1,m_TreeItem1); tree.SetItemData(sub,VIEW1_SUB); } tree.Expand(m_TreeItem1,TVE_EXPAND); } void CMyTreeView::UpdateTree2(void) { CTreeCtrl& tree = GetTreeCtrl(); CString str = _T(""); int i=0, cnt = 0; HTREEITEM root,sub; str = _T("View2"); root = tree.InsertItem(str,0,0,TVI_ROOT); tree.SetItemData(root,VIEW2_ROOT); m_TreeItem2 = root; cnt = 3; for(i=0; i<cnt; i++) { str.Format(_T("View2 %d"),i); sub = tree.InsertItem(str,1,1,m_TreeItem2); tree.SetItemData(sub,VIEW2_SUB); } tree.Expand(m_TreeItem2,TVE_EXPAND); } void CMyTreeView::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此添加控件通知处理程序代码 CTreeCtrl& tree = GetTreeCtrl(); CPoint CursorPoint; if(!GetCursorPos(&CursorPoint)) { return; } tree.ScreenToClient(&CursorPoint); UINT uFlag=0; HTREEITEM select_item = tree.HitTest(CursorPoint,&uFlag); if((NULL != select_item) && (TVHT_ONITEM&uFlag)) { tree.Select(select_item,TVGN_CARET); } else { return; } ShowView(select_item); *pResult = 0; } void CMyTreeView::ShowView(HTREEITEM select_item) { CTreeCtrl& tree = GetTreeCtrl(); DWORD dwData = tree.GetItemData(select_item); CString sText = tree.GetItemText(select_item); switch(dwData) { case VIEW1_ROOT: ((CMainFrame*)(GetParent()->GetParent()))->ShowListView1(); break; case VIEW1_SUB: ((CMainFrame*)(GetParent()->GetParent()))->ShowListView1(); break; case VIEW2_ROOT: ((CMainFrame*)(GetParent()->GetParent()))->ShowListView2(); break; case VIEW2_SUB: ((CMainFrame*)(GetParent()->GetParent()))->ShowListView2(); break; default: break; } }
3.新建多个listview
MyListView1.h
#pragma once // CMyListView1 视图 class CMyListView1 : public CListView { DECLARE_DYNCREATE(CMyListView1) protected: CMyListView1(); // 动态创建所使用的受保护的构造函数 virtual ~CMyListView1(); public: #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: DECLARE_MESSAGE_MAP() public: virtual void OnInitialUpdate(); void UpdateList(void); };
MyListView1.cpp
// MyListView1.cpp : 实现文件 // #include "stdafx.h" #include "TreeListViewDemo.h" #include "MyListView1.h" // CMyListView1 IMPLEMENT_DYNCREATE(CMyListView1, CListView) CMyListView1::CMyListView1() { } CMyListView1::~CMyListView1() { } BEGIN_MESSAGE_MAP(CMyListView1, CListView) END_MESSAGE_MAP() // CMyListView1 诊断 #ifdef _DEBUG void CMyListView1::AssertValid() const { CListView::AssertValid(); } #ifndef _WIN32_WCE void CMyListView1::Dump(CDumpContext& dc) const { CListView::Dump(dc); } #endif #endif //_DEBUG // CMyListView1 消息处理程序 void CMyListView1::OnInitialUpdate() { CListView::OnInitialUpdate(); // TODO: 在此添加专用代码和/或调用基类 //属性设置 CListCtrl& list = GetListCtrl(); list.ModifyStyle(LVS_TYPEMASK,LVS_REPORT & LVS_TYPEMASK | LVS_SINGLESEL);//important for show DWORD dwStyle = list.GetExtendedStyle(); list.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); CImageList image; image.Create(1,20,ILC_COLOR24 | ILC_MASK,4,0); list.SetImageList(&image,LVSIL_SMALL); CFont font; font.CreateFont( 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("宋体")); list.SetFont(&font); list.GetHeaderCtrl()->SetFont(&font); //标题栏 list.InsertColumn(0,_T("CMyListView1 Name"),LVCFMT_LEFT,200,0); list.InsertColumn(1,_T("Comment"),LVCFMT_LEFT,100,0); } void CMyListView1::UpdateList(void) { CListCtrl& list = GetListCtrl(); list.DeleteAllItems(); CString str=_T(""); for(int i=0; i<2; i++) { str.Format(_T("Name1 %d"),i); list.InsertItem(i,str); str.Format(_T("Comment1 %d"),i); list.SetItemText(i,1,str); } }
MyListView2.h
#pragma once // CMyListView2 视图 class CMyListView2 : public CListView { DECLARE_DYNCREATE(CMyListView2) protected: CMyListView2(); // 动态创建所使用的受保护的构造函数 virtual ~CMyListView2(); public: #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: DECLARE_MESSAGE_MAP() public: virtual void OnInitialUpdate(); void UpdateList(void); };
MyListView2.cpp
// MyListView2.cpp : 实现文件 // #include "stdafx.h" #include "TreeListViewDemo.h" #include "MyListView2.h" // CMyListView2 IMPLEMENT_DYNCREATE(CMyListView2, CListView) CMyListView2::CMyListView2() { } CMyListView2::~CMyListView2() { } BEGIN_MESSAGE_MAP(CMyListView2, CListView) END_MESSAGE_MAP() // CMyListView2 诊断 #ifdef _DEBUG void CMyListView2::AssertValid() const { CListView::AssertValid(); } #ifndef _WIN32_WCE void CMyListView2::Dump(CDumpContext& dc) const { CListView::Dump(dc); } #endif #endif //_DEBUG // CMyListView2 消息处理程序 void CMyListView2::OnInitialUpdate() { CListView::OnInitialUpdate(); // TODO: 在此添加专用代码和/或调用基类 //属性设置 CListCtrl& list = GetListCtrl(); list.ModifyStyle(LVS_TYPEMASK,LVS_REPORT & LVS_TYPEMASK | LVS_SINGLESEL);//important for show DWORD dwStyle = list.GetExtendedStyle(); list.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); CImageList image; image.Create(1,20,ILC_COLOR24 | ILC_MASK,4,0); list.SetImageList(&image,LVSIL_SMALL); CFont font; font.CreateFont( 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("宋体")); list.SetFont(&font); list.GetHeaderCtrl()->SetFont(&font); //标题栏 list.InsertColumn(0,_T("CMyListView2 Name"),LVCFMT_LEFT,200,0); list.InsertColumn(1,_T("Comment"),LVCFMT_LEFT,100,0); } void CMyListView2::UpdateList(void) { CListCtrl& list = GetListCtrl(); list.DeleteAllItems(); CString str=_T(""); for(int i=0; i<3; i++) { str.Format(_T("Name2 %d"),i); list.InsertItem(i,str); str.Format(_T("Comment2 %d"),i); list.SetItemText(i,1,str); } }
4.CMainFrame处理
在CMainFrame中添加拆分窗口和视图窗口相关变量,并且在构造函数中设置其初始值为空,重写OnCreateClient函数来拆分窗口:左边treeview,右边listview
MainFrm.h
// MainFrm.h : CMainFrame 类的接口 // #include "MyTreeView.h" #include "MyListView1.h" #include "MyListView2.h" #pragma once class CMainFrame : public CFrameWnd { protected: // 仅从序列化创建 CMainFrame(); DECLARE_DYNCREATE(CMainFrame) // 属性 public: // 操作 public: // 重写 public: virtual BOOL PreCreateWindow(CREATESTRUCT& cs); // 实现 public: virtual ~CMainFrame(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // 控件条嵌入成员 CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; // 生成的消息映射函数 protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext); private: CSplitterWnd m_wndSplitter; CMyTreeView* m_pMyTreeView; CMyListView1* m_pCMyListView1; CMyListView2* m_pCMyListView2; public: void ShowListView1(void); void ShowListView2(void); };
MainFrm.cpp
// MainFrm.cpp : CMainFrame 类的实现 // #include "stdafx.h" #include "TreeListViewDemo.h" #include "MainFrm.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() static UINT indicators[] = { ID_SEPARATOR, // 状态行指示器 ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; // CMainFrame 构造/析构 CMainFrame::CMainFrame() { // TODO: 在此添加成员初始化代码 m_pMyTreeView = NULL; m_pCMyListView1 = NULL; m_pCMyListView2 = NULL; } CMainFrame::~CMainFrame() { } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("未能创建工具栏\n"); return -1; // 未能创建 } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("未能创建状态栏\n"); return -1; // 未能创建 } // TODO: 如果不需要可停靠工具栏,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: 在此处通过修改 // CREATESTRUCT cs 来修改窗口类或样式 return TRUE; } // CMainFrame 诊断 #ifdef _DEBUG void CMainFrame::AssertValid() const { CFrameWnd::AssertValid(); } void CMainFrame::Dump(CDumpContext& dc) const { CFrameWnd::Dump(dc); } #endif //_DEBUG // CMainFrame 消息处理程序 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { // TODO: 在此添加专用代码和/或调用基类 //拆分窗口 if(!m_wndSplitter.CreateStatic(this,1,2)) { return FALSE; } if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMyTreeView),CSize(300,100),pContext) || !m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CMyListView1),CSize(100,100),pContext)) { m_wndSplitter.DestroyWindow(); return FALSE; } m_pMyTreeView = (CMyTreeView*)m_wndSplitter.GetPane(0,0); return TRUE; //return CFrameWnd::OnCreateClient(lpcs, pContext); } void CMainFrame::ShowListView1(void) { if(m_pCMyListView1) { m_pCMyListView1->UpdateList(); } else { CRect rect; CSize size; m_wndSplitter.GetPane(0,1)->GetWindowRect(&rect); size.cx = rect.Width(); size.cy = rect.Height(); CCreateContext Context; Context.m_pCurrentDoc = NULL; Context.m_pCurrentFrame = this; Context.m_pNewViewClass = RUNTIME_CLASS(CMyListView1); m_wndSplitter.DeleteView(0,1); m_wndSplitter.CreateView(0,1,Context.m_pNewViewClass,size,&Context); m_pCMyListView1 = (CMyListView1*)m_wndSplitter.GetPane(0,1); m_wndSplitter.RecalcLayout(); m_pCMyListView1->OnInitialUpdate(); m_pCMyListView1->UpdateList(); // m_pCMyListView1 = NULL; m_pCMyListView2 = NULL; } } void CMainFrame::ShowListView2(void) { if(m_pCMyListView2) { m_pCMyListView2->UpdateList(); } else { CRect rect; CSize size; m_wndSplitter.GetPane(0,1)->GetWindowRect(&rect); size.cx = rect.Width(); size.cy = rect.Height(); CCreateContext Context; Context.m_pCurrentDoc = NULL; Context.m_pCurrentFrame = this; Context.m_pNewViewClass = RUNTIME_CLASS(CMyListView2); m_wndSplitter.DeleteView(0,1); m_wndSplitter.CreateView(0,1,Context.m_pNewViewClass,size,&Context); m_pCMyListView2 = (CMyListView2*)m_wndSplitter.GetPane(0,1); m_wndSplitter.RecalcLayout(); m_pCMyListView2->OnInitialUpdate(); m_pCMyListView2->UpdateList(); m_pCMyListView1 = NULL; // m_pCMyListView2 = NULL; } }
5.文件结构目录
6.测试效果
点击treeview的不同项显示不同的listview。
ok,功能实现啦!