金陵十二钗正策:ListCtrl CTreeCtrl 操作 - 常见操作实例代码 - 石柱森林

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 12:00:52
 13. 得到单击的listctrl的行列号
      添加listctrl控件的NM_CLICK消息相应函数
      void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)
      {
           // 方法一:
           /*
           DWORD dwPos = GetMessagePos();
           CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
           m_list.ScreenToClient(&point);
           LVHITTESTINFO lvinfo;
           lvinfo.pt = point;
           lvinfo.flags = LVHT_ABOVE;
           int nItem = m_list.SubItemHitTest(&lvinfo);
           if(nItem != -1)
           {
                CString strtemp;
                strtemp.Format("单击的是第%d行第%d列", lvinfo.iItem, lvinfo.iSubItem);
                AfxMessageBox(strtemp);
           }
          */
          // 方法二:
          /*
           NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
           if(pNMListView->iItem != -1)
           {
                CString strtemp;
                strtemp.Format("单击的是第%d行第%d列",
                                pNMListView->iItem, pNMListView->iSubItem);
                AfxMessageBox(strtemp);
           }
          */
           *pResult = 0;
      }

14. 判断是否点击在listctrl的checkbox上
      添加listctrl控件的NM_CLICK消息相应函数
      void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)
      {
           DWORD dwPos = GetMessagePos();
           CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
           m_list.ScreenToClient(&point);
           LVHITTESTINFO lvinfo;
           lvinfo.pt = point;
           lvinfo.flags = LVHT_ABOVE;
           UINT nFlag;
           int nItem = m_list.HitTest(point, &nFlag);
           //判断是否点在checkbox上
           if(nFlag == LVHT_ONITEMSTATEICON)
           {
                AfxMessageBox("点在listctrl的checkbox上");
           }
           *pResult = 0;
      }

15. 右键点击listctrl的item弹出菜单
      添加listctrl控件的NM_RCLICK消息相应函数
      void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)
      {
           NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
           if(pNMListView->iItem != -1)
           {
                DWORD dwPos = GetMessagePos();
                CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
                CMenu menu;
                VERIFY( menu.LoadMenu( IDR_MENU1 ) );
                CMenu* popup = menu.GetSubMenu(0);
                ASSERT( popup != NULL );
                popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this );
           }
           *pResult = 0;
}

