Solved

DrawText and Gradients

Posted on 2004-09-14
10
726 Views
Last Modified: 2008-02-01
Hello;

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?

RJ

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

            //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;
      if(IsFooter)
      hNewBrush=::CreateSolidBrush(RGB(0,0,0));
      else
      hNewBrush=::CreateSolidBrush(RGB(RED,GREEN,BLUE));
      
      
      HBRUSH hOldBrush=(HBRUSH)::SelectObject(dc,hNewBrush);
      HPEN   hOldPen=(HPEN)::SelectObject(dc,::GetStockObject(NULL_PEN));
      
      RECT ww;
      ww.left=rr.left;
      ww.top =rr.top;
      ww.right=rr.right;
      ww.bottom=rr.bottom;
      
      if(!IsFooter)
      {
      while(1)
      {
      Rectangle(dc,ww.left,ww.top,ww.right,ww.bottom);
      
      RED+=10;
      GREEN+=10;
      BLUE+=10;
      if(RED>255)RED=255;
      if(GREEN>255)GREEN=255;
      if(BLUE>255)BLUE=255;

      ::SelectObject(dc,hOldBrush);
      ::DeleteObject(hNewBrush);
      hNewBrush=CreateSolidBrush(RGB(RED,GREEN,BLUE));
      //hOldBrush=(HBRUSH)
      ::SelectObject(dc,hNewBrush);

      ww.left++;
      if(ww.left+10>=ww.right)break;
      }//endwhile
      
      }//endif!IsFooter
      else       Rectangle(dc,ww.left,ww.top,ww.right,ww.bottom);

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

      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);

      ::SetBkMode(dc,TRANSPARENT);

      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
      ::SelectObject(dc,hrgnOld);
      ::SelectObject(dc,hOldFont);
      ::SelectObject(dc,hOldPen);
      ::SelectObject(dc,hOldBrush);
      ::ReleaseDC(m_hWnd,dc);
      ::DeleteObject(hNewBrush);
      ::DeleteObject(hNewPen);
      ::DeleteObject(hNewFont);
      ::DeleteObject(hrgn);

}//endfunc

0
Comment
Question by:RJSoft
  • 5
  • 5
10 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
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);

 
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
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.
RJ
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
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
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Yes that is similar come to think of it. Thanks
RJ
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Any luck with the code Alex?
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
I found an article but hadn't time til now to check it.

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

Regards, Alex




0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
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*/);
                    break;
                  ...
             }
             ....
             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
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Alex.

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.

BUT!

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.

RJ
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 500 total points
Comment Utility
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
 
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
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
RJ
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now