Solved

Setting the font for a windows title bar

Posted on 1998-06-16
7
1,410 Views
Last Modified: 2013-12-02
Is there an easy way to set the font used in a window's title bar.  I do not want to change the overall system properties, just the font in certain windows.  I would prefer to avoid using non-client draw messages.

Any suggestions?
0
Comment
Question by:jstolan
7 Comments
 
LVL 2

Expert Comment

by:Belgarat
Comment Utility
Sorry, it seems that there is not a message/system call that would change font in window's caption. Try sending WM_SETFONT, but I suppose that only standard window classes (controls & dialog boxes) will accept it.
The only way I think about is to handle WM_NCPAINT in your program.
0
 

Expert Comment

by:topol
Comment Utility
I can send you the code, but it's in Visual Basic 5, but it uses API -- so you will easily convert it to C
OK?
0
 
LVL 2

Author Comment

by:jstolan
Comment Utility
To topol

If I can adapt it, I will gladly give you the points.  My E-mail is

jstolan@ossconsulting.com

PS to Belgarat WM_SETFONT doesn't work
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 2

Expert Comment

by:Belgarat
Comment Utility
topol: can you send me your code too ? e-mail is svatopluk.dedic@st.mff.cuni.cz.
Thanks in advance :-)
0
 
LVL 3

Expert Comment

by:shaig
Comment Utility
topol: can you send me your code too ? e-mail is shaig@inter.net.il
Thanks in advance :-)
0
 
LVL 4

Accepted Solution

by:
piano_boxer earned 200 total points
Comment Utility
Here is some MFC code for drawing you own titlebar:
---------------------------------------------------

BOOL g_fDrawFancyCaption = TRUE;

/////////////////
// Paint non-client area: First let Windows paint, then I'll paint over it.
//
// I use the relatively obscure and poorly documented update region feature
// to prevent Windows from painting the title text. This is to get totally
// flicker-free painting when the user sizes the window. Note that Windows
// sometimes uses WPARAM=1.
//

void CMainFrame::OnNcPaint()
{
    if(!g_fDrawFancyCaption)
    {
        CMDIFrameWnd::OnNcPaint();
        return;
    }

    MSG& msg = AfxGetThreadState()->m_lastSentMsg;
    HRGN hRgn = (HRGN)msg.wParam;

    CCaptionRect rc(*this);     // caption rectangle in window coords
    CRect rcWin;                    // window rect
    GetWindowRect(&rcWin);      // .. get window rect
    rc += rcWin.TopLeft();      // convert caption rect to screen coords

    // Don't bother painting if the caption doesn't lie within the region.
    //
    if (msg.wParam > 1 && !::RectInRegion((HRGN)msg.wParam, &rc)) {
        CFrameWnd::OnNcPaint(); // just do default thing
        return;                     // and quit
    }

    // Exclude caption from update region
    //
    HRGN hRgnCaption = ::CreateRectRgnIndirect(&rc);
    HRGN hRgnNew     = ::CreateRectRgnIndirect(&rc);
    if (msg.wParam > 1) {
        // wParam is a valid region: subtract caption from it
        ::CombineRgn(hRgnNew, hRgn, hRgnCaption, RGN_DIFF);
    } else {
        // wParam is not a valid region: create one that's the whole
        // window minus the caption bar
        HRGN hRgnAll = ::CreateRectRgnIndirect(&rcWin);
        CombineRgn(hRgnNew, hRgnAll, hRgnCaption, RGN_DIFF);
        DeleteObject(hRgnAll);
    }

    // Call Windows to do WM_NCPAINT with altered update region
    //
    WPARAM savewp = msg.wParam; // save original wParam
    msg.wParam = (WPARAM)hRgnNew;   // set new region for DefWindowProc
    CFrameWnd::OnNcPaint();         // call it
    DeleteObject(hRgnCaption);      // clean up
    DeleteObject(hRgnNew);          // ...
    msg.wParam = savewp;                // restore original wParam

    PaintCaption();                 // Now paint my special caption
}

