2017-05-06 331 views
2

我想實現的東西,如Visual Studio安裝確實有邊界的窗口和陰影:邊界的窗口與陰影

screenshot

我嘗試了各種選項,如CS_DROPSHADOW和DWM API,但只要我應用了暗影消失的WS_THICKFRAME風格。

這是我創建和居中的窗口代碼:

RECT R = {0, 0, _clientWidth, _clientHeight}; 
AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false); 
_mainWnd = CreateWindow(L"D3DWndClassName", _mainWndCaption.c_str(), WS_OVERLAPPEDWINDOW, 100, 100, R.right, R.bottom, nullptr, nullptr, _appInst, nullptr); 

if(!_mainWnd){ 
    MessageBox(nullptr, L"CreateWindow FAILED", nullptr, 0); 
    PostQuitMessage(0); 
} 

RECT rc; 

GetWindowRect(_mainWnd, &rc); 

LONG lStyle = GetWindowLong(_mainWnd, GWL_STYLE); 
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); 
SetWindowLong(_mainWnd, GWL_STYLE, lStyle); 


int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right)/2; 
int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom)/2; 

SetWindowPos(_mainWnd, 0, xPos, yPos, _clientWidth, _clientHeight, SWP_NOZORDER); 

ShowWindow(_mainWnd, SW_SHOW); 
UpdateWindow(_mainWnd); 
+0

沒有類樣式'CS_SHADOW'。你真的嘗試過什麼? – IInspectable

+1

對不起,我的意思是CS_DROPSHADOW。它的效果與我作爲例子提供的效果有所不同。 [比較](http://i.imgur.com/2JNOEgj.png) – wajsic

+0

啓動Spy ++工具並檢查想要鏡像的行爲和屬性。 – 2017-05-06 09:37:48

回答

6

可以使用的DwmExtendFrameIntoClientArea()組合和WM_NCCALCSIZE返回0如果wParam爲TRUE產生這種效果。以下詳細步驟。

  • 窗口風格應該是這樣的,通常爲整個框架將顯示(很適合我WS_CAPTION|WS_POPUP作品),但不包括任何的WS_MINIMIZEWS_MAXIMIZEWS_SYSMENU
  • 請致電DwmExtendFrameIntoClientArea()MARGINS{0,0,0,1}。我們並不是真的想要一個透明的框架,所以只設置底部邊距就足夠了。
  • 致電SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)讓系統重新計算NC區域。
  • 如果wParam爲TRUE,則從WM_NCCALCSIZE返回0。這具有將客戶區擴展到窗口大小的效果,包括框架,但不包括陰影。請參閱文檔的備註部分。
  • WM_PAINT畫出你的框架和內容區域,只要你喜歡,但請務必使用不透明的Alpha通道(255值)由DwmExtendFrameIntoClientArea()調用所定義的邊緣區域。否則,在此區域中可以看到常規框架的一部分。您可以使用GDI +,因爲大多數常規GDI函數忽略Alpha通道。 BitBlt()與包含不透明alpha通道的32bpp源位圖同樣適用。
  • 如果你想要一個可調整大小的窗口,你可以處理WM_NCHITTEST

這一切的效果是,你畫「在」常規窗框也就是現在的客戶區域內由於DWM調用,但保持經常開窗陰影。即使您調整窗口大小,也不要擔心「塗滿」不會產生閃爍現象。

您可以將任何標準或用戶定義的控件放入此窗口中。只要確保子控件不會與DwmExtendFrameIntoClientArea()調用定義的邊界重疊,因爲大多數基於GDI的控件都會忽略Alpha通道。

下面是一個最小的,自包含的示例應用程序:

#define WIN32_LEAN_AND_MEAN 
#include <windows.h> 
#include <dwmapi.h> 
#include <unknwn.h> 
#include <gdiplus.h> 
#pragma comment(lib, "dwmapi") 
#pragma comment(lib, "gdiplus") 
namespace gdip = Gdiplus; 

INT_PTR CALLBACK MyDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 
        _In_opt_ HINSTANCE hPrevInstance, 
        _In_ LPWSTR lpCmdLine, 
        _In_ int  nCmdShow) 
{ 
    // Initialize GDI+ 
    gdip::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdipToken = 0; 
    gdip::GdiplusStartup(&gdipToken, &gdiplusStartupInput, nullptr); 

    struct MyDialog : DLGTEMPLATE { 
     WORD dummy[3] = { 0 }; // unused menu, class and title 
    } 
    dlg; 
    dlg.style = WS_POPUP|WS_CAPTION|DS_CENTER; 
    dlg.dwExtendedStyle = 0; 
    dlg.cdit = 0; // no controls in template 
    dlg.x = 0; 
    dlg.y = 0; 
    dlg.cx = 300; // width in dialog units 
    dlg.cy = 200; // height in dialog units 

    DialogBoxIndirectW(hInstance, &dlg, nullptr, MyDialogProc); 

    gdip::GdiplusShutdown(gdipToken); 

    return 0; 
} 

INT_PTR CALLBACK MyDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch(message) 
    { 
     case WM_INITDIALOG: 
     { 
      SetWindowTextW(hDlg, L"Borderless Window with Shadow"); 

      // This plays together with WM_NCALCSIZE. 
      MARGINS m{ 0, 0, 0, 1 }; 
      DwmExtendFrameIntoClientArea(hDlg, &m); 

      // Force the system to recalculate NC area (making it send WM_NCCALCSIZE). 
      SetWindowPos(hDlg, nullptr, 0, 0, 0, 0, 
       SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED); 
      return TRUE; 
     } 
     case WM_NCCALCSIZE: 
     { 
      // Returning 0 from the message when wParam is TRUE removes the standard 
      // frame, but keeps the window shadow. 
      if(wParam == TRUE) 
      { 
       SetWindowLong(hDlg, DWL_MSGRESULT, 0); 
       return TRUE; 
      } 
      return FALSE; 
     } 
     case WM_PAINT: 
     { 
      PAINTSTRUCT ps{ 0 }; 
      HDC hdc = BeginPaint(hDlg, &ps); 

      // Draw with GDI+ to make sure the alpha channel is opaque. 
      gdip::Graphics gfx{ hdc }; 
      gdip::SolidBrush brush{ gdip::Color{ 255, 255, 255 } }; 
      gfx.FillRectangle(&brush, ps.rcPaint.left, ps.rcPaint.top, 
       ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); 

      EndPaint(hDlg, &ps); 
      return TRUE; 
     } 
     case WM_NCHITTEST: 
     { 
      // Returning HTCAPTION allows the user to move the window around by clicking 
      // anywhere. 
      // Depending on the mouse coordinates passed in LPARAM, you may 
      // return other values to enable resizing. 
      SetWindowLong(hDlg, DWL_MSGRESULT, HTCAPTION); 
      return TRUE; 
     } 
     case WM_COMMAND: 
     { 
      WORD id = LOWORD(wParam); 
      if(id == IDOK || id == IDCANCEL) 
      { 
       EndDialog(hDlg, id); 
       return TRUE; 
      } 
      return FALSE; 
     } 
    } 
    return FALSE; // return FALSE to let DefDialogProc handle the message 
} 
+0

非常感謝您的詳細解釋。雖然...我設法畫了一個陰影,但現在我得到這個1px的框架,在我的情況下是綠色的。任何想法如何擺脫? [Image](http://i.imgur.com/Kgcc6Cu.png) – wajsic

+0

@wajsic您是否使用GDI +進行繪製? – zett42

+0

不。我使用的是DirectX – wajsic