【问题标题】:Which Winapi listview type to use使用哪种 Winapi 列表视图类型
【发布时间】:2016-04-17 09:23:44
【问题描述】:

我需要使用 WINAPI 和 MINGW 创建一个列表视图(不可能使用 MFC、WTF 或任何类型。纯 C/C++ 和 WINAPI),但我不确定哪种列表类型用于最简单的解决方案。

列表视图 items 将被所有者绘制,并且它要求项目与固定的项目宽度对齐。

|-----------------------|
| item1 | item2 | item3 |
|-----------------------|
| item4 | item5 | item6 |
|-----------------------|
| item7 | item8 | item9 |
|-----------------------|

对于最简单的解决方案,我应该使用哪种列表类型:

  • LVS_REPORT 带有所有者绘制的项目和子项目。 (大量自定义消息处理)
  • 具有自定义宽度固定的 LVS_ICON。 (不知道怎么做)
  • LVS_LIST ??
  • ???

那里有任何 win32 编程向导,谁知道我怎样才能在不头痛的情况下完成我的目标?

更新

好的,我明白了。 TLDR;解决方案是从用户单击的位置获取光标位置,然后进行 subitemhittest 并找出用户单击的项目/子项目。然后将该项目/子项目设置为 LVIS_SELECTED。但是你必须要自己绘制列表,因为 windows 本身不支持子项列选择。

感谢 nariujifluter 提供支持提示和技巧。

【问题讨论】:

  • 我只是尝试一下。让用户决定视图。
  • 图标视图将按该顺序列出。所有者绘制版本并不容易。请参阅此帖子以获取提示stackoverflow.com/a/36443401/4603670
  • 您所说的“纯 C/C++”是什么?

标签: c listview winapi


【解决方案1】:

自定义抽奖:
可以更改项目的字体和背景颜色等。
这是 LVS_REPORT 和 LVS_ICON 的功能

DWORD OnPrePaint(int nID, LPNMCUSTOMDRAW lpnmcd) {
    if(lpnmcd->hdr.idFrom == IDC_MY_LISTVIEW)  // my list view's ID
        return CDRF_NOTIFYITEMDRAW;            // custom draw
    else
        return CDRF_DODEFAULT;
}
DWORD OnItemPrePaint(int nID, LPNMCUSTOMDRAW lpnmcd) {
    if(lpnmcd->hdr.idFrom == IDC_MY_LISTVIEW){
        LPNMLVCUSTOMDRAW lpnmlv = (LPNMLVCUSTOMDRAW)lpnmcd;
        if(lpnmcd->dwItemSpec % 2) {            // change color
            lpnmlv->clrText = RGB(255, 255, 255);
            lpnmlv->clrTextBk = RGB(128, 128, 128);
        }
    }
    return CDRF_DODEFAULT;
}

所有者抽签:
必须编写所有绘图代码。
它是一种仅适用于 LVS_REPORT 样式的功能。

void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    int nItem = lpDrawItemStruct->itemID;
    LV_ITEM lvi;
    lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
    lvi.iItem = nItem;
    lvi.iSubItem = 0;
    lvi.stateMask = 0xFFFF;
    GetItem(&lvi);

    // selected item color
    if (lvi.state & LVIS_SELECTED) {
        CBrush cb(::GetSysColor(COLOR_HIGHLIGHT));
        pDC->FillRect(rcItem, &cb);
    }
    else {
        // stripe color
        if (nItem % 2) {
            CBrush cb(::GetSysColor(LTGRAY_BRUSH));
            pDC->FillRect(rcItem, &cb);
        }
    }

    // draw text
    CRect rectText;
    GetItemRect(nItem, rectText, LVIR_LABEL);
    CString strData = GetItemText(nItem, 0);
    pDC->DrawText(strData, rectText, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
}

【讨论】:

  • 关于使每个子项单独可选的任何想法? ownerdrawing 很容易,但我不需要选择行,我需要选择“项目”(项目和子项目)。例如第一行子项 0、第二行子项 3、第一行子项 5 等。
  • 要突出显示单个单元格,请将LVS_EX_FULLROWSELECT 标志添加到列表视图。然后检查光标位置(GetCursorPos)并与单元格的矩形(ListView_GetItemRect)进行比较
【解决方案2】:

阅读有关样式和视图的列表视图文档,您想要的是 LVS_REPORT,即视图样式为您提供行和列。其他视图将根据控件大小调整和重新排列项目。

https://msdn.microsoft.com/en-us/library/windows/desktop/bb774735(v=vs.85).aspx#ListView_Styles_and_Views

【讨论】:

  • 实际上 LVS_REPORT 为您提供项目和子项目,您仍然一次只能选择一行。我需要我的列表可以单独选择所有子项。即Oscar, Tabbie, Female, 175$(我的数据彼此无关,只是一种选择框)
  • 是的,默认情况下它是可选择的子项。通过添加LVS_EX_FULLROWSELECT,您将无法选择单个项目。
猜你喜欢
  • 2015-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 2013-12-19
相关资源
最近更新 更多