Create window without titlebar, with resizable border and without bogus 6px white stripe

后端 未结 3 1460
天涯浪人
天涯浪人 2020-12-28 08:35

I want a window without title bar but with resizable frames and shadow. This can easily be achieved by removing WS_CAPTION and adding WS_THICKFRAME, however, since Windows 1

相关标签:
3条回答
  • 2020-12-28 09:29

    Just to expand on this a little; in order to remove the white stripe one just has to remove the corresponding value from the first rect in NCCALCSIZE. pywin32 code would be:

        if msg == WM_NCCALCSIZE:
            if wParam:
                res = CallWindowProc(
                    wndProc, hWnd, msg, wParam, lParam
                )
                sz = NCCALCSIZE_PARAMS.from_address(lParam)
                sz.rgrc[0].top -= 6 # remove 6px top border!
                return res
    
    0 讨论(0)
  • 2020-12-28 09:39

    Change the style of dialog.

    LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
    lStyle |= WS_THICKFRAME; // 6px white stripe cause of this.
    lStyle = lStyle & ~WS_CAPTION;
    
    0 讨论(0)
  • 2020-12-28 09:40

    That's not a bug. In Windows 10 the borders on left/right/bottom are transparent. The top border is not transparent. You should leave it as is. Probably nobody will complain.

    To change it, you must modify the non-client area. This is rather difficult in Windows Vista and above. See Custom Window Frame Using DWM for reference.

    • Find border thickness

    • Use DwmExtendFrameIntoClientArea to get access to non-client area

    • Use BeginBufferedPaint to draw opaque color over non-client area

    Windows 10 example:

    (See the next example for compatibility with Windows Vista, 7, 8)

    //requires Dwmapi.lib and UxTheme.lib
    #include <Windows.h>
    #include <Dwmapi.h>
    
    void my_paint(HDC hdc, RECT rc)
    {
        HBRUSH brush = CreateSolidBrush(RGB(0, 128, 0));
        FillRect(hdc, &rc, brush);
        DeleteObject(brush);
    }
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        static RECT border_thickness;
    
        switch (uMsg)
        {
        case WM_CREATE:
        {
            //find border thickness
            SetRectEmpty(&border_thickness);
            if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME)
            {
                AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
                border_thickness.left *= -1;
                border_thickness.top *= -1;
            }
            else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER)
            {
                SetRect(&border_thickness, 1, 1, 1, 1);
            }
    
            MARGINS margins = { 0 };
            DwmExtendFrameIntoClientArea(hwnd, &margins);
            SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
            break;
        }
    
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
    
            RECT rc = ps.rcPaint;
            BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
            HDC memdc;
            HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, &params, &memdc);
    
            my_paint(memdc, rc);
    
            BufferedPaintSetAlpha(hbuffer, &rc, 255);
            EndBufferedPaint(hbuffer, TRUE);
    
            EndPaint(hwnd, &ps);
            return 0;
        }
    
        case WM_NCACTIVATE:
            return 0;
    
        case WM_NCCALCSIZE:
            if (lParam)
            {
                NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lParam;
                sz->rgrc[0].left += border_thickness.left;
                sz->rgrc[0].right -= border_thickness.right;
                sz->rgrc[0].bottom -= border_thickness.bottom;
                return 0;
            }
            break;
    
        case WM_NCHITTEST:
        {
            //do default processing, but allow resizing from top-border
            LRESULT result = DefWindowProc(hwnd, uMsg, wParam, lParam);
            if (result == HTCLIENT)
            {
                POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                ScreenToClient(hwnd, &pt);
                if (pt.y < border_thickness.top) return HTTOP;
            }
            return result;
        }
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    
        }
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int)
    {
        const wchar_t CLASS_NAME[] = L"Sample Window Class";
    
        WNDCLASS wc = {};
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.lpszClassName = CLASS_NAME;
        RegisterClass(&wc);
    
        CreateWindowEx(0, CLASS_NAME,   NULL,
            WS_VISIBLE | WS_THICKFRAME | WS_POPUP,
            10, 10, 600, 400, NULL, NULL, hInstance, NULL);
    
        MSG msg = {};
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return 0;
    }
    

    For compatibility with Windows Vista/7/8 use this procedure instead. This will paint over left/top/bottom borders as well as top border. This window will appear as a simple rectangle, with resizing borders:

    //for Windows Vista, 7, 8, 10
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        static RECT border_thickness;
    
        switch (uMsg)
        {
        case WM_CREATE:
        {
            //find border thickness
            SetRectEmpty(&border_thickness);
            if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME)
            {
                AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
                border_thickness.left *= -1;
                border_thickness.top *= -1;
            }
            else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER)
            {
                SetRect(&border_thickness, 1, 1, 1, 1);
            }
    
            MARGINS margins = { 0 };
            DwmExtendFrameIntoClientArea(hwnd, &margins);
            SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
            break;
        }
    
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
    
            RECT rc = ps.rcPaint;
            BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
            HDC memdc;
            HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, &params, &memdc);
    
            my_paint(memdc, rc);
    
            BufferedPaintSetAlpha(hbuffer, &rc, 255);
            EndBufferedPaint(hbuffer, TRUE);
    
            EndPaint(hwnd, &ps);
            return 0;
        }
    
        case WM_NCACTIVATE:
            return 0;
    
        case WM_NCCALCSIZE:
            if (lParam)
                return 0;
    
        case WM_NCHITTEST:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ScreenToClient(hwnd, &pt);
            RECT rc;
            GetClientRect(hwnd, &rc);
            enum {left=1, top=2, right=4, bottom=8};
            int hit = 0;
            if (pt.x < border_thickness.left) hit |= left;
            if (pt.x > rc.right - border_thickness.right) hit |= right;
            if (pt.y < border_thickness.top) hit |= top;
            if (pt.y > rc.bottom - border_thickness.bottom) hit |= bottom;
    
            if (hit & top && hit & left) return HTTOPLEFT;
            if (hit & top && hit & right) return HTTOPRIGHT;
            if (hit & bottom && hit & left) return HTBOTTOMLEFT;
            if (hit & bottom && hit & right) return HTBOTTOMRIGHT;
            if (hit & left) return HTLEFT;
            if (hit & top) return HTTOP;
            if (hit & right) return HTRIGHT;
            if (hit & bottom) return HTBOTTOM;
    
            return HTCLIENT;
        }
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    
        }
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    
    0 讨论(0)
提交回复
热议问题