Page 1 of 1

Microsoft : Shaped Windows Rate Topic: -----

#1 Martyn.Rae   User is offline

  • The programming dinosaur
  • member icon

Reputation: 556
  • View blog
  • Posts: 1,436
  • Joined: 22-August 09

Posted 29 July 2017 - 09:58 PM


Windows do not have to be rectangles! They can be any shape you want them to be. This tutorial explains how to draw a circular main window.

The Theory

What the Windows Operating system offers us is the ability to define a shape and then set the window's paint region to ensure that nothing is painted outside the paint region. The window is still a rectangle, but all areas outside that region are transparent. So, we are cheating I hear you say. Well, not exactly, as all functions behave as though the area outside the region we have set for the window does not exist. So setting mouse capture for example will not send a WM_MOUSEMOVE message unless the mouse is inside the defined area. So effectively we have a window of the shape we have defined.

The Code

The code below draws a white circle in the top left hand corner of the screen and gives you the ability to mode it around by clicking in the circle and dragging it around.

#include <Windows.h>

int windowPosX = 0;
int windowPosY = 0;
int mousex;
int mousey;
bool moving;

LRESULT __stdcall mainWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_PAINT:
            PAINTSTRUCT paintStruct;
            HDC hDC = BeginPaint(hWnd, &paintStruct);
            FillRect(hDC, &paintStruct.rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
            EndPaint(hWnd, &paintStruct);
            return 0;
        case WM_LBUTTONDOWN:
            mousex = LOWORD(lParam);
            mousey = HIWORD(lParam);
            moving = true;
            return 0;
        case WM_LBUTTONUP:
            moving = false;
            return 0;
        case WM_MOUSEMOVE:
            if (moving) {
                int new_mousex = LOWORD(lParam);
                int new_mousey = HIWORD(lParam);
                RECT windowRect;
                GetClientRect(hWnd, &windowRect);
                windowPosX += new_mousex - mousex;
                windowPosY += new_mousey - mousey;
                SetWindowPos(hWnd, nullptr, windowPosX, windowPosY, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
                InvalidateRect(hWnd, nullptr, FALSE);
            return 0;
    return DefWindowProc(hWnd, message, wParam, lParam);

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR cmdLine, int cmdShow) {
    WNDCLASS mainWindowClass = { CS_OWNDC, mainWindowProc, 0, 0, hInstance, nullptr, nullptr, nullptr, nullptr, L"WindowClass" };
    HWND hWindowHandle = CreateWindowEx(0, L"WindowClass", L"", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, nullptr, nullptr, hInst, nullptr);
    HRGN hRegion = CreateEllipticRgn(0, 0, 100, 100);
    int cc = SetWindowRgn(hWindowHandle, hRegion, TRUE);
    SetCursor(LoadCursor(nullptr, IDC_ARROW));
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0)) DispatchMessage(&msg);
    return 0;

I am not going to go into any detail about the code within the main window procedure as that is quite standard. Similarly, the majority of the WinMain function is standard. However, the two lines ...

    HRGN hRegion = CreateEllipticRgn(0, 0, 100, 100);
    int cc = SetWindowRgn(hWindowHandle, hRegion, TRUE);

... are not. All they do is create an elliptical region (in this case being as the width and height are the same 100 pixel value, a circle) and set the window region to the created region. Et viola a circular main window.

The way forward from this tutorial is to experiment by creating regions of other shapes and see what results you can achieve!

Is This A Good Question/Topic? 0
  • +

Page 1 of 1