⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 为ctreeview添加背景图.txt

📁 vc使用技巧汇集
💻 TXT
📖 第 1 页 / 共 2 页
字号:
        CBitmap maskBitmap;

        // Create monochrome bitmap for the mask
        maskBitmap.CreateBitmap( rcClient.Width(), rcClient.Height(), 
                        1, 1, NULL );
        maskDC.SelectObject( &maskBitmap );
        memDC.SetBkColor( ::GetSysColor( COLOR_WINDOW ) );

        // Create the mask from the memory DC
        maskDC.BitBlt( 0, 0, rcClient.Width(), rcClient.Height(), &memDC, 
                    rcClient.left, rcClient.top, SRCCOPY );

        
        CDC tempDC;
        tempDC.CreateCompatibleDC(&dc);
        tempDC.SelectObject( &m_bitmap );

        CDC imageDC;
        CBitmap bmpImage;
        imageDC.CreateCompatibleDC( &dc );
        bmpImage.CreateCompatibleBitmap( &dc, rcClient.Width(), 
                        rcClient.Height() );
        imageDC.SelectObject( &bmpImage );

        if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
        {
            dc.SelectPalette( &m_pal, FALSE );
            dc.RealizePalette();

            imageDC.SelectPalette( &m_pal, FALSE );
        }

        // Get x and y offset
        CRect rcRoot;
        GetItemRect( GetRootItem(), rcRoot, FALSE );
        rcRoot.left = -GetScrollPos( SB_HORZ );

        // Draw bitmap in tiled manner to imageDC
        for( int i = rcRoot.left; i < rcClient.right; i += m_cxBitmap )
            for( int j = rcRoot.top; j < rcClient.bottom; j += m_cyBitmap )
                imageDC.BitBlt( i, j, m_cxBitmap, m_cyBitmap, &tempDC, 
                            0, 0, SRCCOPY );

        // Set the background in memDC to black. Using SRCPAINT with black and any other
        // color results in the other color, thus making black the transparent color
        memDC.SetBkColor(RGB(0,0,0));        
        memDC.SetTextColor(RGB(255,255,255));
        memDC.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, 
                rcClip.left, rcClip.top, SRCAND);

        // Set the foreground to black. See comment above.
        imageDC.SetBkColor(RGB(255,255,255));
        imageDC.SetTextColor(RGB(0,0,0));
        imageDC.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, 
                rcClip.left, rcClip.top, SRCAND);

        // Combine the foreground with the background
        imageDC.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), 
                    &memDC, rcClip.left, rcClip.top,SRCPAINT);

        // Draw the final image to the screen        
        dc.BitBlt( rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), 
                    &imageDC, rcClip.left, rcClip.top, SRCCOPY );
    }
    else
    {
        dc.BitBlt( rcClip.left, rcClip.top, rcClip.Width(), 
                rcClip.Height(), &memDC, 
                rcClip.left, rcClip.top, SRCCOPY );
    }
}

Step 5: Handle the scroll messages
The only reason we need to handle the scroll messages is because it helps in reducing the flicker caused by the control update. The default handling the WM_HSCROLL and the WM_VSCROLL messages is that the control is scrolled by the window proc and then the exposed area is invalidated. By calling InvalidateRect() we make sure that the control gets updated only once. 
void CTreeCtrlX::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    if( m_bitmap.m_hObject != NULL )
        InvalidateRect(NULL);
    CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CTreeCtrlX::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    if( m_bitmap.m_hObject != NULL )
        InvalidateRect(NULL);
    CTreeCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

Step 6: Handle TVN_ITEMEXPANDING
We handle the TVN_ITEMEXPANDING message for the same reason that we handle the scroll messages. 
void CTreeCtrlX::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

    if( m_bitmap.m_hObject != NULL )
        InvalidateRect(NULL);
    
    *pResult = 0;
}

Step 7: Add handler for WM_ERASEBKGND
Since we are already drawing the background in the OnPaint() function handling this function and simply returning TRUE ensures that the default window procedure does not erase the background. Adding this handler prevents extra updates to the control's client area and thus reduces flicker. 
BOOL CTreeCtrlX::OnEraseBkgnd(CDC* pDC) 
{
    if( m_bitmap.m_hObject != NULL )
        return TRUE;
    return CTreeCtrl::OnEraseBkgnd(pDC);
}

Step 8: Handle WM_QUERYNEWPALETTE & WM_PALETTECHANGED
The WM_QUERYNEWPALETTE message is sent to a window when it is about to receive input focus. It gives the window an oppurtunity to realize its logical palette so that it can present itself in the best form. The WM_PALETTECHANGED message is sent to a window whenever that system palette is changed. If we do not handle these messages and another application changes the system palette then the colors in our background image will look terrible. Unfortunately both these messages are sent to top level windows. We will deal with that in the next step. 
The OnQueryNewPalette() function first checks whether it needs to reselect the palette. Once it realizes the logical palette it invalidates the window if any of the color were remapped. The OnPaletteChanged() function returns without any further processing if the tree view control itself was responsible for the message because it changed the palette. It then calls OnQueryNewPalette() to rerealize the palette. 

BOOL CTreeCtrlX::OnQueryNewPalette() 
{
    CClientDC dc(this);
    if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
    {
        dc.SelectPalette( &m_pal, FALSE );
        BOOL result = dc.RealizePalette();
        if( result )
            Invalidate();
        return result;
    }
    
    return CTreeCtrl::OnQueryNewPalette();
}

void CTreeCtrlX::OnPaletteChanged(CWnd* pFocusWnd) 
{
    CTreeCtrl::OnPaletteChanged(pFocusWnd);
    
    if( pFocusWnd == this )
        return;

    OnQueryNewPalette();
}

Step 9: Forward palette messages from top level window
As I've already mentioned in the previous step, the WM_QUERYNEWPALETTE & WM_PALETTECHANGED messages are sent only to top level windows. Since the list view control had changed the palette we have to forward these messages to the list view control. I had used a dialog based application to test this so here's what the handlers look like. 
void CTreeViewDlg::OnPaletteChanged(CWnd* pFocusWnd) 
{
    CDialog::OnPaletteChanged(pFocusWnd);
    
    m_tree.SendMessage( WM_PALETTECHANGED, (WPARAM)pFocusWnd->m_hWnd );    
}

BOOL CTreeViewDlg::OnQueryNewPalette() 
{
    CDialog::OnQueryNewPalette();

    return m_tree.SendMessage( WM_QUERYNEWPALETTE );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -