Michen
Michen

Reputation: 61

Using TransparentBlt for drawing in MFC

I want do draw a vector of CRect into a device context. The CRects that overlap should add up in a way that the intersection of all turn to a brighter green. Therefore I came up with the following code:

void Grid::tag(CDC* pDC){

    CBrush brushGreen;
    brushGreen.CreateSolidBrush(RGB(0, 100, 0));
    CDC dcMemory;
    dcMemory.SelectObject(&brushGreen);
    dcMemory.CreateCompatibleDC(pDC);
    for (size_t i = 0; i < taglist.size(); i++){
        dcMemory.FillRect(taglist[i], &brushGreen);
        pDC->TransparentBlt(frame.left, frame.top, frame.Width(), frame.Height(), &dcMemory, taglist[i].left, taglist[i].top, taglist[i].Width(), taglist[i].Height(),RGB(0,100,0));
    }
    DeleteObject(brushGreen);

}

Unfortunately, it turns out black. It seems like nothing is drawn into pDC. What am I doing wrong? Is this a valid approach to begin with?

Upvotes: 1

Views: 4197

Answers (2)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

In your example you have to fill memory dc with a transparent color. This will initialize the background color, so to speak. Then draw on memory dc and use TransparentBlt with that transparent color.

void CMyWnd::OnPaint()
{
    CWnd::OnPaint();
    CClientDC dc(this);
    CRect rc;
    GetClientRect(&rc);

    //paint any custom background
    dc.FillSolidRect(&rc, RGB(200,200,255));

    //choose a color which you don't otherwise need, use it for transparency
    COLORREF transparent_color = RGB(1, 1, 1);

    //create memory dc and initialize with transparent_color:
    CDC memdc;
    memdc.CreateCompatibleDC(&dc);
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(&dc, rc.right, rc.bottom);
    memdc.SelectObject(bitmap);
    memdc.FillSolidRect(&rc, transparent_color);

    //start custom drawing on memeory dc:
    CBrush brushGreen;
    brushGreen.CreateSolidBrush(RGB(0, 100, 0));
    CRect small_rc(10, 10, rc.right - 10, 20);
    memdc.FillRect(small_rc, &brushGreen);
    //end custom drawing

    //Finish by copying memeory dc to destination dc:
    dc.TransparentBlt(0, 0, rc.Width(), rc.Height(), 
        &memdc, 0, 0, rc.Width(), rc.Height(), transparent_color);
}

Upvotes: 1

marcinj
marcinj

Reputation: 49986

Instead of TransparentBlt - which does color keying during blt, you can use AlphaBlend, you have also other issues in your code. Below are some fixes, and ideas how to correct your code (I have not tested if this compiles).

CBrush brushGreen;
brushGreen.CreateSolidBrush(RGB(0, 100, 0));
CDC dcMemory;

//SO: what is the use of this? Also before creating DC
//dcMemory.SelectObject(&brushGreen);   
dcMemory.CreateCompatibleDC(pDC);

//SO: for memory DC you need also a bitmap to be selected (dont forget to release it):
HBITMAP hbmp = CreateCompatibleBitmap((HDC)dc, 500, 500);
auto oldDcMemoryBmp = dcMemory.SelectObject(hbmp);

for (size_t i = 0; i < taglist.size(); i++){
    dcMemory.FillRect(taglist[i], &brushGreen);

    // SO: this is not needed
    //pDC->TransparentBlt(frame.left, frame.top, frame.Width(), frame.Height(), &dcMemory, taglist[i].left, taglist[i].top, taglist[i].Width(), taglist[i].Height(),RGB(0,100,0));

    // SO: Instead use albhaBlt
    BLENDFUNCTION BlendFunction;
    BlendFunction.AlphaFormat = AC_SRC_ALPHA;
    BlendFunction.BlendFlags = 0;
    BlendFunction.BlendOp = AC_SRC_OVER;
    BlendFunction.SourceConstantAlpha = 15; // value 0 (transparent) to 255 (opaque)

    dc.AlphaBlend(taglist[i].left, taglist[i].top, taglist[i].Width(), taglist[i].Height(), &dcMemory, 0, 0, taglist[i].Width(), taglist[i].Height(), BlendFunction);
}
//DeleteObject(brushGreen);

Upvotes: 1

Related Questions