Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Setting the font for a windows title bar

Posted on 1998-06-16
7
1,466 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
ID: 1318044
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
ID: 1318045
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
ID: 1318046
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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 2

Expert Comment

by:Belgarat
ID: 1318047
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
ID: 1318048
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
ID: 1318049
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
ID: 1318050
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

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
crystal report check box and wingdings font 7 217
Window placement 17 87
Message not shown 5 67
Way to decrease size of apk file 9 86
This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
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…

856 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