Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / MFC
Article

See through Rich Edit control

Rate me:
Please Sign up or sign in to vote.
4.21/5 (27 votes)
8 Aug 2005CPOL4 min read 84.9K   3.8K   36   8
This article discribes how to give a see through look to your Rich Edit control.

Image 1

Introduction

Giving a rich edit control a background image seems to be impossible, but it is possible to give a rich edit control full transparency so you can see what is drawn on its parent window, this seems to be very helpful. Simply we can make the parent window draw what ever background (any image, any background color, see-thought look, etc) we desire to give the rich edit control the desired look and feel.

Background

I don’t think this control will be of any use to you if you don’t have a picture in the background of your dialog box. I built this controller to enhance a chat application that I’m building. But how does this work? It is really simple. I created a dialog with a Rich Edit control giving the Rich Edit control the Transparency property (that will give the Rich Edit control a fully transparent background) , now we are half way through, all you need to do is draw the background for the Rich Edit control yourself (on its parent window). If you are drawing an image in your dialog background then you must have handled the dialog’s WM_ERASEBKGND message to get your background drawn, here is where you should ask your Rich Edit control to draw its background too. The Rich Edit control takes the HDC of your dialog and a memory DC where you have already drawn your background. The Rich Edit calculates its dimensions and draws itself on the memory DC. Then all you have to do is draw that memory DC on your dialog.

How Does it Work?

First of all, a bitmap is created to keep the background image in the main application dialog so its size should be as big as the dialog it self:

void SemiRichEditDlg::CreateMemoryDC()
{
    HDC hdc = GetDC(m_hWnd);
    m_hMemDC =  CreateCompatibleDC(hdc);
    SelectObject (m_hMemDC, m_hBKbitmap);
    m_hStretchedBitmap = ::CreateCompatibleBitmap(hdc, 
                          WndClintRect.right - WndClintRect.left, 
                          WndClintRect.bottom - WndClintRect.top);
    m_hStretchedMem = CreateCompatibleDC(hdc);
    SelectObject(m_hStretchedMem, m_hStretchedBitmap);
    ReleaseDC(m_hWnd, hdc);
}

This bitmap needs to be deleted and resized whenever the dialog size changes so it would fit the new dialog size (remember to delete the old one or you will run out of memory soon). The new crated bitmap should be the same size as the resized dialog. This is how you handle the sizing message WM_SIZE:

SelectObject(m_hStretchedMem,m_hStretchedBitmapOld);
DeleteObject(m_hStretchedBitmap);
HDC hdc = GetDC(m_hWnd);
m_hStretchedBitmap = ::CreateCompatibleBitmap(hdc,
                      WndClintRect.right - WndClintRect.left,
                      WndClintRect.bottom - WndClintRect.top);
InvalidateRect(m_hWnd, NULL, false);
SelectObject(m_hStretchedMem, m_hStretchedBitmap);
ReleaseDC(m_hWnd, hdc);

You need to select the old bitmap first so that you can delete the currently selected bitmap safely.

Now that we have a bitmap the same size of the dialog all we need to do is draw it on the background of the dialog, but remember before we draw the background we will pass the bitmap to the rich edit control so it would draw its background on the given bitmap. We will handle this in the background erasing of the main dialog.:

int SemiRichEditDlg::OnEraseBkgnd(WPARAM wParam, LPARAM lParam)
{
    HDC hdc = (HDC)wParam;    
    StretchBlt(m_hStretchedMem, 0, 0, WndClintRect.right, 
                      WndClintRect.bottom, m_hMemDC, 0, 0, 
                      m_iBitmapWidth, m_iBitmapHight, SRCCOPY);
    m_semiricheditctrl.DrawBackGround(hdc, m_hStretchedMem);
    BitBlt(hdc, 0, 0, WndClintRect.right - WndClintRect.left, 
                        WndClintRect.bottom - WndClintRect.top, 
                        m_hStretchedMem, 0, 0, SRCCOPY);
    return 1;
}

How Does the Rich Edit draw its Background (Rich Edit to Bitmap)?

Here the rich edit control need to build its custom background on a bitmap then simply copy it to the parent window background image. In windows programming for customizing the behavior of a control we need to subclass the control. This is what we exactly need to customize the rich edit control. All that has to be done is to set the rich edit a new window procedure, this is how it is done. (Remember to keep the original windows procedure)

bool SemiRichEditCtrl::AttachCtrl(HWND hwnd)
{
    m_hWnd = hwnd;
    SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
    OrgCrlProc = (WNDPROC) SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)CtrlProc_);
    GetRectPos(&m_RichEditRect);
    return true;
}

