DrawText and Gradients


I create a gradient (one color sweeps into another color) in a static box. That works ok. But when I try to use DrawText to display text across the gradient using SetBkMode TRANSPARENT I still wind up with a solid color arround the area of the text.

How can I display text across a gradient and have the gradient remain intact?


void TextBox::MySetWindowText(char *In)
//save global
      RECT rr;::GetClientRect(m_hWnd,&rr);
      RECT r2;
      r2.left  =rr.left  +LMargin;
      r2.top   =rr.top   +TMargin;
      r2.right =rr.right -RMargin;

            //hard coded values for now      
            int RED=204,GREEN=255,BLUE=253;
      HDC dc=::GetDC(m_hWnd);
      HRGN hrgn=::CreateRectRgn(rr.left,rr.top,rr.right,rr.bottom);
      HRGN hrgnOld=(HRGN)::SelectObject(dc,hrgn);
      HBRUSH hNewBrush;
      HBRUSH hOldBrush=(HBRUSH)::SelectObject(dc,hNewBrush);
      HPEN   hOldPen=(HPEN)::SelectObject(dc,::GetStockObject(NULL_PEN));
      RECT ww;
      ww.top =rr.top;


      else       Rectangle(dc,ww.left,ww.top,ww.right,ww.bottom);

      HPEN hNewPen=::CreatePen(PS_SOLID,1,RGB(0,0,0));

      int Height = -MulDiv(10, GetDeviceCaps(dc, LOGPIXELSY), 72);
      HFONT  hNewFont=::CreateFont(Height,0,0,0,FW_REGULAR,0,0,0,0,0,0,0,0,"");
      HFONT  hOldFont=(HFONT)::SelectObject(dc,hNewFont);


      if(CenterIt==2) DrawText(dc,In,strlen(In),&r2,DT_LEFT);
      if(CenterIt==-1)DrawText(dc,In,strlen(In),&r2,DT_LEFT   | DT_SINGLELINE | DT_VCENTER);
      if(CenterIt==1) DrawText(dc,In,strlen(In),&r2,DT_CENTER | DT_SINGLELINE | DT_VCENTER);
      if(CenterIt==0) DrawText(dc,In,strlen(In),&r2,DT_CENTER | DT_SINGLELINE | DT_TOP);
      //clean up


Who is Participating?
itsmeandnobodyelseConnect With a Mentor Commented:
Maybe you are right with the table of differences of MFC and VC (what i would call native Windows), but there is one difference between WindowsProc and a handler function, that might be important:

WindowsProc immediately will be called by DispatchMessage when the message was caught by the Message Loop. There is only one filtering function before (TranslateMessage). A member function of a CWnd derived class supposed to handle a message will be called at the very end of the chain, e. g. there is the WindowsProc function that you are installing when subclassing the control, the virtual function CWnd::PreTranslateMessage, the Message Map of your control class, ... (maybe some more ...).

So, i would recommend you either to replace the DefaultWindowProc after subclassing by your own Proc (see example above) or at least to overload CWnd::PreTranslateMessage(..) in your textbox class.

Regards, Alex
How do you calculate LMargin, TMargin, RMargin and BMargin?

I tried to include your code in one of my test progs but couldn't get any output (til now);

Regards, Alex

BTW,  you could try to move SetBkMode statement above SelectObject(dc, hNewFont);

RJSoftAuthor Commented:
Hello Alex;

For now the LMargin,TMargin,RMargin and BMargin are all 0. They are for an offset so not to print text near edges of static rectangle.

I tried swapping positions of the SetBkMode but that did not fix things.

I ran across some links about api that does gradients. Thought maybe I could do something with the CreateFont. I saw one example where a Menu's text (caption) is altered to show on left side of window vertically. The modified caption bar used a gradient and from what I could see on the post the only thing different that I could detect was the CreateFont had  CLIP_MASK in one of it's parms. Tried it on mine and it did nothing. Also they had SetBkMode(dc, 1) I dont know what the value of 1 is. I assume TRANSPARENT.

I found the example in code project. I will try to find the link again and post it here.

Any clues apreciated.
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

I failed on a similar problem maybe 10 years ago. It was a progress bar where i tried to correctly draw the background of the centered percent value when the progress color reached the text region.

I'll try - tomorrow - to find code samples where someone had solved this problem (and it can be solved as the progress bar that came with common controls works as required). Maybe a solution of my old problem will help you also.

Regards, Alex
RJSoftAuthor Commented:
Yes that is similar come to think of it. Thanks
RJSoftAuthor Commented:
Any luck with the code Alex?
I found an article but hadn't time til now to check it.

Look at   http://support.microsoft.com/?kbid=174301

Regards, Alex

Ok, i checked it. It is Visual Basic code (grrrrr) but we should be able doing similar in C++ and native WINAPI.

