Creating Round SysMenu Buttons

Environment: This control was developed with VC6 and ATL.

-->

I have seen a lot of code on the Internet about round buttons but none on Round SysMenu buttons, so here it is. The code also explains how to do flicker-free painting in the caption and throws light how to do the same in other non-client areas. As usual, I explain a lot.

To handle the painting and message processing on the caption area, you need to handle WM_NCPAINT, WM_LBUTTONUP, and WM_MOUSEMOVE. First of all, I remove the sysmenu while designing the Dialog; then I see the code how to add the WM_NCPAINT, WM_LBUTTONUP, and WM_MOUSEMOVE messages.

In WM_NCPAINT, flicker occurs because, by default, Windows paints blue in the caption area; then over that, you paint red, and when that you-paint-red happens again and again, a flicker is generated.

When a WM_NCPAINT message is generated, the region to be invalidated will be sent in the WPARAM of the MSG structure that contains the WM_NCPAINT. We intercept the message and give Windows a new region to be invalidated and Windows will faithfully use that region invalidates only that region. If you look into the code in the OnNcPaint(..) function, I create a rectangular region that is the whole window minus the caption area (if you return the form there, Windows will not paint the caption area at all).

Then I call DefWindowProc(WM_NCPAINT,(WPARAM)hRgnCaption,NULL) to invalidate all the window except the caption area. Continuing further, I locate the place to put the close button. I create an elliptic region in that area, select that region into the Window DC, and do the following:

dc.SelectClipRgn(&rgnClose);    // paint only in this region
dc.DrawFrameControl(m_rcButClose,DFC_CAPTION,DFCS_CAPTIONCLOSE);
                                    // draw the Close button

Go inside and fill the region with the selected brush (brYellow VARAIBLE). FloodFill will fill the entire region until it meets the RGB(0,0,0) (sent in as a parameter) color that happens to be the color of the cross mark in the Close button.

dc.FloodFill(m_rcButClose.left+2,m_rcButClose.top+5,RGB(0,0,0));

Repeat the same thing for all the other buttons.

If you get too excited and paint the caption area with red you will generate a flicker. At the recently drawn buttons, because again and again you will paint the caption area with red, and again paint the buttons. So this is not a bright idea. Just take care to remove the recently painted areas—the three buttons from the caption area

HRGN hRgnCap = ::CreateRectRgnIndirect(&rb);
  //region = full caption area
HRGN rgnTemp = ::CreateRectRgnIndirect(&rb);


::CombineRgn(rgnTemp,hRgnCap,rgnClose,RGN_DIFF);
  //remove the Close button region
::CombineRgn(rgnTemp,rgnTemp,rgnMin,RGN_DIFF);
  //remove the Minimize button region
::CombineRgn(rgnTemp,rgnTemp,rgnMaxRes,RGN_DIFF);
  //remove the maximize/restore button region
::SelectClipRgn(dc.m_hDC,rgnTemp);
  //Select this region
dc.FillSolidRect(0,0,rc.Width(),22,RGB(255,0,0));
  // now boldly paint the full caption with red.

How to Increase the Non-Client Area

This material was added to update the article.

Some time back, I desperately needed to increase the caption area and the borders usually found in multimedia applications. After some R & D, here it is. The answer is the WM_NCCALCSIZE message; trap this message and shrink the size of the client area. The remaining is the non-client area, the caption, and the borders; hence, you get an increase in the caption and borders. See OnNcCalcSize (..) for how this is done.

But there will be a problem if you have a menu. The menu will appear where it usually appears, so what to do?. We software engineers always have a trick or two up our sleeves in such situations. I take a dialog, append the menu to this dialog, and append the dialog to the main dialog. IDD_MENU_CONTAINER exists on earth solely to serve this purpose.

Note: There is one more trick to make the static textbox show only the text without disturbing the background image. I use SetWindowLong to change the WndProc of the static textbox, where I trap the WM_PAINT and WM_SETTEXT; see the code. Please be aware that there can be a thousand ways to do this and I have one way to do it. I do it because I get to play around with an unseen WndProc.

Downloads

Download main source - 27 Kb
Download source for increasing the non-client areas - 34 Kb


Comments

  • The button is not round

    Posted by scurtu on 11/22/2006 06:13pm

    I run the example given by link above, and the buttons are not round. Yes, it looks like a round button, but it's not. Want to check? Click on one the corners of the button. I tried many times to do this in C++, but I was not able to do, fortunatelly, CBuilder++ does it very simple, only by using CombineRgn(...) and it's really round.

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

Top White Papers and Webcasts

  • Companies undertaking an IT project need to find the right balance between cost and functionality. It's important to start by determining whether to build a solution from scratch, buy an out-of-the-box solution, or a combination of both. In reality, most projects will require some system tailoring to meet business requirements. Decision-makers must understand how much software development is enough and craft a detailed implementation plan to ensure the project's success. This white paper examines the different …

  • On-demand Event Event Date: February 12, 2015 The evolution of systems engineering with the SysML modeling language has resulted in improved requirements specification, better architectural definition, and better hand-off to downstream engineering. Agile methods have proven successful in the software domain, but how can these methods be applied to systems engineering? Check out this webcast and join Bruce Powel Douglass, author of Real-Time Agility, as he discusses how agile methods have had a tremendous …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date