Experience summary of ListCtrl in VC++

  • 2020-04-02 03:05:37
  • OfStack

First of all, here, we use m_listctrl to represent a CListCtrl class object, and then here our ListCtrl are all in the form of report, as for the other such as what big icon, small icon temporarily not to talk about, after all, report is the use of popular words. Second, let's use terms 1 and 2 to describe the first and second points, which refer to Effective C++, which I think is COOL :)

Item 1: set the style of ListCtrl

On CSDN you often see people asking how to set the style, they ListCtrl like a list, they have horizontal bar and vertical bar dividing line, and then select a line, to select the whole line, not just one column selected, and so on, here is a more comprehensive setting method.


//Get the original style
DWORD dwStyle = ::GetWindowLong(m_listctrl.m_hWnd, GWL_STYLE); 
dwStyle &= ~(LVS_TYPEMASK);
dwStyle &= ~(LVS_EDITLABELS);
//Set a new style
SetWindowLong(m_listctrl.m_hWnd, GWL_STYLE,dwStyle, |LVS_REPORT | LVS_NOLABELWRAP | LVS_SHOWSELALWAYS);
//Set the extended style
DWORD styles = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES;
ListView_SetExtendedListViewStyleEx(m_listctrl.m_hWnd, styles, styles );

Where LVS_EX_FULLROWSELECT is the entire row selected
LVS_EX_GRIDLINES (listctrl with report style only)
Add a checkbox in front of your lvs_ex_checkbox
PListCtrl - > SetExtendedStyle (m_listctrl GetExtendedStyle () | LVS_EX_SUBITEMIMAGES);
This is also a very important attribute, in this case, you can add ICON in the list, remember the Windows task manager, you want to do that, this attribute also need to add oh, I will talk about this later ~

Clause 2: add column headers

This is a more substantial, to list box respectively, and then add the column head, code, is here


TCHAR rgtsz[2][10] = {_T(" The column header 1"), _T(" The column header 2")};
LV_COLUMN lvcolumn;
CRect rect;
m_listctrl.GetWindowRect(&rect);
for(int i=0;i<2;i++)
{
 lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH | LVCF_ORDER;
 lvcolumn.fmt = LVCFMT_LEFT;
 lvcolumn.pszText = rgtsz[i];
 lvcolumn.iSubItem = i;
 lvcolumn.iOrder = i;
 if(i==0)
 {
    lvcolumn.cx = rect.Width()*3/5 ; 
 }
 else
    lvcolumn.cx = rect.Width()*2/5;
  m_listctrl.InsertColumn(i, &lvcolumn);
}

This is how you insert two columns, you insert 20 columns?? Suit yourself ~ ~
The mask in lvcolumn. Mask can have all kinds of properties. Let's go to MSDN for details.

Item 3: insert the record into the list box


int nIndex = m_listctrl.GetItemCount();
LV_ITEM  lvitemAdd = {0};
lvitemAdd.mask = LVIF_TEXT;
lvitemAdd.iItem = nIndex ;
lvitemAdd.iSubItem = 0;
lvitemAdd.pszText =_T(" maomao 1");;
if (m_listctrl.InsertItem(&lvitemAdd) != -1)
{ 
  LV_ITEM lvitem = {0};
  lvitem.mask = LVIF_TEXT;
  lvitem.iItem = nIndex ;
  lvitem.iSubItem = 1;
  lvitem.pszText =_T(" maomao 2");
  m_listctrl.SetItem(&lvitem);  
}

NIndex is the current number of rows, and then you put the new row at the bottom,

Clause 4: insert an icon into the list

In the report format, you can also insert ICONS

Continue to talk code

M_image is a CImageList object


m_image.Create(16,16, TRUE|ILC_COLOR24, 3, 1);
m_listctrl.SetImageList(&m_image,LVSIL_SMALL);

Then call the CImageList member function int CImageList::Add(HICON HICON);
Insert the ICON into the imagelist,
And then when you insert the record


lvitemAdd.mask = LVIF_TEXT; 
lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE

Then add a lvitemadd. iImage = n;
This n is the serial number in imagelist, indicating which icon is specific, list? Hehe

Clause 5: use additional information when inserting records, use of lParam

Sometimes you want to add some extra information to a row, so you can use this lParam
MSDN is such a description Specifies the 32 - bit value of the item
Last time I added a message to a row, a window handle, and then I added it like this,


int nIndex = m_listctrl.GetItemCount();
LV_ITEM  lvitemAdd = {0};
lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
lvitemAdd.iItem = nIndex ;
lvitemAdd.iSubItem = 0;
lvitemAdd.pszText =_T(" maomao 1");;
lvitemAdd.iImage = n;
lvitemAdd.lParam = (LPARAM)hwnd;( Window handle to a window )
if (m_listctrl.InsertItem(&lvitemAdd) != -1)
{ 
  LV_ITEM lvitem = {0};
  lvitem.mask = LVIF_TEXT;
  lvitem.iItem = nIndex ;
  lvitem.iSubItem = 1;
  lvitem.pszText =_T(" maomao 2");
  m_listctrl.SetItem(&lvitem);  
}

