VS之treeview和listview拆分窗口

时间:2021-05-13 21:30:25

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.文件结构目录

VS之treeview和listview拆分窗口 VS之treeview和listview拆分窗口

6.测试效果

点击treeview的不同项显示不同的listview。

VS之treeview和listview拆分窗口 VS之treeview和listview拆分窗口

ok,功能实现啦!


源码下载