BOOL CMainFrame::OnNcActivate(BOOL bActive)
{
    if(!g_fDrawFancyCaption)
        return CMDIFrameWnd::OnNcActivate(bActive);


    // Mimic MFC kludge to stay active if WF_STAYACTIVE bit is on
    //
    if (m_nFlags & WF_STAYACTIVE)
        bActive = TRUE;
    if (!IsWindowEnabled())         // but not if disabled
        bActive = FALSE;

    if (bActive==m_bActive)
        return TRUE;                    // nothing to do

    DefWindowProc(WM_NCACTIVATE, bActive, 0L);

    m_bActive = bActive;        // update state
    SendMessage(WM_NCPAINT);    // paint non-client area (frame too)
   
    return TRUE;                    // done OK
}


void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
    OnSysColorChange();
}

void CMainFrame::OnSysColorChange()
{
    if(!g_fDrawFancyCaption)
    {
        CMDIFrameWnd::OnSysColorChange();
        return;
    }

    m_fontCaption.DeleteObject();   // generate new fonts
    m_rcCaption.SetRectEmpty(); // will force new bitmap to be created
}


//////////////////
// Paint custom caption. Flag tells whether active or not.
// Just blast the bitmap to the title bar, but not iif minimized (iconic).
//
void CMainFrame::PaintCaption(BOOL bActive)
{
    if (!IsIconic())
    {
        CWindowDC dcWin(this);
        CDC dc;
        dc.CreateCompatibleDC(&dcWin);
        CBitmap* pOldBitmap = dc.SelectObject(GetCaptionBitmap(bActive));
        const CRect& rc = m_rcCaption;
        dcWin.BitBlt(rc.left,rc.top,rc.Width(),rc.Height(),&dc,0,0,SRCCOPY);
    }
}

//////////////////
// Helper function to compute the luminosity for an RGB color.
// Measures how bright the color is. I use this so I can draw the caption
// text using the user's chosen color, unless it's too dark. See MSDN for
// definition of luminosity and how to compute it.
//
static int GetLuminosity(COLORREF color)
{
#define HLSMAX 240  // This is what Display Properties uses
#define RGBMAX 255  // max r/g/b value is 255
    int r = GetRValue(color);
    int g = GetGValue(color);
    int b = GetBValue(color);
    int rgbMax = max( max(r,g), b);
    int rgbMin = min( min(r,g), b);
    return (((rgbMax+rgbMin) * HLSMAX) + RGBMAX ) / (2*RGBMAX);
}

#define COLOR_WHITE RGB(255,255,255)
#define COLOR_BLACK RGB(0,0,0)
#define NCOLORSHADES 64     // this many shades in gradient

//////////////////
// Helper to paint rectangle with a color.
//
static void PaintRect(CDC& dc, int x, int y, int w, int h, COLORREF color)
{
    CBrush brush(color);
    CBrush* pOldBrush = dc.SelectObject(&brush);
    dc.PatBlt(x, y, w, h, PATCOPY);
    dc.SelectObject(pOldBrush);
}