Ok, this is a more complete example, and inserted ICON, and use PARAM

Clause 6: click the list box to get the selected line information

Responding to the NM_CLICK message, if you have MSDN, you can see that there is a special introduction to NM_CLICK of the listview


void CMyDlg::OnItemClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
  // TODO: Add your control notification handler code here
  int nItem = -1;
  LPNMITEMACTIVATE lpNMItemActivate = (LPNMITEMACTIVATE)pNMHDR;
  if(lpNMItemActivate != NULL)
  {
   nItem = lpNMItemActivate->iItem;
  }
}

Now nItem is just clicking on the index of the selected row. With index, is it difficult to get the information of the row
Lazy man say: difficult, because you haven't said, dizzy, that continue to say

Clause 7: get the information of the row according to its index

Go straight to the code


LV_ITEM lvitem = {0};
lvitem.iItem = nIndex;
lvitem.iSubItem = 0;
lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
m_listctrl.GetItem(&lvitem)

So, I'm going to take the information from the first column of nindex, including the ICON we just added, and that extra information (window handle), like if I want to get the window handle, I'm going to HWND = (HWND) lvitem.lparam;
Mask is used to indicate what information you want to get
Specifically, you can check the definition of LVITEM Structure and CListCtrl::GetItem in MSDN

Clause 8: program a line to be selected

Of the selected
M_listctrl. SetItemState (nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
Unselected, unselected
M_listctrl. SetItemState (nIndex. Zero, LVIS_SELECTED | LVIS_FOCUSED);

Clause 9: get all currently selected rows (multiple)

This, I am lazy, copy MSDN code, anyway very simple


// CListCtrl* pListCtrl = (CListCtrl*) GetDlgItem
(IDC_YOURLISTCONTROL);
ASSERT(pListCtrl != NULL);

POSITION pos = pList->GetFirstSelectedItemPosition();
if (pos == NULL)
  TRACE0("No items were selected!n");
else
{
  while (pos)
  {
   int nItem = pList->GetNextSelectedItem(pos);
   TRACE1("Item %d was selected!n", nItem);
   // you could do your own processing on nItem here
  }
}

Clause 10: delete the selected line in clause 9

This is a bit of a hassle compared to the first nine clauses, because if you want to delete more than one line, you tend to make an error. For example, I'm going to delete line 0 and line 1 (the sequence of lines in the list starts at 0)
That's good. I deleted


m_listctrl.DeleteItem(0)
m_listctrl.DeleteItem(1)

Congratulations, no, I'm so happy :)
Because when you delete the 0th line, the bottom line moves up, so the first line becomes the 0th line, so you go to m_listctr.deleteitem (1), and you delete the second line, which is really annoying,
So, it's only safe to delete from the bottom up, first delete, will not affect the operation,


m_listctrl.DeleteItem(1)
m_listctrl.DeleteItem(0)

Sometimes, however, we don't know which lines to delete, only the selected ones, like those in clause 9
If we still use it


POSITION pos = m_listctrl.GetFirstSelectedItemPosition();
if (pos == NULL)
  TRACE0("No items were selected!n");
else
{
  while (pos)
  {
   int nItem = m_listctrl.GetNextSelectedItem(pos);
   m_listctrl.DeleteItem(nItem );

  }
}

Just wait for the body
At this time we'll B4 Microsoft for shrimp without GetLastselectedItemPosition and GetPrevSelectedItem, how to write a member function will die: (
No way, way to think for yourself, here is a stupid way


POSITION sSelPos = NULL;
while(sSelPos = m_listctrl.GetFirstSelectedItemPosition())
{
  int nSelItem = -1;
  nSelItem = m_listctrl.GetNextSelectedItem(sSelPos);
  if(nSelItem >= 0 && nSelItem<m_listctrl.GetItemCount())
  {
   //Ok, so this nSelItem is the DD that we want
  }
}

GetNextSelectedItem This function, 

If you look at the usage of MSDN, it's going to return the index of the first one, and then go to the next selected line, so it's safe to do that, and in practice, I did that, and I passed the test, and it's ok

And, of course, there is a way to get all of the selected rows by GetFirstSelectedItemPosition and GetNextSelectedItem index, then put the index into an array, and then delete from down to up side

Alas true troublesome, also inconstant array, don't say to open with new on the heap, then a vector always want, troublesome, so I temporarily is to use the method above to delete, also for your reference, hope to find a better way.

The above is all the content of this article, I hope you can enjoy it.


Related articles: