CListCtrl编程示例(设计MyView)
目标:
l 实现大图标,小图标,详细列表,列表视图的实现
l 当双击ModelBar时,若为目录,则在MyView中列出其子结点;若为模型,列出其所在目录的结点
l 在Myview下若双击目录,进入下一级,若双击模型,则提供预览
l 提供向上,后退,前进功能
第一步:设定CListCtrl
1
定义变量:
CListCtrl& m_list ;
CImageList *m_pLargeImageList;
CImageList *m_pSmallImageList;
CImageList *m_pMiddleImageList;
ViewMode m_viewMode;
2
设置风格
void CMyView::OnInitialUpdate()
{
……
DWORD dwStyle = m_list.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
//dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
m_list.SetExtendedStyle(dwStyle); //设置扩展风格
m_pLargeImageList = new CImageList();
ASSERT(m_pLargeImageList != NULL); // serious allocation failure checking
m_pLargeImageList->Create(64, 64, ILC_COLOR32, 4, 4);
m_pLargeImageList->Add(AfxGetApp()->LoadIcon(IDR_MAINFRAME));
m_pLargeImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON1));
m_pSmallImageList = new CImageList();
ASSERT(m_pSmallImageList != NULL); // serious allocation failure checking
m_pSmallImageList->Create(16, 16, ILC_COLOR32, 4, 4);
m_pSmallImageList->Add(AfxGetApp()->LoadIcon(IDR_MAINFRAME));
m_pSmallImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON1));
m_pMiddleImageList = new CImageList();
ASSERT(m_pMiddleImageList != NULL); // serious allocation failure checking
m_pMiddleImageList->Create(32, 32, ILC_COLOR32, 4, 4);
m_pMiddleImageList->Add(AfxGetApp()->LoadIcon(IDR_MAINFRAME));
m_pMiddleImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON1));
//默认情况下是小图标模式
m_list.SetImageList(m_pMiddleImageList, LVSIL_SMALL);
m_list.InsertColumn( 0, "名称", LVCFMT_LEFT, 250 );//插入列
m_list.InsertColumn( 1, "大小", LVCFMT_LEFT, 150);
m_list.InsertColumn( 2, "类型", LVCFMT_LEFT, 50);
m_list.InsertColumn( 3, "修改日期", LVCFMT_LEFT, 150);
m_list.InsertColumn( 4, "创建者", LVCFMT_LEFT, 150);
m_list.InsertColumn( 5, "描述信息", LVCFMT_LEFT, 250);
//默认是详细report视图
LONG lStyle=GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style
m_list.SetImageList(m_pSmallImageList, LVSIL_SMALL);
m_list.Arrange(LVA_ALIGNTOP);//自动调整位置,防止重叠
……
}
第二步:编写updateModelView
根据指定的位置进行更新CmyView
若为目录,则在MyView中列出其子结点;若为模型,列出其所在目录的结点
void CMyView::updateModelView(int modelIndex)
{
m_list.DeleteAllItems();
m_viewMode=MODEL_VIEW;
//确保modelIndex有效
ASSERT(modelIndex>=0&&modelIndex<(int)DBM.m_modelItemVec.size());
//若为模型,列出其所在目录的结点
if (!(DBM.m_modelItemVec[modelIndex].flag))
{
modelIndex=DBM.m_modelItemVec[modelIndex].parent;
}
//const CModelItem &itemT=DBM.m_modelItemVec[modelIndex];
for (size_t i=0;i<DBM.m_modelItemVec[modelIndex].children.size();i++)
{
int j=DBM.m_modelItemVec[modelIndex].children[i];
const CModelItem &itemT=DBM.m_modelItemVec[j];
CString str;
int nRow = m_list.InsertItem(j,itemT.name.c_str(),itemT.flag);//插入行
if (!itemT.flag)//若是模型
{
int sizeKB=(double)itemT.dataSize/1024.0+0.5;//四舍五入
str.Format("%d KB",sizeKB);
m_list.SetItemText(nRow, 1, str);//设置数据
}
itemT.flag?str.Format("文件夹"):str.Format("模型");
m_list.SetItemText(nRow, 2, str);
m_list.SetItemText(nRow, 3, itemT.dateTime.substr(0,16).c_str());
m_list.SetItemText(nRow, 4, itemT.owner.c_str());
m_list.SetItemText(nRow, 5, itemT.description.c_str());
}
}
第三步:树型控件的双击函数,此时激活CMyView并且列表显示
void CModelBar::CMyTreeCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
//双击应该响应MyView
HTREEITEM ht=this->GetSelectedItem();
int depthT=0;//当前选择所在的层数,根据层数和名字可以唯一确定选择项目
string nameT=GetItemText(ht);
while(GetParentItem(ht)!=NULL)
{
depthT++;
ht=GetParentItem(ht);
}
int indexT=DBM.getIndexByDepthAndName(depthT,nameT);
ASSERT(indexT!=MY_NOTEXIST);
((CMyView *)(GLB.m_pMyView))->updateModelView(indexT);
*pResult = 1;
}
第四步:编写CMyView的的双击函数,进入下一级,若为模型,则提供预览
void CMyView::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
int nItem=-1;
nItem = m_list.GetNextItem(nItem, LVNI_SELECTED);
if(nItem==-1) return;
int indexT=atoi(m_list.GetItemText(nItem,6).GetBuffer());
indexT=DBM.getIndexByID(indexT);
if (DBM.m_modelItemVec[indexT].flag)//若是目录
{
updateModelView(indexT);
}
else
{
//预览
}
*pResult = 0;
}
第五步:设置后退,前进,向上的功能
第六步:自动排序(ID和Size按照数字大小,其它按照字母顺序)
1
定义数据结构
struct SortData
{
CListCtrl *m_list;
BOOL flags[20];//1从小到大
unsigned int curPos;
};
2
定义比较函数
注意:务必调用m_list.SetItemData(nRow,nRow);给每个设置唯一标识,最好是元素位置
int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CMyView::SortData *sd=(CMyView::SortData *)lParamSort;
LVFINDINFO findInfo;
findInfo.flags = LVFI_PARAM;
findInfo.lParam = lParam1;
int iItem1 = sd->m_list->FindItem(&findInfo, -1);
findInfo.lParam = lParam2;
int iItem2 = sd->m_list->FindItem(&findInfo, -1);
CString strItem1 =sd->m_list->GetItemText(iItem1,sd->curPos);
CString strItem2 =sd->m_list->GetItemText(iItem2,sd->curPos);
if ((sd->curPos==6)||(sd->curPos==1))//ID和大小按照数字大小排序
{
……
}
else//其它按照字母顺序排序
{
……
}
}
3.
响应点击列的函数,找到列号和排序方向
void CMyView::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
m_sortData.curPos=pNMLV->iSubItem;
m_sortData.flags[m_sortData.curPos]=!m_sortData.flags[m_sortData.curPos];
m_sortData.m_list=&m_list;
m_list.SortItems(MyCompareProc,(LPARAM)&m_sortData);
*pResult = 0;
}