VC 树控件与列表控件的结合

来源:互联网 发布:字中字软件 编辑:程序博客网 时间:2024/04/29 02:20

前一阵子写个进程管理器玩,其中要用到一个树控件和列表控件结合的控件,犹如VC调试时查看变量的窗口中的列表可以像树一样展开、关闭,感觉很有意思,就写了一个树控件与列表控件结合的类(其中参考了网上的资料)。

该类结合了树控件和列表控件的特点,效果如下图所示

要实现这个功能主要是继承CListCtrl然后重写CListCtrl类中的DrawItem()函数(完整的类文件在我上传的资源中):

void CTreeListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    if (lpDrawItemStruct->CtlType != ODT_LISTVIEW)
        return;
    if(lpDrawItemStruct->itemAction == ODA_FOCUS)
        return ;
    m_nImageWidth = lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top-3;

    LV_ITEM item;
    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    const ITEMINFO *pItemInfo = (ITEMINFO *)lpDrawItemStruct->itemData;
    if (!pDC || !pItemInfo || ((UINT)(pItemInfo->arrText.GetSize()) != GetColumnCount()))
    {
        ASSERT(FALSE);
        return ;
    }
    const int nLeftMargin = GetLeftMargin(pItemInfo);
    const int nCheckBoxLeft = lpDrawItemStruct->rcItem.left+nLeftMargin+(m_nImageWidth+m_nClearance);
    const int nCheckBoxTop = lpDrawItemStruct->rcItem.top+(lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top-m_nImageWidth)/2;
    const BOOL bHasCheckBox = IsHasCheckBox();
    
    RECT rcSubItem;
    UINT nTemp(0);
    POINT potTemp;
    COLORREF crBK, crText;
    TCHAR pText[MAX_PATH];
    
    rcSubItem = lpDrawItemStruct->rcItem;
    rcSubItem.right = rcSubItem.left+GetColumnWidth(0);

    item.mask = LVIF_TEXT|LVIF_STATE;
    item.iItem = lpDrawItemStruct->itemID;
    item.iSubItem =0;
    item.pszText = pText;
    item.cchTextMax = MAX_PATH;
    item.stateMask = 0xFFFF;
    GetItem(&item);

    if (lpDrawItemStruct->itemState & ODS_SELECTED) //当前item被选中
    {
        crBK = GetSysColor(COLOR_HIGHLIGHT);
        crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
    }
    else
    {
        crBK = CListCtrl::GetBkColor();
        crText = CListCtrl::GetTextColor();
    }

    //绘制树节点前的button与lines
    DrawExpandSign(pDC,pItemInfo,rcSubItem);

    //draw checkboxs
    if (bHasCheckBox)
    {
        potTemp.x = nCheckBoxLeft;
        potTemp.y = nCheckBoxTop;
        if ((long)(potTemp.x+m_nImageWidth) <= rcSubItem.right)
        {
            nTemp = item.state&LVIS_STATEIMAGEMASK;
            ASSERT(nTemp);
            if (nTemp)
            {
                nTemp = (nTemp>>12)-1;
                CImageList *pImageList = GetImageList(LVSIL_STATE);
                if (pImageList)
                {
                    pImageList->Draw(pDC, nTemp,potTemp,ILD_TRANSPARENT);                
                }
            }
        }
    }

    //draw image
    if (m_pImageList)
    {
        if (bHasCheckBox)
            potTemp.x = nCheckBoxLeft+(m_nImageWidth+m_nClearance);
        else
            potTemp.x = nCheckBoxLeft;
        potTemp.y = nCheckBoxTop;

        if (pItemInfo->arrPChild.GetSize() < 1)
            item.iImage = pItemInfo->nImage;
        else if (pItemInfo->bExpanded)
            item.iImage = pItemInfo->nExpandedImage;
        else
            item.iImage = pItemInfo->nUnExpandedImage;

        if ((long)(potTemp.x+m_nImageWidth) <= rcSubItem.right)
        {
            //if dragging show a SelectDropTarget alike effect :)
            if(GetItemState(lpDrawItemStruct->itemID,LVIF_STATE) & LVIS_DROPHILITED)
                nTemp = ILD_TRANSPARENT|ILD_BLEND50;
            else
                nTemp = ILD_TRANSPARENT;
            
            ImageList_DrawEx(m_pImageList->m_hImageList
                        , item.iImage
                        , lpDrawItemStruct->hDC
                        , potTemp.x
                        , potTemp.y
                        , m_nImageWidth
                        , m_nImageWidth
                        , CLR_NONE
                        , CLR_NONE
                        , nTemp);
        }
    }

    //--draw text-start-------------//
    pDC->SetBkColor(crBK);
    pDC->SetTextColor(crText);
    rcSubItem.left = nCheckBoxLeft;
    if (bHasCheckBox)
        rcSubItem.left += (m_nImageWidth+m_nClearance);
    if (m_pImageList)
        rcSubItem.left += (m_nImageWidth+m_nClearance);
    pDC->FillSolidRect(&rcSubItem,crBK);
    if (rcSubItem.right-rcSubItem.left > 5)
        pDC->DrawText(item.pszText,&rcSubItem,DT_LEFT|DT_SINGLELINE|DT_VCENTER);

    //draw subitem texts
    LVCOLUMN lvcolumn;
    lvcolumn.mask = LVCF_FMT|LVCF_WIDTH;
    for (UINT i=1; GetColumn(i,&lvcolumn); i++)
    {
        rcSubItem.left = rcSubItem.right;
        rcSubItem.right = rcSubItem.left+lvcolumn.cx;
        pDC->FillSolidRect(&rcSubItem,crBK);
        if ((lvcolumn.cx < 6) || (pItemInfo->arrText[i].GetLength() < 1))
            continue;

        if (lvcolumn.fmt&LVCFMT_CENTER)
            nTemp = DT_SINGLELINE|DT_VCENTER|DT_CENTER;
        else if (lvcolumn.fmt&LVCFMT_RIGHT)
            nTemp = DT_SINGLELINE|DT_VCENTER|DT_RIGHT;
        else
            nTemp = DT_SINGLELINE|DT_VCENTER|DT_LEFT;
        
        rcSubItem.left += 2;
        rcSubItem.right -= 3;
        pDC->DrawText(pItemInfo->arrText[i],&rcSubItem,nTemp);
        rcSubItem.left -= 2;
        rcSubItem.right += 3;
    }
    //--draw text-end---------------//
}