16. item切换焦点时(包括用键盘和鼠标切换item时),状态的一些变化顺序
      添加listctrl控件的LVN_ITEMCHANGED消息相应函数
      void CTest6Dlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)
      {
           NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
           // TODO: Add your control notification handler code here
           CString sTemp;
           if((pNMListView->uOldState & LVIS_FOCUSED) == LVIS_FOCUSED &&
            (pNMListView->uNewState & LVIS_FOCUSED) == 0)
           {
                sTemp.Format("%d losted focus",pNMListView->iItem);
           }
           else if((pNMListView->uOldState & LVIS_FOCUSED) == 0 &&
               (pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED)
           {
                sTemp.Format("%d got focus",pNMListView->iItem);
           }
           if((pNMListView->uOldState & LVIS_SELECTED) == LVIS_SELECTED &&
            (pNMListView->uNewState & LVIS_SELECTED) == 0)
           {
                sTemp.Format("%d losted selected",pNMListView->iItem);
           }
           else if((pNMListView->uOldState & LVIS_SELECTED) == 0 &&
            (pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED)
           {
                sTemp.Format("%d got selected",pNMListView->iItem);
           }
           *pResult = 0;
      }

 

20. listctrl的subitem添加图标
      m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);
      m_userlist.SetItem(..); //具体参数请参考msdn

21. 在CListCtrl显示文件,并根据文件类型来显示图标
      网上找到的代码,share
      BOOL CTest6Dlg::OnInitDialog()
      {
           CDialog::OnInitDialog();
           HIMAGELIST himlSmall;
           HIMAGELIST himlLarge;
           SHFILEINFO sfi;
           char cSysDir[MAX_PATH];
           CString strBuf;
           memset(cSysDir, 0, MAX_PATH);
           GetWindowsDirectory(cSysDir, MAX_PATH);
           strBuf = cSysDir;
           sprintf(cSysDir, "%s", strBuf.Left(strBuf.Find("file:///));
           himlSmall = (HIMAGELIST)SHGetFileInfo ((LPCSTR)cSysDir,
                      0,
                      &sfi,
                      sizeof(SHFILEINFO),
                      SHGFI_SYSICONINDEX | SHGFI_SMALLICON );
           himlLarge = (HIMAGELIST)SHGetFileInfo((LPCSTR)cSysDir,
                      0,
                      &sfi,
                      sizeof(SHFILEINFO),
                      SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
           if (himlSmall && himlLarge)
           {
                ::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST,
                             (WPARAM)LVSIL_SMALL, (LPARAM)himlSmall);
                ::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST,
                             (WPARAM)LVSIL_NORMAL, (LPARAM)himlLarge);
           }
           return TRUE; // return TRUE unless you set the focus to a control
      }
      void CTest6Dlg::AddFiles(LPCTSTR lpszFileName, BOOL bAddToDocument)
      {
           int nIcon = GetIconIndex(lpszFileName, FALSE, FALSE);
           CString strSize;
           CFileFind filefind;
           // get file size
           if (filefind.FindFile(lpszFileName))
           {
                filefind.FindNextFile();
                strSize.Format("%d", filefind.GetLength());
           }
           else
                strSize = "0";
           // split path and filename
           CString strFileName = lpszFileName;
           CString strPath;
           int nPos = strFileName.ReverseFind('\\');
           if (nPos != -1)
           {
                strPath = strFileName.Left(nPos);
                strFileName = strFileName.Mid(nPos + 1);
           }
           // insert to list
           int nItem = m_list.GetItemCount();
           m_list.InsertItem(nItem, strFileName, nIcon);
           m_list.SetItemText(nItem, 1, strSize);
           m_list.SetItemText(nItem, 2, strFileName.Right(3));
           m_list.SetItemText(nItem, 3, strPath);
      }
      int CTest6Dlg::GetIconIndex(LPCTSTR lpszPath, BOOL bIsDir, BOOL bSelected)
      {
           SHFILEINFO sfi;
           memset(&sfi, 0, sizeof(sfi));
           if (bIsDir)
           {
            SHGetFileInfo(lpszPath,
                         FILE_ATTRIBUTE_DIRECTORY,
                         &sfi,
                         sizeof(sfi),
                         SHGFI_SMALLICON | SHGFI_SYSICONINDEX |
                         SHGFI_USEFILEATTRIBUTES |(bSelected ? SHGFI_OPENICON : 0));
            return sfi.iIcon;
           }
           else
           {
            SHGetFileInfo (lpszPath,
                         FILE_ATTRIBUTE_NORMAL,
                         &sfi,
                         sizeof(sfi),
                         SHGFI_SMALLICON | SHGFI_SYSICONINDEX |
                         SHGFI_USEFILEATTRIBUTES | (bSelected ? SHGFI_OPENICON : 0));
            return   sfi.iIcon;
           }
           return -1;
      }  

22. listctrl内容进行大数据量更新时,避免闪烁
      m_list.SetRedraw(FALSE);
      //更新内容
      m_list.SetRedraw(TRUE);
      m_list.Invalidate();
      m_list.UpdateWindow();

23. listctrl排序


24. 在listctrl中选中某个item时动态改变其icon或bitmap


25. 在添加item后,再InsertColumn()后导致整列数据移动的问题


26. 关于listctrl第一列始终居左的问题
解决办法:把第一列当一个虚列,从第二列开始插入列及数据,最后删除第一列。

27. 锁定column header的拖动

28. 如何隐藏clistctrl的列
    把需隐藏的列的宽度设为0,然后检测当该列为隐藏列时,用上面第27点的锁定column 的拖动来实现

29. listctrl进行大数据量操作时,使用virtual list   

30. 关于item只能显示259个字符的问题
解决办法:需要在item上放一个edit。
POSITION   pos   =   m_ctrlList.GetFirstSelectedItemPosition();
if(pos)  
{  
int   nItem   =   m_ctrlList.GetNextSelectedItem(pos);
CRect   rc;
m_ctrlList.GetSubItemRect(nItem,1,LVIR_BOUNDS,rc);  
ptEdit=new   CEdit;//ptEdit是对话框类CMyDlg的CEdit类成员  
    if(ptEdit->Create(ES_CENTER,rc,&m_ctrlList,2001))  
    {  
        ptEdit->MoveWindow(rc.left,rc.top,rc.Width(),rc.Height(),TRUE);  
    ptEdit->ShowWindow(TRUE);  
    .......;  
        }  
}  

31. 响应在listctrl的column header上的鼠标右键单击


33. 以下为一些为实现各种自定义功能的listctrl派生类
          (1)    拖放       

                   在CListCtrl和CTreeCtrl间拖放

          (2)    多功能listctrl
                   支持subitem可编辑,图标,radiobutton,checkbox,字符串改变颜色的类

                   支持排序,subitem可编辑,subitem图标,subitem改变颜色的类


          (3)    subitem中显示超链接


          (4)    subitem的tooltip提示


          (5)    subitem中显示进度条   


     (6)    动态改变subitem的颜色和背景色

          (8)    选中subitem(只高亮选中的item)
          (9)    改变行高
          (10)   改变行颜色
          (11)   可编辑subitem的listctrl

          (12)   subitem可编辑,插入combobox,改变行颜色,subitem的tooltip提示

          (13)   header 中允许多行字符串
          (14)   插入combobox

          (15)   添加背景图片

          (16) 自适应宽度的listctrl

9:16 | 添加评论 | 固定链接 | 写入日志
CTreeCtrl的用法
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点。MFC中使用 CTreeCtrl类来封装树形控件的各种操作。通过调用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的专用风格:

TVS_HASLINES 在父/子结点之间绘制连线

TVS_LINESATROOT 在根/子结点之间绘制连线

TVS_HASBUTTONS 在每一个结点前添加一个按钮,用于表示当前结点是否已被展开

TVS_EDITLABELS 结点的显示字符可以被编辑

TVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点

TVS_DISABLEDRAGDROP 不允许Drag/Drop

TVS_NOTOOLTIPS 不使用ToolTip显示结点的显示字符

在树形控件中每一个结点都有一个句柄(HTREEITEM),同时添加结点时必须提供的参数是该结点的父结点句柄,(其中根Root结点只有一个,既不可以添加也不可以删除)利用
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一个结点,pszItem为显示的字符,hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。下面的代码会建立一个如下形式的树形结构:

+--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假设m_tree为一个CTreeCtrl对象,而且该窗口已经创建*/

HTREEITEM hItem,hSubItem;
hItem = m_tree.InsertItem("Parent1",TVI_ROOT); 在根结点上添加Parent1
hSubItem = m_tree.InsertItem("Child1_1",hItem); //在Parent1上添加一个子结点
hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem); //在Parent1上添加一个子结点,排在Child1_1后面
hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem);
hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem);
hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem);

