How can I have a multi-line item in a ListControl MFC?

5.1k views Asked by At

I have an MFC List Control in Visual Studio 2013 (C++) with a List of items (Report view)

   LVCOLUMN lvColumn;

        lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
        lvColumn.fmt = LVCFMT_LEFT;
        lvColumn.cx = 120;
        lvColumn.pszText = "Full Name";
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(0, &lvColumn);

        lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
        lvColumn.fmt = LVCFMT_LEFT;
        lvColumn.cx = 75;
        lvColumn.pszText = "Profession";
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(1, &lvColumn);

        lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
        lvColumn.fmt = LVCFMT_LEFT;
        lvColumn.cx = 80;
        lvColumn.pszText = "Fav Sport";
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(2, &lvColumn);

        lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
        lvColumn.fmt = LVCFMT_LEFT;
        lvColumn.cx = 75;
        lvColumn.pszText = "Hobby";
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(3, &lvColumn);

        LVITEM lvItem;
        int nItem;

        lvItem.mask = LVIF_TEXT;
        lvItem.iItem = 0;
        lvItem.iSubItem = 0;
        lvItem.pszText = "Sandra C. Anschwitz";
        nItem = ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertItem(&lvItem);

        ((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 1, "Singer");
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 2, "HandBall");
        ((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 3, "Beach");

How can I have multiline items for Full Name, Profession, Sport and Hobby?

1

There are 1 answers

3
rrirower On

Surprisingly, this is not possible with the default CListCtrl. But, with a little custom coding (and some trickery), you can get the effect you want.

First, you’ll need to derive your own class from CListCtrl and set the owner draw bit (Owner Draw Fixed = true) for the control style. In your parent dialog class, create an image list (here’s the trickery). The image list will be used to specify the height of each row of the list control. In my example below, I used:

m_imagelist.Create(48, 48, ILC_COLOR4, 10, 10);
m_listctrl.SetImageList(&m_imagelist, LVSIL_SMALL);

You’ll need to play around with the cx and cy values for the image list to fit your needs. Your control will use the image list to size each row because it’s anticipating displaying icons. Next, add a handler for DrawItem like this:

void MyClistCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

    CString text = _T("Now is the time \nfor all good men\nto come to the aid");
    pDC->DrawText(text , &lpDrawItemStruct->rcItem, DT_TOP);
    // TODO:  Add your code to draw the specified item
    }

In my example, this results in…

enter image description here

It may not be an elegant solution, but, it works. Note: With this approach, every row will have the same height.

EDIT: There are a few ways to obtain the row text. The easiest would be to use GetItemText like so:

CString txt = GetItemText(lpDrawItemStruct->itemID, 0);
pDC->DrawText(txt, &lpDrawItemStruct->rcItem, DT_TOP);

The above assumes you set the text for each row using one of the CListCtrl methods to set text.