Once this is done the windows messages will go to the new window procedure. Now you can over ride what ever messages you want to customize the control.

Now that we are almost done all we need to draw the background of the rich edit control to a bitmap and then copy it to the main window background(the main bitmap). So we need to create a bitmap the size of the rich edit background

//Creating A DC
HDC hdcTransparent = CreateCompatibleDC(hdc);
//Creating a bitmap
hTransparentBitmap = ::CreateCompatibleBitmap(hdc,
    m_RichEditRect.right - m_RichEditRect.left,
    m_RichEditRect.bottom - m_RichEditRect.top);
//Selecting the bitmap in to the created DC
SelectObject(hdcTransparent, hTransparentBitmap);

My Goal here was to give the rich edit control the see throught look so I will fill the bitmap with white color

//Fill the bitmap with white colour
FloodFill(hdcTransparent, 0, 0,RGB(255,255,255));

Now to give the see-through look we will use the AlphaBlend function to draw the rich edit bitmap to the parent background. If you want to control the transparency modify the BLENDFUNCTION (last parameter passed to the AlphaBlend function)

AlphaBlend(hStretchedMem, m_RichEditRect.left + 1, m_RichEditRect.top + 1,
    m_RichEditRect.right - m_RichEditRect.left,
    m_RichEditRect.bottom - m_RichEditRect.top,
    hdcTransparent, 0, 0, m_RichEditRect.right - m_RichEditRect.left,
    m_RichEditRect.bottom - m_RichEditRect.top, blend);

For now we need the rich edit control to draw it self (content) on the bitmap this will reduce the flickering effect when ever the control is invalidated. The rich edit content is rendered to the bitmap then rendered to the main parent bitmap by using BitBlt with SRCAND as the raster operation code

//Finding the size in twips
nLogPixelsX = ::GetDeviceCaps(hdcTransparent, LOGPIXELSX);
nLogPixelsY = ::GetDeviceCaps(hdcTransparent, LOGPIXELSY);

rc.left = MulDiv(rc.left, 1440, nLogPixelsX);
rc.top = MulDiv(rc.top, 1440, nLogPixelsY);
rc.right = MulDiv(rc.right, 1440, nLogPixelsX);
rc.bottom = MulDiv(rc.bottom, 1440, nLogPixelsY);

fr.hdc = hdcTransparent;
fr.hdcTarget = hdcTransparent;
fr.rc = rc;
fr.rcPage = rc;
fr.chrg.cpMin = SendMessage( m_hWnd, EM_CHARFROMPOS, (WPARAM) FALSE, <BR>                                (LPARAM) &point);
fr.chrg.cpMax = -1;
//Requesting to draw on the DC
lResult = SendMessage( m_hWnd, EM_FORMATRANGE, (WPARAM) TRUE, <BR>                           (LPARAM) &fr);
lResult = SendMessage( m_hWnd, EM_FORMATRANGE, (WPARAM) FALSE, <BR>                           (LPARAM) NULL);
BitBlt (hStretchedMem, m_RichEditRect.left + 1, m_RichEditRect.top + 1,<BR>        m_RichEditRect.right - m_RichEditRect.left, <BR>        m_RichEditRect.bottom - m_RichEditRect.top,
    hdcTransparent, 0, 0,SRCAND);

Known Issues

  • The Rich Edit control doesn't always draw the correct content. This is due to the limitation rendering the contect of rich edit control for a specific device

History

  • Version 1.5 Improved performance, almost no flicking
  • Version 1 of the see through Rich Edit control

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
I love coding with C++. I always split my free time between coding and gaming Smile | :)

Comments and Discussions

 
GeneralVery misleading Pin
kend_ca_200026-Mar-15 10:37
kend_ca_200026-Mar-15 10:37 
GeneralRe: Very misleading Pin
Amro Ibrahim13-May-15 9:42
Amro Ibrahim13-May-15 9:42 
GeneralThe method I use. Pin
Randor 7-Dec-05 13:14
professional Randor 7-Dec-05 13:14 
GeneralRe: The method I use. Pin
Amro Ibrahim12-Dec-05 2:24
Amro Ibrahim12-Dec-05 2:24 
Generalgreat work Pin
kvrnkiran1-Sep-05 3:50
kvrnkiran1-Sep-05 3:50 
GeneralSlow control Pin
_Stilgar_27-Aug-05 10:07
_Stilgar_27-Aug-05 10:07 
GeneralRe: Slow control Pin
Anonymous27-Aug-05 10:28
Anonymous27-Aug-05 10:28 
GeneralRe: Slow control Pin
Amro Ibrahim6-Aug-06 20:27
Amro Ibrahim6-Aug-06 20:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.