c++winapitreeviewcustom-draw

Treeview node with transparent text background instead of default white


I am using custom draw to try and create transparent tree view ( for now I am testing when Visual Styles are enabled ).

My CDDS_PREPAINT handler works fine, tree has parent's background bitmap drawn properly.

I tried to add CDDS_ITEMPREPAINT handler where I use SetBkColor( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT ); and return CDRF_NEWFONT, but that failed. Node is drawn with default white background.

How can I make item's text background transparent?

Thank you.

Best regards.

Below is the illustrative code snippet:

switch( ((LPNMCUSTOMDRAW)lParam)->dwDrawStage  )
{
case CDDS_PREPAINT:
    {
        DrawThemeParentBackground(
            ((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
            ((LPNMCUSTOMDRAW)lParam)->hdc,
            &((LPNMCUSTOMDRAW)lParam)->rc );

        // since tree is in dialog box we need below statement
        SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NOTIFYITEMDRAW );
        return TRUE;

    }
    break;
case CDDS_ITEMPREPAINT :  // how to properly handle this ???
    {   
        SetBkMode( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT );

        SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NEWFONT );
        return TRUE;
    }
    break;
}

Solution

  • Unfortunately, this is not easily possible without drawing the items yourself, sorry.

    It turns out the Tree View Control has traditionally used ExtTextOut() function internally to draw the item titles. This function takes an explicit flags parameter, where value ETO_OPAQUE says that "the current background color should be used to fill the rectangle".

    Because this option is passed as an extra flag and not determined by looking at the current GDI background mode, you can't use SetBkMode() in a custom draw handler to work around this. The background color property of a DC does not support alpha channel either, so it cannot be just set transparent.

    Since Common Controls version 6.0 and themed window decorations, this is a bit different, but still not useful in this case: the control just calls DrawThemeBackground() with the TVP_TREEITEM part and the rest is handled according to the theme being used. I see e.g in the default Aero theme in Windows 8.1 that there is this entry:

    ClassID  | PartID       | StateID      | Property        | Value
    ---------+--------------+--------------+-----------------+--------------
    TreeView | TVP_TREEITEM | TREIS_NORMAL | FILLCOLOR:COLOR | 255, 255, 255
    

    So, what are the alternatives?

    There is always an option to return CDRF_SKIPDEFAULT for the CDDS_ITEMPREPAINT event and do all the display operations yourself. But then you need to take care of drawing even the lines, [+] boxes, selection and focus rectangles and everything else.

    Another option might be to leave the title text stored in the control empty, then add it in CDDS_ITEMPOSTPAINT - i.e. use TVM_GETITEMRECT with wParam=TRUE to get the text rectangle and draw the real text there after everything else has been already painted by the control. But this method fails too, because some tiny opaque rectangle is apparently drawn even for empty text. You'd need to erase that artifact first, only then proceed with drawing the text youself. Coming up with a code which does work for all combinations of item state seemed tricky.