设置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 所以我暂时是用上述的办法来删除,也供大家参考,希望能找到更好的办法

 

posted @ 2013-10-29 10:26  陳さん様  阅读(345)  评论(0)    收藏  举报