The point is that we have to replace WindowsProc of the text box control to get the WM_CTLCOLOREDIT message and change background color at this time. The VB sample implements a hook by replacing the old WindowsProc handler. The new handler checks WM_CTLCOLOREDIT message and set background to transparent. In any case it calls the previous WindowsProc function after that.

I don't know how you did create the textbox.  Maybe you already have an own WindowsProc function? Then, simply add

     LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             switch (uMsg)
             case WM_CTLCOLOR:
                    SetBkMode((HDC)wParam, TRANSPARENT/*=1*/);
             return DefWindowProc(hwnd, uMsg, wParam, lParam);

If you don't use your own WindowsProc function you have to write one like that:

    LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             if (uMsg == WM_CTLCOLOR)
                    SetBkMode((HDC)wParam, TRANSPARENT/*=1*/);
             return g_pPrevWindowProc(hwnd, uMsg, wParam, lParam);

g_pPrevWindowProc is the old WindowsProce function that you get when installing your own func by calling

      g_pPrevWindowProc = SetWindowLong(hwnd, GWL_WNDPROC, MyWindowProc);

You should do it similar to the VB sample. Hook the MyWindwoProc after creating the main window and unhook it before destroying it. If you are using a class for your main window you may store the previous WindowProc funktion as a data member there rather than using a global variable.

I'll make my own tests as well but it may took me some time till i got my old project running again.

Regards, Alex
RJSoftAuthor Commented:

Thanks much for your help!

Well, so far I could not get what you posted to work. But I did not do exactly as you posted!

All I did was add a message handler for the WM_CTLCOLOR message to my TextBox class as Visual C++ provides this functionality.

I don't see the difference here as the style you propose is simply older MFC code where vs the newer style of MFC-VC++ 6.0.

I am familiar with the older MFC style of coding that you post. (Although I admit a little rusty) Basically you modify the proc where the messages are recieved.

MFC style:
Create and define a class
Create and define a proc
Register the class
Recieve windows messages via the proc
Programmer directs message to functions

VC style:
Create a class.
VC creates Message Map and Data transfer members.
Programmer adds windows message. VC then creates response function.
Programmer edits response function.


All of that aside, I still dont see the difference between setting the dc to transparent previous to to DrawText while doing the text and trying to modify the static or edit class.

I know to paint the background of an edit box you can obtain the WM_CTLCOLOR message and return an HBRUSH so that each instance of that sub class of the edit will be of that color.

But basically all I am doing is subclassing a static and painting in it. Then placing text over the painting. My function is called after WM_PAINT is called.

The problem here seems to be DrawText incapability to create a truley invisible background for the text. When I have a simple solid color then the DrawText does fine.

My code creates the gradiant by using a loop that creates HBRUSHes and selects them and deselects them and destroys them.  

But you would think that SetBkMode would do TRANSPARENT. Also a HBRUSH should not affect choice of HPEN.

To me this is all remenisant of doing images with the wrong pallette. When ever I tried to render an image with an inadaquate palette I would get a blotchy make due color.

So what I believe is that DrawText does not have the capability to fill the transparent area with the gradiant background, so it tries to do the best it can with a close solid brush.

I am also thinking that maybe I should employ masking. But my knowledge of masking is limitted. I know how to create sprite animation by using a bitmap image then making a duplicate of that image with only black and white (AND bitmask). I would fill in by hand the black area and white area.

Where the black of the copy designates what will show up on the real image and the white will be the transparent portion.

So the image is displayed to the screen against any background. Not in a box.

I have seen some code examples (dont remember where) where previous to an image being displayed and AND bitmap was calculated I believe using some normal api. I almost think it was LoadImage with some parameter options provided.. But I forget. The code would then replace the need for creating the AND bitmask by hand.

But this seems much too rediculous. I am hoping that I am totally misunderstanding something of what you posted. I understand that WM_CTLCOLOR message establishes the color of the static and the transparency of the pen for text. But somehow this is not working.

Another thought is that my routine does the gradient paintiing after recieving the WM_PAINT message. So maybe we are talking apples and oranges here. Where you are giving me instruction on how to correct the situation at creation time and I am responding at the painting time.

Maybe I should put the gradient somehow in a creation message response member.
Then all I would have to do is use DrawText with transparent maybe?

Apreciate your insight.

RJSoftAuthor Commented:
Hello Alex;

Well, it was all my screw up. It was nothing to do with SetBkMode directly. I was just calling SetBkMode on the wrong dc.

The SetBkMode to TRANSPARENT works. Did not even have to do hooks or nothing. Just a simple call to SetBkMode before DrawText on the correct dc.

I was doing double buffering so I did all my api calls to a MemDC. (Except I forgot SetBkMode).

The function in the first post was not even being called. The error was in a whole other function....

My bad.

But since you had me looking in the right area you get the points anyway.

Thanks again
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.