"Win'98 like" Gradient Caption Bar

Environment: The demo project was created with Visual C++ 6.0. In order to run the compiled example (included) you need to have mfc42.lib version 6.0 or better. If you don't have it, you won't be able to run it. You must recompile the project.

This is how the window looks like when it's active.
This is how the window looks like when it's not active.

This article is based upon a previous article written by Brent Corkum called Gradient color caption bar. It brings additional features and fixes some of the problems. I modified the algorithm to display the window caption bar just like Win'98 does and I made it more user friendly. I have tested it in Win'95, Win'98 and WinNT.

Here are the features:
  • You can specify the colors (the beginning and the ending color) of the gradient.
  • Displays a gradient even when the window is inactive.
  • Smoother gradient look.

If you want to implement this gradient bar in your project you probably need to see Brent's article first. If you already have seen his article then all you need to do to is replace the PaintMyCaption() method in your PaintCap.cpp file:

void CCaptionPainter::PaintMyCaption(WPARAM bActive, LPARAM lParam, CString m_strTitle)
if (lParam == 0) {
// lParam = 0 means system setting change: invalidate fonts.

const PAINTCAP& pc = *((PAINTCAP*)lParam);
CDC& dc = *pc.m_pDC;

int cxCap = pc.m_szCaption.cx;
int cyCap = pc.m_szCaption.cy;

COLORREF clrFrom; // the beginning color
COLORREF clrTo; // the ending color

// These are the default colors in Windows(R) 98
// Modify them to suit your needs.
if (bActive) {
// Active caption
clrFrom  = GetSysColor(COLOR_ACTIVECAPTION);
clrTo  = RGB(16, 132, 208);
// Inactive caption
clrTo  = RGB(184, 180, 184);

// Get the intensity values for the ending color
int r1 = GetRValue(clrTo); // red
int g1 = GetGValue(clrTo); // green
int b1 = GetBValue(clrTo); // blue

// Get the intensity values for the begining color
int r2 = GetRValue(clrFrom); // red
int g2 = GetGValue(clrFrom); // green
int b2 = GetBValue(clrFrom); // blue

int x = 5*cxCap/6; // start 5/6 of the way right
int w = x; // width of area to shade
int xDelta= max(w/NCOLORSHADES,1); // width of one shade band

// Paint far right 1/6 of caption the background color
PaintRect(dc, x, 0, cxCap-x, cyCap, clrTo);

int r, g, b;
while (x > xDelta) {
x -= xDelta;
if (r1 > r2)
r = r1 - (r1-r2)*(w-x)/w;
r = r1 + (r2-r1)*(w-x)/w;

if (g1 > g2)
g = g1 - (g1-g2)*(w-x)/w;
g = g1 + (g2-g1)*(w-x)/w;

if (b1 > b2)
b = b1 - (b1-b2)*(w-x)/w;
b = b1 + (b2-b1)*(w-x)/w;

// Paint bands right to left
PaintRect(dc, x, 0, xDelta, cyCap, RGB(r, g, b));

// Paint what's left of the caption with the beginning color
PaintRect(dc, 0, 0, x, cyCap, clrFrom);

// Use caption painter to draw icon and buttons
int cxIcon = DrawIcon(pc);
int cxButns = DrawButtons(pc);

// Now draw text. First Create fonts if needed
if (!m_fontCaption.m_hObject)

CString dt=GetDocTitle();
CString s;

// app title
if(dt.IsEmpty()) s = " " + m_strTitle;
else s = " " + m_strTitle + " - [" + dt + "]";

CRect rc(CPoint(0,0), pc.m_szCaption); // text rectangle
rc.left += cxIcon+2; // start after icon
rc.right -= cxButns; // don't draw past buttons
dc.SetBkMode(TRANSPARENT); // draw on top of our shading

// This is a trial and error value that sets the point
// where the caption background is too light/dark in
// order to display the text with white/black.

if (GetLuminosity(clrFrom) > LUMINOSITY_MARK)

CFont* pOldFont = dc.SelectObject(&m_fontCaption);

// Restore DC

Visit my Internet Pages for updates and other articles.

Download demo project - 36KB

Date Last Updated: March 3, 1999


  • To All Gurus

    Posted by Legacy on 10/09/2001 12:00am

    Originally posted by: Sudip

    Well, Whta the fun in rediscovering the wheel and worse replicating it knowningly (I suppose I stopped short of saying some more). Peep into MSDN and the Guru of all gurus Paul Dilascia has an article 'ShadeCap'-- go through it. Its the best of all NcPaint jobs ppl have done here and there.. 

  • What about an SDI application?

    Posted by Legacy on 04/10/2000 12:00am

    Originally posted by: Jacques Cooper

    Where does the "childframe" code go in an SDI application?
    The problem I am having may be related to the above question. I did not implement the "childframe" code and the minimize, maximize and cancel buttons only appear when I click on the title bar. I am using WinNT 4.0.

  • Problem with multi-threading

    Posted by Legacy on 06/11/1999 12:00am

    Originally posted by: johnnyboy

    I found a strange problem that I'll try and progress, I've just put a very quick fix in. Basically, when my app invokes a viewer, which resides inside a COM object, the message loops appear to get mixed up - OnNcActivate in the CCaptionPainter is called from the other MainFame window. This at the very start of OnNcActivate() and OnNcPaint() solved the problem but it's not the most elegant solution:

    if (m_pWndHooked != AfxGetMainWnd())

  • Working with dialog too?

    Posted by Legacy on 05/12/1999 12:00am

    Originally posted by: Paykan Imani

    This is very good and worked fine.

    I am searching the same but for Dialog.

    How can i change your code to work with Dialog?


  • Small Problem

    Posted by Legacy on 03/04/1999 12:00am

    Originally posted by: Keith Roberts

    This class works great except for one small problem, when the window is active and you right click on the title bar and the system menu is shown, the area surrounding the three buttons on the right reverts to the win98 original colors.

  • Gradient Painting

    Posted by Legacy on 03/04/1999 12:00am

    Originally posted by: Tim Sooter

    Your example clearly demonstrates how to provide a gradient look to a title bar, but what about painting a Cview in the same way. Do you have any examples of this?

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds