[英]Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake
[英]Borderless Window with Drop Shadow
我正在嘗試使用無邊框窗口和投影來實現類似 Visual Studio 安裝程序所做的事情:
我嘗試了各種選項,例如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);
如果 wParam 為TRUE
您可以通過使用DwmExtendFrameIntoClientArea()
和設置0
作為WM_NCCALCSIZE
的消息結果的組合來創建此效果。 詳細步驟如下。
WS_CAPTION|WS_POPUP
對我來說效果很好),但不包括WS_MINIMIZE
、 WS_MAXIMIZE
、 WS_SYSMENU
任何一個。DwmExtendFrameIntoClientArea()
MARGINS{0,0,0,1}
調用DwmExtendFrameIntoClientArea()
。 我們真的不想要一個透明的框架,所以只設置底部邊距就足夠了。SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)
讓系統重新計算NC區域。TRUE
則從WM_NCCALCSIZE
返回 0。 這具有將客戶區擴展到包括 frame 在內的窗口大小的效果,但不包括陰影。 請參閱文檔的備注部分。WM_PAINT
繪制框架和內容區域,但請確保對DwmExtendFrameIntoClientArea()
調用定義的邊距區域使用不透明的 alpha 通道(值為 255)。 否則,該區域中將可見部分常規框架。 您可以為此使用 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:
{
// Setting 0 as the message result 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:
{
// Setting HTCAPTION as the message result allows the user to move
// the window around by clicking anywhere within the window.
// Depending on the mouse coordinates passed in LPARAM, you may
// set 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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.