Я пытаюсь добиться чего-то похожего на то, что делает установщик 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);
Вы можете создать этот эффект, используя комбинацию DwmExtendFrameIntoClientArea()
и возвращаясь 0
от WM_NCCALCSIZE
если wParam TRUE
, Подробные шаги ниже.
WS_CAPTION|WS_POPUP
хорошо работает для меня), но не включайте WS_MINIMIZE
, WS_MAXIMIZE
, WS_SYSMENU
,DwmExtendFrameIntoClientArea()
с MARGINS{0,0,0,1}
, Нам не нужна прозрачная рамка, поэтому достаточно установить только нижнее поле.SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)
чтобы система пересчитала площадь ЧПУ.WM_NCCALCSIZE
если wParam TRUE
, Это имеет эффект расширение клиентской области до размера окна, включая фрейм, но исключая тень. Смотрите примечания в разделе документации.WM_PAINT
Нарисуйте свой фрейм и область содержимого, как вам нравится, но обязательно используйте непрозрачный альфа-канал (значение 255) для области поля, определенной DwmExtendFrameIntoClientArea()
вызов. В противном случае часть обычного кадра будет видна в этой области. Вы можете использовать GDI + для этого, так как большинство обычных функций GDI игнорируют альфа-канал. BitBlt()
с 32-битным исходным растровым изображением, содержащим непрозрачный альфа-канал, также работает.WM_NCHITTEST
если вы хотите изменить размер окна.Эффект всего этого состоит в том, что вы рисуете «поверх» обычной оконной рамы, которая теперь находится внутри клиентской области из-за вызовов DWM, но держать обычную тень окна. Не волнуйтесь, «закрашивание» не создает мерцания, даже если вы изменяете размер окна.
Вы можете поместить любые стандартные или пользовательские элементы управления в это окно. Просто убедитесь, что дочерние элементы управления не перекрывают поле, определенное DwmExtendFrameIntoClientArea()
вызов, потому что большинство элементов управления на основе GDI игнорируют альфа-канал.
Вот минимальный, автономный пример приложения:
#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
}
Других решений пока нет …