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

  • 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 …

  • 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 …

Most Popular Programming Stories

More for Developers

RSS Feeds