设置ListCtrl的风格
1 在CSDN上常常看到有人问怎么设置风格的,他们ListCtrl的样子是一个列表,有横条和竖条分界线,然后选中一行,要整一行都选中,而不是只有某一列被选中,等等,这里给一个比较全面的设置方法。 2 3 //获得原有风格 4 DWORD dwStyle = ::GetWindowLong(m_listctrl.m_hWnd, GWL_STYLE); 5 dwStyle &= ~(LVS_TYPEMASK); 6 dwStyle &= ~(LVS_EDITLABELS); 7 8 //设置新风格 9 SetWindowLong(m_listctrl.m_hWnd, GWL_STYLE, 10 11 dwStyle,|LVS_REPORT|LVS_NOLABELWRAP|LVS_SHOWSELALWAYS); 12 13 14 //设置扩展风格 15 DWORD styles = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES; 16 17 ListView_SetExtendedListViewStyleEx(m_listctrl.m_hWnd, styles, styles ); 18 19 其中LVS_EX_FULLROWSELECT 就是前面说得整行选中 20 21 LVS_EX_GRIDLINES 网格线(只适用与report风格的listctrl) 22 23 LVS_EX_CHECKBOXES 前面加个checkbox 24 25 pListCtrl->SetExtendedStyle( m_listctrl.GetExtendedStyle() | LVS_EX_SUBITEMIMAGES); 26 27 28 这也是一个很重要的属性,这样的话,可以在列表中加ICON,记得windows的任务管理器吗,你想做得那样,这个属性也要加哦,这个我以后会讲的~ 29 30 条款二:加入列头 31 32 这是一个比较实质的东西,给列表框分列,然后加上列头 33 34 代码说话,来了 35 36 TCHAR rgtsz[2][10] = {_T("列头1"), _T("列头2")}; 37 38 LV_COLUMN lvcolumn; 39 CRect rect; 40 m_listctrl.GetWindowRect(&rect); 41 for(int i=0;i<2;i++) 42 { 43 lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT 44 | LVCF_WIDTH | LVCF_ORDER; 45 lvcolumn.fmt = LVCFMT_LEFT; 46 lvcolumn.pszText = rgtsz[i]; 47 lvcolumn.iSubItem = i; 48 lvcolumn.iOrder = i; 49 if(i==0) 50 { 51 lvcolumn.cx = rect.Width()*3/5 ; 52 } 53 else 54 lvcolumn.cx = rect.Width()*2/5; 55 56 57 m_listctrl.InsertColumn(i, &lvcolumn); 58 } 59 60 这是插入两列的做法,你要插入20列??随便你,依样画葫芦~~ 61 62 lvcolumn.mask 中那个mask可以有各种属性,具体去看msdn吧, 63 64 65 条款三:把记录,插入列表框中 66 67 int nIndex = m_listctrl.GetItemCount(); 68 69 LV_ITEM lvitemAdd = {0}; 70 lvitemAdd.mask = LVIF_TEXT; 71 lvitemAdd.iItem = nIndex ; 72 lvitemAdd.iSubItem = 0; 73 lvitemAdd.pszText =_T("毛毛1");; 74 75 76 if (m_listctrl.InsertItem(&lvitemAdd) != -1) 77 { 78 LV_ITEM lvitem = {0}; 79 lvitem.mask = LVIF_TEXT; 80 lvitem.iItem = nIndex ; 81 lvitem.iSubItem = 1; 82 83 lvitem.pszText =_T("毛毛2"); 84 m_listctrl.SetItem(&lvitem); 85 86 } 87 88 nIndex 是当前的行数,然后把新的一行,插在最下面, 89 90 91 条款四:给列表中插入图标 92 93 在report格式中,也能插入图标 94 95 继续代码说话 96 97 m_image是个CImageList对象 98 99 m_image.Create(16,16, TRUE|ILC_COLOR24, 3, 1); 100 101 m_listctrl.SetImageList(&m_image,LVSIL_SMALL); 102 103 然后调用CImageList的成员函数int CImageList::Add( HICON hIcon ); 104 105 把ICON插入到imagelist, 106 107 然后在插入记录的时候 108 109 lvitemAdd.mask = LVIF_TEXT; -》 lvitemAdd.mask = 110 111 LVIF_TEXT|LVIF_IMAGE 112 113 然后添加一个lvitemAdd.iImage = n; 114 115 这个n是imagelist中的序号,表示是具体的哪一个图标,list么,呵呵 116 117 118 条款五: 插入记录时使用额外的信息,lParam 的使用 119 120 有时候,你想对于某一行,加入一些额外的信息,那么就可以使用这个lParam 121 122 msdn是这么描述的Specifies the 32-bit value of the item 123 124 我上次是为了在某一行加入一个信息,窗口句柄,然后是这么加的, 125 126 int nIndex = m_listctrl.GetItemCount(); 127 128 LV_ITEM lvitemAdd = {0}; 129 lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM; 130 lvitemAdd.iItem = nIndex ; 131 lvitemAdd.iSubItem = 0; 132 lvitemAdd.pszText =_T("毛毛1");; 133 134 lvitemAdd.iImage = n; 135 lvitemAdd.lParam = (LPARAM)hwnd;(某个窗口的窗口句柄) 136 137 138 if (m_listctrl.InsertItem(&lvitemAdd) != -1) 139 { 140 LV_ITEM lvitem = {0}; 141 lvitem.mask = LVIF_TEXT; 142 lvitem.iItem = nIndex ; 143 lvitem.iSubItem = 1; 144 145 lvitem.pszText =_T("毛毛2"); 146 m_listctrl.SetItem(&lvitem); 147 148 } 149 150 ok,这是一个比较全的例子的,又插ICON,又使用PARAM的 151 152 条款六 : 点击列表框,获取选中行信息 153 154 响应NM_CLICK消息,如果你有MSDN,可以看到,有专门关于listview的 155 156 NM_CLICK的介绍 157 158 void CMyDlg::OnItemClick(NMHDR* pNMHDR, LRESULT* pResult) 159 { 160 // TODO: Add your control notification handler code here 161 int nItem = -1; 162 163 LPNMITEMACTIVATE lpNMItemActivate = (LPNMITEMACTIVATE)pNMHDR; 164 165 if(lpNMItemActivate != NULL) 166 { 167 nItem = lpNMItemActivate->iItem; 168 } 169 170 } 171 172 现在nItem就是点击选中那行的index了,有了index,获取那行的信息还难吗 173 174 ? 175 176 懒汉说:难,因为你还没讲,晕,那就继续说 177 178 179 条款七: 根据行的index,获取该行的信息 180 181 直接上代码吧 182 183 LV_ITEM lvitem = {0}; 184 lvitem.iItem = nIndex; 185 lvitem.iSubItem = 0; 186 lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM; 187 188 m_listctrl.GetItem(&lvitem) 189 190 这样,就把nindex,第一列的信息取出来了,包括刚才我们加入的ICON,和那个 191 192 额外信息(窗口句柄), 193 194 比如我要获取窗口句柄,就可以hwnd = (HWND)lvitem.lParam; 195 196 mask 用来指明你想获取那些信息 197 198 具体可以查msdn中LVITEM Structure的定义和CListCtrl::GetItem 199 200 201 条款八:用程序选中某一行,使之选中 202 203 选中之 204 205 m_listctrl.SetItemState 206 207 (nIndex,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED); 208 209 不选中,取消选中之 210 211 m_listctrl.SetItemState(nIndex,0,LVIS_SELECTED|LVIS_FOCUSED); 212 213 214 条款九:获取当前所有选中的行(多选) 215 216 这个,俺就比较懒了,抄msdn的代码吧,反正很简单 217 218 219 220 Example 221 // CListCtrl* pListCtrl = (CListCtrl*) GetDlgItem 222 223 (IDC_YOURLISTCONTROL); 224 ASSERT(pListCtrl != NULL); 225 226 POSITION pos = pList->GetFirstSelectedItemPosition(); 227 if (pos == NULL) 228 TRACE0("No items were selected!\n"); 229 else 230 { 231 while (pos) 232 { 233 int nItem = pList->GetNextSelectedItem(pos); 234 TRACE1("Item %d was selected!\n", nItem); 235 // you could do your own processing on nItem here 236 } 237 } 238 239 240 条款十:删除条款九中选中的行 241 242 这个相对前面九个条款是比较麻烦的,因为如果你要删除多行的话。往往要出错 243 244 比如,我现在要删除第0行和第1行(列表的行序列是从0开始的) 245 246 那么好啊。我来删了 247 248 m_listctrl.DeleteItem(0) 249 250 m_listctrl.DeleteItem(1) 251 252 恭喜你,错了,我好开心啊 :) 253 254 因为你删除第0行以后,下面的行会往上移,那么原来的第1行就变成了第0行,那么你再 m_listctrl.DeleteItem(1),那么删除的是原来的第2行,真麻烦, 255 256 所以,只有从下往上删,才是安全的,先删的,不会影响后面的操作, 257 258 m_listctrl.DeleteItem(1) 259 260 m_listctrl.DeleteItem(0) 261 262 但有时候,我们也不知道要删除哪些行,只知道要删除选中的那些行,像条款九中的那些 263 264 如果我们还是用 265 266 267 268 POSITION pos = m_listctrl.GetFirstSelectedItemPosition(); 269 if (pos == NULL) 270 TRACE0("No items were selected!\n"); 271 else 272 { 273 while (pos) 274 { 275 int nItem = m_listctrl.GetNextSelectedItem(pos); 276 277 278 m_listctrl.DeleteItem(nItem ); 279 280 } 281 } 282 283 你就等着收尸吧 284 285 这时候我们就要B4微软了,为虾米木有GetLastselectedItemPosition 和GetPrevSelectedItem 286 287 多写一对成员函数会死啊 :( 288 289 没办法,办法自己想,这里有个笨办法 290 291 POSITION sSelPos = NULL; 292 293 while(sSelPos = m_listctrl.GetFirstSelectedItemPosition()) 294 { 295 int nSelItem = -1; 296 nSelItem = m_listctrl.GetNextSelectedItem(sSelPos); 297 298 if(nSelItem >= 0 && nSelItem<m_listctrl.GetItemCount()) 299 { 300 301 好了,这个nSelItem 就是我们要的DD 302 303 } 304 305 } 306 307 GetNextSelectedItem这个函数,看msdn的用法,其实是返回第一个的index,然后走到下一个选中的行去,所以这么做也是安全的,在实际中,俺也是这么做的,测试也通过,没问题的 308 309 当然,还有个办法,先通过GetFirstSelectedItemPosition和GetNextSelectedItem 310 311 来获取所有的选中行的index,然后把这些index放到一个数组里,然后再从下往上删 312 313 唉真麻烦啊,还要不定数组,不说用new在堆上开吧,那么一个vector总是要的吧,麻烦啊 314 315 所以我暂时是用上述的办法来删除,也供大家参考,希望能找到更好的办法
よろしく,お願いします!