2016-09-27 84 views
5

我想要一個沒有標題欄但帶有可調整大小的框架和陰影的窗口。 這很容易通過刪除WS_CAPTION並添加WS_THICKFRAME來實現,但是,自Windows 10以來,存在一個6px的白色非客戶端區域。創建窗口沒有標題欄,可調整大小的邊框和沒有僞造6px白色條紋

使用下面的代碼我創建一個窗口並用黑色繪製所有客戶區域,窗口獲得左,右和底部6px透明邊距,但是頂部邊距爲白色。

#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); 
} 

呈現: image showing the problem

我怎樣才能去除白條紋? 我還發現這個相關的Qt錯誤報告QTBUG-47543,因爲它可以用win32 api重現,所以它不被Qt問題關閉。

回答

4

這不是一個錯誤。在Windows 10中,左/右/底部的邊界是透明的。頂部邊框不透明。你應該保持原樣。可能沒有人會抱怨。

要更改它,您必須修改非客戶端區域。在Windows Vista及更高版本中這是相當困難的。請參閱Custom Window Frame Using DWM以供參考。

  • 查找邊框厚度

  • 使用DwmExtendFrameIntoClientArea以訪問非客戶區

  • 使用BeginBufferedPaint在非客戶區繪製不透明顏色

的Windows 10例如:

enter image description here

參見兼容性與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; 
} 

對於與Windows Vista/7/8使用這個過程,而不是相容性。這將繪製左/上/下邊框以及上邊框。該窗口將顯示爲一個簡單的矩形,用縮放邊框:

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

您的Win7 compat示例沒有影子周圍的任何方式來獲取一個? –

+1

您可以爲'WNDCLASS'註冊添加'wc.style = CS_DROPSHADOW;'。這爲右側和底側投下陰影。爲了在它周圍添加陰影,必須手動完成,例如使用GDI +。 –

+0

有時我仍然看到白色條紋。捕捉WM_NCACTIVATE修復了大部分情況,但有時當窗口移動得非常快時,它會得到白色條紋。任何其他Windows事件我應該阻止? –

0

只是爲了在這一點擴大;爲了去除白色條紋,只需要從NCCALCSIZE中的第一個矩形中刪除相應的值。 pywin32代碼將是:

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 
相關問題