//////////////////
// Get the appropriate bitmap whether active/inactive. If the size of
// the caption rect has changed since the last time it was generated,
// generate it again.
//
// This is the function that actually does the shading. It creates a
// bitmap that's used to paint the caption. It looks horrible, but it's
// just a lot of bit-twiddling GDI stuff.
//
CBitmap* CMainFrame::GetCaptionBitmap(BOOL bActive)
{
    CBitmap& bm = m_bmCaption[bActive!=0]; // one of two bitmaps
    CCaptionRect rcCap(*this);                  // caption rectangle in win coords
    if (rcCap != m_rcCaption) {             // if changed since last time:
        m_bmCaption[0].DeleteObject();      // delete both bitmaps,
        m_bmCaption[1].DeleteObject();      // ..they are bad
        m_rcCaption = rcCap;                        // note for next time
    }
   
    if (bm.m_hObject)
        return &bm;                                // already have bitmap; return it.
   
    // Either the size changed or the bitmap was never created. Create it.
    //
    rcCap -= rcCap.TopLeft(); // convert caption rectangle origin to (0,0)
    int w = rcCap.Width();
    int h = rcCap.Height();
    int cxIcon = GetSystemMetrics(SM_CXSIZE);
    int cyIcon = GetSystemMetrics(SM_CYSIZE);

    // Create bitmap same size as caption area and select into memory DC
    //
    CWindowDC dcWin(this);
    CDC dc;
    dc.CreateCompatibleDC(&dcWin);
    bm.DeleteObject();
    bm.CreateCompatibleBitmap(&dcWin, w, h);
    CBitmap* pOldBitmap = dc.SelectObject(&bm);

    // Paint shaded background. Note all painting is into memory DC,
    // not window, so there's no flicker.
    //
    if (!bActive) {
        // Inactive caption: don't do shading, just fill w/bg color
        PaintRect(dc, 0, 0, w, h, GetSysColor(COLOR_INACTIVECAPTION));

    } else {
        // Active caption: do shading
        //
        COLORREF clrBG = GetSysColor(COLOR_ACTIVECAPTION); // background color
        int r = GetRValue(clrBG);               // red..
        int g = GetGValue(clrBG);               // ..green
        int b = GetBValue(clrBG);               // ..blue color vals
        int x = 5*rcCap.right/6;                // start 5/6 of the way right
        int w = x - rcCap.left;                 // 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, rcCap.right-x, h, clrBG);

        // Compute new color brush for each band from x to x + xDelta.
        // Excel uses a linear algorithm from black to normal, i.e.
        //
        //      color = CaptionColor * r
        //
        // where r is the ratio x/w, which ranges from 0 (x=0, left)
        // to 1 (x=w, right). This results in a mostly black title bar,
        // since we humans don't distinguish dark colors as well as light
        // ones. So instead, I use the formula
        //
        //      color = CaptionColor * [1-(1-r)^2]
        //
        // which still equals black when r=0 and CaptionColor when r=1,
        // but spends more time near CaptionColor. For example, when r=.5,
        // the multiplier is [1-(1-.5)^2] = .75, closer to 1 than .5.
        // I leave the algebra to the reader to verify that the above formula
        // is equivalent to
        //
        //      color = CaptionColor - (CaptionColor*(w-x)*(w-x))/(w*w)
        //
        // The computation looks horrendous, but it's only done once each
        // time the caption changes size; thereafter BitBlt'ed to the screen.
        //
        while (x > xDelta) {                        // paint bands right to left
            x -= xDelta;                            // next band
            int wmx2 = (w-x)*(w-x);             // w minus x squared
            int w2  = w*w;                          // w squared
            PaintRect(dc, x, 0, xDelta, h,  
                RGB(r-(r*wmx2)/w2, g-(g*wmx2)/w2, b-(b*wmx2)/w2));
        }

        PaintRect(dc,0,0,x,h,COLOR_BLACK);  // whatever's left ==> black
    }

    // Draw icon and caption buttons.
    // These are all drawn inside a rectangle of dimensions SM_C[XY]SIZE.
    //
    CRect rcButn(0,0,cxIcon,cyIcon);

    // Within the basic button rectangle, Windows 95 uses a 1 or 2 pixel border
    // Icon has 2 pixel border on left, 1 pixel on top/bottom, 0 right
    rcButn.DeflateRect(0,1);
    rcButn.left += 2;
    DrawIconEx(dc.m_hDC, rcButn.left, rcButn.top,
        (HICON)GetClassLong(m_hWnd, GCL_HICONSM),
        rcButn.Width(), rcButn.Height(), 0, NULL, DI_NORMAL);


    // Close box has a 2 pixel border on all sides but left, which is zero
    rcButn.DeflateRect(0,1);                // shrink top/bottom 1 more
    rcButn += CPoint(w-cxIcon-2,0);     // move right
    dc.DrawFrameControl(&rcButn, DFC_CAPTION, DFCS_CAPTIONCLOSE);


    DWORD dwStyle = GetStyle();

    // Max/restore button is like close box; just shift rectangle left
    //
    if (dwStyle & WS_MAXIMIZEBOX) {
        rcButn -= CPoint(cxIcon,0);
        dc.DrawFrameControl(&rcButn, DFC_CAPTION,
            IsZoomed() ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
    }

    // Minimize button has 2 pixel border on all sides but right.
    //
    if (dwStyle & WS_MINIMIZEBOX) {
        rcButn -= CPoint(cxIcon-2,0);
        dc.DrawFrameControl(&rcButn, DFC_CAPTION, DFCS_CAPTIONMIN);
    }


    // Now draw text. First Create fonts if needed
    //
    if (!m_fontCaption.m_hObject)
        CreateFonts();
    CFont* pOldFont = (CFont*)dc.SelectObject(&m_fontCaption);

   
    // Paint "ACME TEXT" using ACME font, always white
    //
    CRect rcText = rcCap;                    // caption rectangle
    rcText.left += cxIcon+2;                 // start after icon
    rcText.right = rcButn.left-2;            // don't draw past buttons
    dc.SetBkMode(TRANSPARENT);



    // Now paint window title (caption)
    //
    if (rcText.right > rcText.left)
    {       // if still room:
        COLORREF clrText;                           // text color
        if (bActive) {
            // Excel always uses white for title color, but I use the user's
            // selected color--unless it's too dark, then I use white.
            //
            clrText = GetSysColor(COLOR_CAPTIONTEXT);
            if (GetLuminosity(clrText) < 90) // good from trial & error
                clrText = COLOR_WHITE;
        } else
            clrText = GetSysColor(COLOR_INACTIVECAPTIONTEXT);

        // Paint the text. Use DT_END_ELLIPSIS to draw ellipsis if text
        // won't fit. Win32 sure is friendly!
        //
        dc.SetTextColor(clrText);
        CString s;
        GetWindowText(s);
        dc.DrawText(s, &rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
    }


    // Restore DC
    dc.SelectObject(pOldFont);
    dc.SelectObject(pOldBitmap);

    return &bm; // return bitmap to caller--whew!
}

//////////////////
// Helper function to build the fonts I need.
//
void CMainFrame::CreateFonts()
{
    // Get current system caption font, just to get its size
    //
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(ncm);
    VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0));
    m_fontCaption.CreateFontIndirect(&ncm.lfCaptionFont);
}