如果你希望在每个结点前添加一个小图标,就必需先调用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明当前所使用的ImageList,nImageListType为TVSIL_NORMAL。在调用完成后控件中使用图片以设置的 ImageList中图片为准。然后调用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加结点,nImage为结点没被选中时所使用图片序号,nSelectedImage为结点被选中时所使用图片序号。下面的代码演示了ImageList的设置。

/*m_list 为CImageList对象 IDB_TREE 为16*(16*4)的位图,每个图片为16*16共4个图标*/

m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1); //添加,选中时显示图标1,未选中时显示图标0


此外CTreeCtrl还提供了一些函数用于得到/修改控件的状态。
HTREEITEM GetSelectedItem( );将返回当前选中的结点的句柄。BOOL SelectItem( HTREEITEM hItem );将选中指明结点。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某结点所使用图标索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一结点的显示字符。
BOOL DeleteItem( HTREEITEM hItem );用于删除某一结点,BOOL DeleteAllItems( );将删除所有结点。

此外如果想遍历树可以使用下面的函数:
HTREEITEM GetRootItem( );得到根结点。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子结点。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明结点的上/下一个兄弟结点。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父结点。

树形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于树形控件可能取值和对应的数据结构为:

TVN_SELCHANGED 在所选中的结点发生改变后发送,所用结构:NMTREEVIEW

