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

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Due to internal controls and regulations, the amount of long term archival data is increasing every year. Since magnetic tape does not need to be periodically operated or connected to a power source, there will be no data loss because of performance degradation due to the drive actuator. Read this white paper to learn about a series of tests that determined magnetic tape is a reliable long-term storage solution for up to 30 years.

Most Popular Programming Stories

More for Developers

RSS Feeds