//////////////////
// CCaptionRect: Constructor conputes caption rectangle in window coords.
//
CCaptionRect::CCaptionRect(const CWnd& wnd)
{
    // Get size of frame around window
    DWORD dwStyle = wnd.GetStyle();
    CSize szFrame = (dwStyle & WS_THICKFRAME) ?
        CSize(GetSystemMetrics(SM_CXSIZEFRAME),
               GetSystemMetrics(SM_CYSIZEFRAME)) :
        CSize(GetSystemMetrics(SM_CXFIXEDFRAME),
                GetSystemMetrics(SM_CYFIXEDFRAME));

    int cxIcon = GetSystemMetrics(SM_CXSIZE); // width of caption icon/button

    // Compute rectangle
    wnd.GetWindowRect(this);        // window rect in screen coords
    *this -= CPoint(left, top); // shift origin to (0,0)
    left  += szFrame.cx;                // frame
    right -= szFrame.cx;                // frame
    top   += szFrame.cy;                // top = end of frame
    bottom = top + GetSystemMetrics(SM_CYCAPTION)  // height of caption
        - GetSystemMetrics(SM_CYBORDER);                  // minus gray shadow border
}

LRESULT CMainFrame::OnSetText(WPARAM wParam, LPARAM lParam)
{
    if(!g_fDrawFancyCaption)
        return Default();

    // Turn WS_VISIBLE style off before calling Windows to
    // set the text, then turn it back on again after.
    //
    DWORD dwStyle = GetStyle();
    if (dwStyle & WS_VISIBLE)
        SetWindowLong(m_hWnd, GWL_STYLE, dwStyle & ~ WS_VISIBLE);
    LRESULT lRet = DefWindowProc(WM_SETTEXT, wParam, lParam);
    if (dwStyle & WS_VISIBLE)
        SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);

    m_rcCaption.SetRectEmpty();          // invalidate caption
    SendMessage(WM_NCPAINT);    // paint non-client area (frame too)
    PaintCaption();                          // ..and paint it
    return lRet;
}

0
 
LVL 2

Author Comment

by:jstolan
Comment Utility
Thanks piano_boxer, that's just what I was looking for.  I must admit it was a little more complicated than I thought.  I was able to simplify your sample quite a bit, as all I really needed was to change the font so Kanji characters would be guaranteed to be displayed.

Topol, I got your E-mail.  But in fairness, piano-boxer's example was more appropriate since it was in MFC.  If you would like some points, leave a message here and I will put up a special question for you.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
xyBalance chalenge 58 88
windows 10 how make picture as desktop background 2 47
wordcount challenge 11 72
wordappend challenge 8 83
Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

762 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

8 Experts available now in Live!

Get 1:1 Help Now