13. 得到單擊的listctrl的行列號(hào)
13. 得到單擊的listctrl的行列號(hào)
添加listctrl控件的NM_CLICK消息相應(yīng)函數(shù)
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. 判斷是否點(diǎn)擊在listctrl的checkbox上
添加listctrl控件的NM_CLICK消息相應(yīng)函數(shù)
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);
//判斷是否點(diǎn)在checkbox上
if(nFlag == LVHT_ONITEMSTATEICON)
{
AfxMessageBox("點(diǎn)在listctrl的checkbox上");
}
*pResult = 0;
}
15. 右鍵點(diǎn)擊listctrl的item彈出菜單
添加listctrl控件的NM_RCLICK消息相應(yīng)函數(shù)
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切換焦點(diǎn)時(shí)(包括用鍵盤和鼠標(biāo)切換item時(shí)),狀態(tài)的一些變化順序
添加listctrl控件的LVN_ITEMCHANGED消息相應(yīng)函數(shù)
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添加圖標(biāo)
m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);
m_userlist.SetItem(..); //具體參數(shù)請(qǐng)參考msdn
21. 在CListCtrl顯示文件,并根據(jù)文件類型來顯示圖標(biāo)
網(wǎng)上找到的代碼,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內(nèi)容進(jìn)行大數(shù)據(jù)量更新時(shí),避免閃爍
m_list.SetRedraw(FALSE);
//更新內(nèi)容
m_list.SetRedraw(TRUE);
m_list.Invalidate();
m_list.UpdateWindow();
23. listctrl排序
24. 在listctrl中選中某個(gè)item時(shí)動(dòng)態(tài)改變其icon或bitmap
25. 在添加item后,再InsertColumn()后導(dǎo)致整列數(shù)據(jù)移動(dòng)的問題
26. 關(guān)于listctrl第一列始終居左的問題
解決辦法:把第一列當(dāng)一個(gè)虛列,從第二列開始插入列及數(shù)據(jù),最后刪除第一列。
27. 鎖定column header的拖動(dòng)
28. 如何隱藏clistctrl的列
把需隱藏的列的寬度設(shè)為0,然后檢測當(dāng)該列為隱藏列時(shí),用上面第27點(diǎn)的鎖定column 的拖動(dòng)來實(shí)現(xiàn)
29. listctrl進(jìn)行大數(shù)據(jù)量操作時(shí),使用virtual list
30. 關(guān)于item只能顯示259個(gè)字符的問題
解決辦法:需要在item上放一個(gè)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是對(duì)話框類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. 響應(yīng)在listctrl的column header上的鼠標(biāo)右鍵單擊
33. 以下為一些為實(shí)現(xiàn)各種自定義功能的listctrl派生類
(1) 拖放
在CListCtrl和CTreeCtrl間拖放
(2) 多功能listctrl
支持subitem可編輯,圖標(biāo),radiobutton,checkbox,字符串改變顏色的類
支持排序,subitem可編輯,subitem圖標(biāo),subitem改變顏色的類
(3) subitem中顯示超鏈接
(4) subitem的tooltip提示
(5) subitem中顯示進(jìn)度條
(6) 動(dòng)態(tài)改變subitem的顏色和背景色
(8) 選中subitem(只高亮選中的item)
(9) 改變行高
(10) 改變行顏色
(11) 可編輯subitem的listctrl
(12) subitem可編輯,插入combobox,改變行顏色,subitem的tooltip提示
(13) header 中允許多行字符串
(14) 插入combobox
(15) 添加背景圖片
(16) 自適應(yīng)寬度的listctrl
9:16 | 添加評(píng)論 | 固定鏈接 | 寫入日志
CTreeCtrl的用法
樹形控件可以用于樹形的結(jié)構(gòu),其中有一個(gè)根接點(diǎn)(Root)然后下面有許多子結(jié)點(diǎn),而每個(gè)子結(jié)點(diǎn)上有允許有一個(gè)或多個(gè)或沒有子結(jié)點(diǎn)。MFC中使用 CTreeCtrl類來封裝樹形控件的各種操作。通過調(diào)用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );創(chuàng)建一個(gè)窗口,dwStyle中可以使用以下一些樹形控件的專用風(fēng)格:
TVS_HASLINES 在父/子結(jié)點(diǎn)之間繪制連線
TVS_LINESATROOT 在根/子結(jié)點(diǎn)之間繪制連線
TVS_HASBUTTONS 在每一個(gè)結(jié)點(diǎn)前添加一個(gè)按鈕,用于表示當(dāng)前結(jié)點(diǎn)是否已被展開
TVS_EDITLABELS 結(jié)點(diǎn)的顯示字符可以被編輯
TVS_SHOWSELALWAYS 在失去焦點(diǎn)時(shí)也顯示當(dāng)前選中的結(jié)點(diǎn)
TVS_DISABLEDRAGDROP 不允許Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip顯示結(jié)點(diǎn)的顯示字符
在樹形控件中每一個(gè)結(jié)點(diǎn)都有一個(gè)句柄(HTREEITEM),同時(shí)添加結(jié)點(diǎn)時(shí)必須提供的參數(shù)是該結(jié)點(diǎn)的父結(jié)點(diǎn)句柄,(其中根Root結(jié)點(diǎn)只有一個(gè),既不可以添加也不可以刪除)利用
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一個(gè)結(jié)點(diǎn),pszItem為顯示的字符,hParent代表父結(jié)點(diǎn)的句柄,當(dāng)前添加的結(jié)點(diǎn)會(huì)排在hInsertAfter表示的結(jié)點(diǎn)的后面,返回值為當(dāng)前創(chuàng)建的結(jié)點(diǎn)的句柄。下面的代碼會(huì)建立一個(gè)如下形式的樹形結(jié)構(gòu):
+--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假設(shè)m_tree為一個(gè)CTreeCtrl對(duì)象,而且該窗口已經(jīng)創(chuàng)建*/
HTREEITEM hItem,hSubItem;
hItem = m_tree.InsertItem("Parent1",TVI_ROOT); 在根結(jié)點(diǎn)上添加Parent1
hSubItem = m_tree.InsertItem("Child1_1",hItem); //在Parent1上添加一個(gè)子結(jié)點(diǎn)
hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem); //在Parent1上添加一個(gè)子結(jié)點(diǎn),排在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);
如果你希望在每個(gè)結(jié)點(diǎn)前添加一個(gè)小圖標(biāo),就必需先調(diào)用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明當(dāng)前所使用的ImageList,nImageListType為TVSIL_NORMAL。在調(diào)用完成后控件中使用圖片以設(shè)置的 ImageList中圖片為準(zhǔn)。然后調(diào)用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加結(jié)點(diǎn),nImage為結(jié)點(diǎn)沒被選中時(shí)所使用圖片序號(hào),nSelectedImage為結(jié)點(diǎn)被選中時(shí)所使用圖片序號(hào)。下面的代碼演示了ImageList的設(shè)置。
/*m_list 為CImageList對(duì)象 IDB_TREE 為16*(16*4)的位圖,每個(gè)圖片為16*16共4個(gè)圖標(biāo)*/
m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1); //添加,選中時(shí)顯示圖標(biāo)1,未選中時(shí)顯示圖標(biāo)0
此外CTreeCtrl還提供了一些函數(shù)用于得到/修改控件的狀態(tài)。
HTREEITEM GetSelectedItem( );將返回當(dāng)前選中的結(jié)點(diǎn)的句柄。BOOL SelectItem( HTREEITEM hItem );將選中指明結(jié)點(diǎn)。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某結(jié)點(diǎn)所使用圖標(biāo)索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一結(jié)點(diǎn)的顯示字符。
BOOL DeleteItem( HTREEITEM hItem );用于刪除某一結(jié)點(diǎn),BOOL DeleteAllItems( );將刪除所有結(jié)點(diǎn)。
此外如果想遍歷樹可以使用下面的函數(shù):
HTREEITEM GetRootItem( );得到根結(jié)點(diǎn)。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結(jié)點(diǎn)。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結(jié)點(diǎn)的上/下一個(gè)兄弟結(jié)點(diǎn)。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父結(jié)點(diǎn)。
樹形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知代碼,id為產(chǎn)生該消息的窗口ID,memberFxn為處理函數(shù),函數(shù)的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一數(shù)據(jù)結(jié)構(gòu),在具體使用時(shí)需要轉(zhuǎn)換成其他類型的結(jié)構(gòu)。對(duì)于樹形控件可能取值和對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)為:
TVN_SELCHANGED 在所選中的結(jié)點(diǎn)發(fā)生改變后發(fā)送,所用結(jié)構(gòu):NMTREEVIEW
TVN_ITEMEXPANDED 在某結(jié)點(diǎn)被展開后發(fā)送,所用結(jié)構(gòu):NMTREEVIEW
TVN_BEGINLABELEDIT 在開始編輯結(jié)點(diǎn)字符時(shí)發(fā)送,所用結(jié)構(gòu):NMTVDISPINFO
TVN_ENDLABELEDIT 在結(jié)束編輯結(jié)點(diǎn)字符時(shí)發(fā)送,所用結(jié)構(gòu):NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某結(jié)點(diǎn)信息時(shí)發(fā)送,(如得到結(jié)點(diǎn)的顯示字符)所用結(jié)構(gòu):NMTVDISPINFO
關(guān)于ON_NOTIFY有很多內(nèi)容,將在以后的內(nèi)容中進(jìn)行詳細(xì)講解。
關(guān)于動(dòng)態(tài)提供結(jié)點(diǎn)所顯示的字符:首先你在添加結(jié)點(diǎn)時(shí)需要指明lpszItem參數(shù)為:LPSTR_TEXTCALLBACK。在控件顯示該結(jié)點(diǎn)時(shí)會(huì)通過發(fā)送 TVN_GETDISPINFO來取得所需要的字符,在處理該消息時(shí)先將參數(shù)pNMHDR轉(zhuǎn)換為LPNMTVDISPINFO,然后填充其中 item.pszText。但是我們通過什么來知道該結(jié)點(diǎn)所對(duì)應(yīng)的信息呢,我的做法是在添加結(jié)點(diǎn)后設(shè)置其lParam參數(shù),然后在提供信息時(shí)利用該參數(shù)來查找所對(duì)應(yīng)的信息。下面的代碼說明了這種方法:
char szOut[8][3]={"No.1","No.2","No.3"}; //添加結(jié)點(diǎn)
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得到需要顯示的字符在數(shù)組中的位置 *pResult = 0; }
關(guān)于編輯結(jié)點(diǎn)的顯示字符:首先需要設(shè)置樹形控件的TVS_EDITLABELS風(fēng)格,在開始編輯時(shí)該控件將會(huì)發(fā)送 TVN_BEGINLABELEDIT,你可以通過在處理函數(shù)中返回TRUE來取消接下來的編輯,在編輯完成后會(huì)發(fā)送TVN_ENDLABELEDIT,在處理該消息時(shí)需要將參數(shù)pNMHDR轉(zhuǎn)換為 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);//判斷是否已經(jīng)取消取消編輯 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText); //重置顯示字符 *pResult = 0; }
上面講述的方法所進(jìn)行的消息映射必須在父窗口中進(jìn)行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。
1.取得或設(shè)定項(xiàng)目的信息.
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.取得與設(shè)定項(xiàng)目的狀態(tài)
UINT CTreeCtrl::GetItemState(HTREEITEM hItem,UINT sStateMask)const;
BOOL CTree Ctrl::SetItemState(HTREEITEM hItem,UINT nState,UINT nStateMask);
3.取得與設(shè)定項(xiàng)目的圖形
BOOL CTreeCtrl::GetItemImage(HTREEITEM hItem,int& nImage,int& nSelectedImage)const;
BOOL CTreeCtrl::SetItemImage(HTREEITEM hItem,int nImage,int nSelectedImage);
4. 取得與設(shè)定項(xiàng)目的文本
CString CTreeCtrl::GetItemText(HTREEITEM,hItem)const;
BOOL CTreeCtrl::SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);
5. 查詢 CTreeCtrl 中項(xiàng)目的個(gè)數(shù)
UINT CTreeCtrl::GetCount();
6.查詢hItem 的父項(xiàng)目的句柄
HTREEITEM CTreeCtrl::GetparenItem(HTREEITEM hItem);
7.查詢hItem是否有子項(xiàng)
BOOL CTreeCtrl::ItemHasChildren(HTREEITEM hItem);
8.取得hItem 第一個(gè)子項(xiàng)的句柄
HTREEITEM CTreeCtrl::GetChildItem(HTREEITEM hItem);
9.查詢排在hItem前后的兄弟項(xiàng)
HTREEITEM CTreeCtrl::GetPrevSiblingItem(HTREEITEM hItem);
HTREEITEM CTreeCtrl::GetNextSiblingItem(HTREEITEM hItem);
10.取得選中項(xiàng)的句柄 取得根項(xiàng)的句柄
HTREEITEM CTreeCtrl::GetSelectedItem();
HTREEITEM CTreeCtrl::GetRootItem();