2016-09-27 12 views
5

Tôi muốn cửa sổ không có thanh tiêu đề nhưng có khung và bóng có thể thay đổi kích thước. Điều này có thể dễ dàng đạt được bằng cách loại bỏ WS_CAPTION và thêm WS_THICKFRAME, tuy nhiên, kể từ Windows 10, có một khu vực không phải khách hàng trắng 6px.Tạo cửa sổ không có thanh tiêu đề, với đường viền có thể thay đổi kích cỡ và không có sọc trắng 6px không có thật

Với đoạn mã sau, tôi tạo một cửa sổ và vẽ toàn bộ khu vực máy khách với màu đen, cửa sổ có lề trái trong suốt, bên phải và dưới 6px, tuy nhiên lề trên là màu trắng.

#ifndef UNICODE 
#define UNICODE 
#endif 

#include <windows.h> 

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) 
{ 
    // Register the window class. 
    const wchar_t CLASS_NAME[] = L"Sample Window Class"; 

    WNDCLASS wc = { }; 

    wc.lpfnWndProc = WindowProc; 
    wc.hInstance  = hInstance; 
    wc.lpszClassName = CLASS_NAME; 

    RegisterClass(&wc); 

    // Create the window. 

    HWND hwnd = CreateWindowEx(
     0,        // Optional window styles. 
     CLASS_NAME,      // Window class 
     L"", // Window text 
       0, 
     // Size and position 
     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
     NULL,  // Parent window  
     NULL,  // Menu 
     hInstance, // Instance handle 
     NULL  // Additional application data 
     ); 

    ShowWindow(hwnd, nCmdShow); 

    LONG lStyle = GetWindowLong(hwnd, GWL_STYLE); 
    lStyle |= WS_THICKFRAME; 
    lStyle = lStyle & ~WS_CAPTION; 
    SetWindowLong(hwnd, GWL_STYLE, lStyle); 
    SetWindowPos(hwnd, NULL, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); 

    // Run the message loop. 

    MSG msg = { }; 
    while (GetMessage(&msg, NULL, 0, 0)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    return 0; 
} 

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (uMsg) 
    { 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 

    case WM_PAINT: 
     { 
      PAINTSTRUCT ps; 
      HDC hdc = BeginPaint(hwnd, &ps); 


      // Paint everything black 
      FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOWTEXT)); 
      EndPaint(hwnd, &ps); 
     } 
     return 0; 

    } 
    return DefWindowProc(hwnd, uMsg, wParam, lParam); 
} 

Renders: image showing the problem

Làm thế nào tôi có thể loại bỏ các sọc trắng? Tôi cũng tìm thấy báo cáo lỗi Qt liên quan này QTBUG-47543 đã bị đóng vì không phải là vấn đề Qt, vì nó có thể được sao chép bằng win32 api.

Trả lời

4

Đó không phải là lỗi. Trong Windows 10, các đường viền bên trái/phải/dưới là trong suốt. Đường viền trên không trong suốt. Bạn nên để nó như vậy. Có lẽ không ai phàn nàn.

Để thay đổi, bạn phải sửa đổi khu vực không phải khách hàng. Điều này khá khó khăn trong Windows Vista trở lên. Xem Custom Window Frame Using DWM để tham khảo.

  • dày Find biên giới

  • Sử dụng DwmExtendFrameIntoClientArea để có được quyền truy cập vào khu vực phi-client

  • Sử dụng BeginBufferedPaint để vẽ màu đục trên khu vực phi-client

Windows 10 ví dụ:

enter image description here

(Xem ví dụ tiếp theo để tương thích với 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; 
} 

Đối với khả năng tương thích với Windows Vista/7/8 sử dụng thủ tục này để thay thế. Điều này sẽ vẽ trên trái/trên/dưới biên giới cũng như biên giới hàng đầu. Cửa sổ này sẽ xuất hiện như một hình chữ nhật đơn giản, với biên giới thay đổi kích thước:

enter image description here

//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

Ví dụ tương thích Win7 của bạn không có bóng xung quanh khung, bất kỳ cách nào để có được? –

+1

Bạn có thể thêm đăng ký 'wc.style = CS_DROPSHADOW;' cho 'WNDCLASS'. Điều này giảm bóng cho phía bên phải và phía dưới. Để thêm bóng xung quanh, nó phải được thực hiện thủ công, ví dụ như GDI +. –

+0

Thỉnh thoảng tôi vẫn thấy sọc trắng. Bắt WM_NCACTIVATE sửa chữa hầu hết các lần xuất hiện, nhưng đôi khi khi di chuyển cửa sổ thật nhanh, nó sẽ có sọc trắng. Bất kỳ sự kiện Windows nào khác tôi nên chặn? –

0

Chỉ cần mở rộng về vấn đề này một chút; để loại bỏ sọc trắng chỉ cần loại bỏ các giá trị tương ứng từ rect đầu tiên trong NCCALCSIZE. mã pywin32 sẽ là:

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 
Các vấn đề liên quan