TVN_ITEMEXPANDED 在某结点被展开后发送,所用结构:NMTREEVIEW

TVN_BEGINLABELEDIT 在开始编辑结点字符时发送,所用结构:NMTVDISPINFO

TVN_ENDLABELEDIT 在结束编辑结点字符时发送,所用结构:NMTVDISPINFO

TVN_GETDISPINFO 在需要得到某结点信息时发送,(如得到结点的显示字符)所用结构:NMTVDISPINFO

关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。

关于动态提供结点所显示的字符:首先你在添加结点时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送 TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMTVDISPINFO,然后填充其中 item.pszText。但是我们通过什么来知道该结点所对应的信息呢,我的做法是在添加结点后设置其lParam参数,然后在提供信息时利用该参数来查找所对应的信息。下面的代码说明了这种方法:

char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点
HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...);
m_tree.SetItemData(hItem, 0 );
hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem, 1 ); //处理消息 void
CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
pTVDI->item.pszText=szOut[pTVDI->item.lParam]; //通过lParam得到需要显示的字符在数组中的位置 *pResult = 0; }

关于编辑结点的显示字符:首先需要设置树形控件的TVS_EDITLABELS风格,在开始编辑时该控件将会发送 TVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送TVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为 LPNMTVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息:

//处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText); //重置显示字符 *pResult = 0; }

上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。

1.取得或设定项目的信息.

BOOL CTreeCtrl::GetItem(TV_ITEM* pItem);
BOOL CTreeCtrl::SetItem(TV_ITEM* pItem);
BOOL CTreeCtrl::SetItem(HTREEITEM hItem,UINTnMask,LPCTSTR lpszItem,int Image,int nSelectedImage,UINT nState,UINT nStateMask,LPARAME lParam);

2.取得与设定项目的状态

UINT CTreeCtrl::GetItemState(HTREEITEM hItem,UINT sStateMask)const;
BOOL CTree Ctrl::SetItemState(HTREEITEM hItem,UINT nState,UINT nStateMask);

3.取得与设定项目的图形

BOOL CTreeCtrl::GetItemImage(HTREEITEM hItem,int& nImage,int& nSelectedImage)const;
BOOL CTreeCtrl::SetItemImage(HTREEITEM hItem,int nImage,int nSelectedImage);

4. 取得与设定项目的文本

CString CTreeCtrl::GetItemText(HTREEITEM,hItem)const;
BOOL CTreeCtrl::SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);

5. 查询 CTreeCtrl 中项目的个数

UINT CTreeCtrl::GetCount();

6.查询hItem 的父项目的句柄

HTREEITEM CTreeCtrl::GetparenItem(HTREEITEM hItem);

7.查询hItem是否有子项

BOOL CTreeCtrl::ItemHasChildren(HTREEITEM hItem);

8.取得hItem 第一个子项的句柄

HTREEITEM CTreeCtrl::GetChildItem(HTREEITEM hItem);

9.查询排在hItem前后的兄弟项

HTREEITEM CTreeCtrl::GetPrevSiblingItem(HTREEITEM hItem);
HTREEITEM CTreeCtrl::GetNextSiblingItem(HTREEITEM hItem);

10.取得选中项的句柄 取得根项的句柄

HTREEITEM CTreeCtrl::GetSelectedItem();

HTREEITEM CTreeCtrl::GetRootItem();

 原文地址 http://hi.baidu.com/jjzhang166/blog/item/42c4a84582dbfd2acffca3e4.html