Окно без границ с тенью

Я пытаюсь добиться чего-то похожего на то, что делает установщик 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);

3

Решение

Вы можете создать этот эффект, используя комбинацию 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) чтобы система пересчитала площадь ЧПУ.
  • Вернуть 0 из 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
}
7

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector