Circular button using BM_SETIMAGE and SetWindowRgn

2019-08-04 06:46发布

I'm attempting to create a circular push button. Here's my process so far:

Create BS_BITMAP style button:

hButton = CreateWindow(L"button",L"Label",WS_CHILD|WS_VISIBLE|BS_BITMAP,
               122,363,65,65,hWnd,(HMENU)BUTTON_ID,NULL,NULL);

Load bitmap with LoadImage. The bitmap is a square, but I only want to display the circle in the center (more on this later):

buttonImage = (HBITMAP)LoadImage(hInstance,L"button.bmp",IMAGE_BITMAP,65,65, 
               LR_LOADFROMFILE|LR_CREATEDIBSECTION);

Set the button's image:

SendMessage(hButton,BM_SETIMAGE,IMAGE_BITMAP,(LPARAM)buttonImage);

In order to display just the circle, I use the following:

hButtonRgn = CreateEllipticRgn(0,0,65,65);
SetWindowRgn(hButton,hButtonRgn,TRUE);

Note that I define hButtonRgn globally and don't use it again, as the MSDN documentation for SetWindowRgn states that "the system owns the region specified by the region handle hRgn".

Here's the problem:

The button initially appears as only a circle. On being clicked and held, though, the full square bitmap appears, with white space surrounding the circle. However, upon release, only the circle appears again.

Here's my attempted solution:

As soon as the button is clicked, repaint the main window around the button. Within the main window's WndProc, then, I do the following:

case WM_PARENTNOTIFY:
    if ((int)wParam == WM_LBUTTONDOWN)
    {
        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);
        pRenderTarget->BeginDraw();
        // paint the background surrounding the button in another function
        pRenderTarget->EndDraw();
        EndPaint(hWnd, &ps);
    }

However, this has no discernible effect. The button appears circular after releasing the mouse, but appears as a square when the mouse is being held down.

Any ideas on where I've gone wrong?

1条回答
叼着烟拽天下
2楼-- · 2019-08-04 07:19

Your redraw routine is incorrect. BeginPaint() should only be used in response to a WM_PAINT message - it tells you that something is dirty and needs repainting. What you want to do is trigger that mechanism, and the way you do that is to use InvalidateRect() to mark the appropriate area of the parent window for redraw.

Even if this does improve things for you I think you'll end up with flickering which will probably be unacceptable. Another mechanism you could investigate is making the button owner draw, because then you can just draw it as a circle (and invalidate the parent window) in the same step.

查看更多
登录 后发表回答