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

  • While successful mobile apps can elevate and transform your brand, hidden deployment disasters can tear down all your hard work in the blink of an eye. Download this white paper to avoid disasters of: Scale Microdowntime and connectivity Location data Upfront costs

  • Employees must exchange sensitive emails with customers and partners. These emails might contain protected health information, protected financial information, or corporate information that should not be made public. Globalscape® Mail Express® allows you to encrypt the emails that it manages so that no one but the sender and recipient--not even the administrator--can view the contents of the email. "Secure the Transfer of Sensitive Emails" is the property of GlobalSCAPE

Most Popular Programming Stories

More for Developers

RSS Feeds

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