'Add texts with line breaks in Win32 API ListView

I am using the WC_LISTVIEW control to create a table that is filled with data at runtime. The table is working fine. However, I cannot display multiple lines in one cell.

Is there a way to use line breaks (e.g. with \n)?

This is how I create the table:

HWND listViewErrors = CreateWindow(WC_LISTVIEW, L"",
    WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT | LVS_SINGLESEL,
    17, 27, errorsRect.Width() - 12, errorsRect.Height() - 25,
    GetWindowHandle(), (HMENU)ID_LIST_ERRORS, NULL, 0);

I add rows like this:

LVITEM lvi = { 0 };

lvi.mask = LVIF_TEXT;
lvi.pszText = L"Label of an entry";

int ret = ListView_InsertItem(hwndList, &lvi); // Main item

if (ret >= 0)
{
    ListView_SetItemText(
            hwndList,
            ret,
            1,
            L"A description containing\nline breaks, but the\nline breaks will be\nignored."); // Sub item
}

return ret;

The result is that the line break character (\n) is not visible anymore, but the text is still in a single line.

enter image description here



Solution 1:[1]

Unless you use custom draw or owner-draw, a LISTVIEW window never supports multi-line entries in report mode.

Even when using use custom draw or owner-draw, all rows will have the same height.

Solution 2:[2]

What @xMRi said is right.

To make WC_LISTVIEW support multi-line text:

  1. you should set it have LVS_OWNERDRAWFIXED style. After this, you could see the ListView's content is invisible, although its header and grid line is visible.

  2. At this time, ListView's parent window will receive WM_MEASUREITEM message. In my test, this message is received only one time. When received it, set the row height like this:

LRESULT DialogMain::OnMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    LPMEASUREITEMSTRUCT lp = (LPMEASUREITEMSTRUCT)lParam;

    //3 times of origin text height
    lp->itemHeight *= 3;

    return 0;
}
  1. When repaint, ListView's parent window will receive WM_DRAWITEM message. Each row is corresponding one message.

In WM_DRAWITEM message, draw the text manually like this:

LRESULT DialogMain::OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;

    if (lpdis->CtlID != IDC_LISTVIEW)
        return 0;

    HDC hdc = lpdis->hDC;
    int index = lpdis->itemID;

    for (int col = 0; col < listView.GetColumnCount(); ++col)
    {
        string s = listView.GetItem(index, col);

        RECT rc = listView.GetGridRect(index, col);

        DrawText(hdc, (LPSTR)s.c_str(), s.length(), &rc, 0);
    }
    return 0;
}

Notice: my method can only make ListView's every row height be fixed.

effect example picture

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cody Gray
Solution 2 Tom Willow