C++ 在Win32 API ListView中添加带换行符的文本

C++ 在Win32 API ListView中添加带换行符的文本,c++,winapi,C++,Winapi,我正在使用WC_LISTVIEW控件创建一个在运行时填充数据的表。这张桌子很好用。但是,我不能在一个单元格中显示多行 是否有使用换行符的方法(例如使用\n) 以下是我创建表的方式: HWND listViewErrors = CreateWindow(WC_LISTVIEW, L"", WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT | LVS_SINGLESEL, 17, 27, errorsRect.Width() - 12, e

我正在使用WC_LISTVIEW控件创建一个在运行时填充数据的表。这张桌子很好用。但是,我不能在一个单元格中显示多行

是否有使用换行符的方法(例如使用
\n

以下是我创建表的方式:

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);
我添加如下行:

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;
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;
}
结果是换行符(
\n
)不再可见,但文本仍在一行中


只要不使用自定义绘图或ownerdraw,LISTVIEW窗口就永远不支持报表模式下的多行条目


即使使用use custom draw或ownerdraw,所有行都将具有相同的高度。

只要不使用custom draw或ownerdraw,LISTVIEW窗口在报告模式下永远不支持多行条目


即使使用自定义绘图或ownerdraw,所有行的高度也将相同。

@xMRi所说的是正确的

要使WC_LISTVIEW支持多行文本,请执行以下操作:

  • 您应该将其设置为LVS_OWNERDRAWFIXED样式。在此之后,您可以看到ListView的内容是不可见的,尽管它的标题和网格线是可见的

  • 此时,ListView的父窗口将接收WM_MEASUREITEM消息。 在我的测试中,此消息只收到一次。收到时,按如下方式设置行高:

  • 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;
    
    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;
    }
    
  • 重新绘制时,ListView的父窗口将接收WM_DRAWITEM消息。每行对应一条消息
  • 在WM_DRAWITEM消息中,手动绘制文本,如下所示:

    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;
    
    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;
    }
    
    LRESULT DialogMain::OnDrawItem(UINT-uMsg、WPARAM-WPARAM、LPARAM-LPARAM、BOOL&bHandled)
    {
    LPDRAWITEMSTRUCT lpdis=(LPDRAWITEMSTRUCT)LPRAM;
    如果(lpdis->CtlID!=IDC\U列表视图)
    返回0;
    HDC HDC=lpdis->HDC;
    int index=lpdis->itemID;
    对于(int col=0;col
    注意:我的方法只能使ListView的每行高度固定


    @xMRi所说的是对的

    要使WC_LISTVIEW支持多行文本,请执行以下操作:

  • 您应该将其设置为LVS_OWNERDRAWFIXED样式。在此之后,您可以看到ListView的内容是不可见的,尽管它的标题和网格线是可见的

  • 此时,ListView的父窗口将接收WM_MEASUREITEM消息。 在我的测试中,此消息只收到一次。收到时,按如下方式设置行高:

  • 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;
    
    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;
    }
    
  • 重新绘制时,ListView的父窗口将接收WM_DRAWITEM消息。每行对应一条消息
  • 在WM_DRAWITEM消息中,手动绘制文本,如下所示:

    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;
    
    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;
    }
    
    LRESULT DialogMain::OnDrawItem(UINT-uMsg、WPARAM-WPARAM、LPARAM-LPARAM、BOOL&bHandled)
    {
    LPDRAWITEMSTRUCT lpdis=(LPDRAWITEMSTRUCT)LPRAM;
    如果(lpdis->CtlID!=IDC\U列表视图)
    返回0;
    HDC HDC=lpdis->HDC;
    int index=lpdis->itemID;
    对于(int col=0;col
    注意:我的方法只能使ListView的每行高度固定


    按照xMRi的建议,通过所有者抽签来实现这一点可能会很有挑战性。您必须动态计算项目高度,例如,当调整列的大小时,项目高度会发生变化。或者,使用单行文本并设置
    LVS_EX_LABELTIP
    以显示不适合列的文本,作为工具提示(不确定工具提示是否支持换行)。除了工具提示之外,您还可以添加一个只读编辑控件,该控件在选择更改和/或鼠标悬停时始终可见并显示全文。按照xMRi的建议,使用所有者绘制实现这一点可能具有挑战性。您必须动态计算项目高度,例如,当调整列的大小时,项目高度会发生变化。或者,使用单行文本并设置
    LVS_EX_LABELTIP
    以显示不适合列的文本,作为工具提示(不确定工具提示是否支持换行)。除了工具提示,您还可以添加只读编辑控件,该控件在选择更改和/或鼠标悬停时始终可见并显示全文。