| | |
| | | |
| | | case CDDS_ITEMPREPAINT | CDDS_SUBITEM: |
| | | { |
| | | int row = (int)pCD->nmcd.dwItemSpec; |
| | | int col = pCD->iSubItem; |
| | | const int row = (int)pCD->nmcd.dwItemSpec; |
| | | const int col = pCD->iSubItem; |
| | | CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc); |
| | | |
| | | // 仅在首列绘制展开按钮与缩进引导 |
| | | if (col == 0) { |
| | | CRect rc; |
| | | GetSubItemRect(row, 0, LVIR_BOUNDS, rc); |
| | | |
| | | // 默认文本让系统画:我们先画按钮和缩进背景,再返回 CDRF_DODEFAULT |
| | | if (col == 0) |
| | | { |
| | | CRect rc; GetSubItemRect(row, 0, LVIR_BOUNDS, rc); |
| | | Node* n = GetNodeByVisibleIndex(row); |
| | | if (n) { |
| | | // 绘制展开三角/方块 |
| | | if (!n->children.empty()) { |
| | | CRect box = expanderRectForRow(row); |
| | | // 小方框 |
| | | pDC->Rectangle(box); |
| | | if (!n) { *pResult = CDRF_DODEFAULT; return; } |
| | | |
| | | // 画“+”或“-” |
| | | CPen pen(PS_SOLID, 1, RGB(0, 0, 0)); |
| | | CPen* oldPen = pDC->SelectObject(&pen); |
| | | // 横线 |
| | | pDC->MoveTo(box.left + 2, box.CenterPoint().y); |
| | | pDC->LineTo(box.right - 2, box.CenterPoint().y); |
| | | if (!n->expanded) { |
| | | // 竖线(表示 + 号) |
| | | pDC->MoveTo(box.CenterPoint().x, box.top + 2); |
| | | pDC->LineTo(box.CenterPoint().x, box.bottom - 2); |
| | | } |
| | | pDC->SelectObject(oldPen); |
| | | // 1) 背景/前景颜色:按是否选中 |
| | | const bool selected = (GetItemState(row, LVIS_SELECTED) & LVIS_SELECTED) != 0; |
| | | const bool focusOnCtrl = (GetSafeHwnd() == ::GetFocus()); |
| | | COLORREF bk = selected ? GetSysColor(focusOnCtrl ? COLOR_HIGHLIGHT : COLOR_3DFACE) |
| | | : ListView_GetBkColor(m_hWnd); |
| | | COLORREF txt = selected ? GetSysColor(focusOnCtrl ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT) |
| | | : ListView_GetTextColor(m_hWnd); |
| | | |
| | | // 仅在需要时填充背景(避免“黑一片”) |
| | | CBrush bkBrush(bk); |
| | | pDC->FillRect(rc, &bkBrush); |
| | | |
| | | // 2) 展开/折叠指示 |
| | | if (!n->children.empty()) |
| | | { |
| | | CRect box = expanderRectForRow(row); |
| | | // 画三角(▶/▼),并恢复画笔/画刷 |
| | | HGDIOBJ oldPen = pDC->SelectObject(GetStockObject(BLACK_PEN)); |
| | | HGDIOBJ oldBrush = pDC->SelectObject(GetStockObject(BLACK_BRUSH)); |
| | | POINT tri[3]; |
| | | if (n->expanded) { // ▼ |
| | | tri[0] = { box.left + 2, box.top + 2 }; |
| | | tri[1] = { box.right - 2, box.top + 2 }; |
| | | tri[2] = { box.CenterPoint().x, box.bottom - 2 }; |
| | | } |
| | | |
| | | // 把文本左边界右移,留出缩进与按钮空间 |
| | | // 这里不改系统绘制的文本起点,而是通过在文本前置空格的方式处理更简单: |
| | | // 我们直接改显示文本(性能足够):在 RebuildVisible 时已经填了纯文本。 |
| | | // 如果你要精准控制文本位置,可以改 OWNERDRAW 或自绘文本。 |
| | | else { // ▶ |
| | | tri[0] = { box.left + 2, box.top + 2 }; |
| | | tri[1] = { box.right - 2, box.CenterPoint().y }; |
| | | tri[2] = { box.left + 2, box.bottom - 2 }; |
| | | } |
| | | pDC->Polygon(tri, 3); |
| | | pDC->SelectObject(oldPen); |
| | | pDC->SelectObject(oldBrush); |
| | | } |
| | | |
| | | // 3) 文本:右移避免遮挡 |
| | | const int indentPx = n->level * 16; |
| | | CRect textRc = rc; |
| | | textRc.left = rc.left + m_expanderPadding + indentPx + m_expanderSize + m_textGap; |
| | | |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(txt); |
| | | CString txt0 = n->cols.empty() ? _T("") : n->cols[0]; |
| | | pDC->DrawText(txt0, textRc, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS); |
| | | |
| | | // 首列自绘完毕 |
| | | *pResult = CDRF_SKIPDEFAULT; |
| | | return; |
| | | } |
| | | |
| | | // 其他列默认绘制 |
| | | *pResult = CDRF_DODEFAULT; |
| | | return; |
| | | } |
| | | |
| | | } |
| | | |
| | | *pResult = CDRF_DODEFAULT; |
| | | } |
| | | |
| | | |