Изменение размера окна вызывает размывание возле правой границы
Я создал стандартное приложение Windows Win32 в Visual Studio 2010. Единственное добавление, которое я сделал, - это вызов TextOut в обработчике WM_PAINT, который отображает алфавит (повторяется 4 раза по ширине) в позиции 0, 0.
Моя проблема в том, что когда я изменяю размер окна, расширяясь вправо, возникает некоторая ошибка рисования у правой боковой границы. Черные блоки отображаются во время изменения размера / рисования, как будто правый край растягивается. Результатом является странный черный эффект "смазывания" при изменении размера. Это происходит только во время изменения размера; как только я отпускаю мышь, окно выглядит правильно.
Я пробовал двойную буферизацию на DC памяти, но вижу тот же эффект. Я не использую какой-либо код темы Windows.
Единственный способ удалить эффект - это обработать WM_NCPAINT (и вернуть 0) - но, конечно, это означает, что граница не закрашена, что не будет приемлемым решением! Я упоминаю об этом на случай, если это поможет кому-нибудь с идеей.
Спасибо за любые идеи или помощь!
@Arx - Извини, я не прояснил себя. Когда я говорю, что границы размыты, я имел в виду правый край отображаемого текста, а не саму границу.
Это происходит, если я просто добавлю вызов TextOut в обработчик WM_PAINT. Обработка WM_ERASEBKGRND и установка кисти фона класса окна не имеет значения.
@ Дэвид - Извинения. Я вижу эффект после добавления только одной строки в стандартное приложение Win32 VS 2008, созданное мастером нового проекта - поэтому я не видел смысла в публикации более 200 строк кода с одной интересующей строкой:)
Я добавил эту строку в обработчик WM_PAINT:
TextOut (hdc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ", 104);
Вот полная версия кода с добавленной двойной буферизацией. Размазывание текста с правой стороны (по краю окна) при расширении окна все еще происходит.
// win32_smearing_at_border.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "win32_smearing_at_border.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32_SMEARING_AT_BORDER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32_SMEARING_AT_BORDER));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = 0; //(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static HDC memory_dc;
static HBITMAP memory_bmp;
static HBITMAP oldbmp;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_ERASEBKGND:
return 1;
case WM_CREATE:
// Create memory DC
{
HDC dc = GetDC (hWnd);
memory_dc = CreateCompatibleDC (dc);
memory_bmp = CreateCompatibleBitmap (dc, 2560, 1440); // arbitary values for testing, set to my current monitor size.
oldbmp = (HBITMAP)SelectObject(memory_dc, memory_bmp);
TextOut (memory_dc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",104);
ReleaseDC (hWnd, dc);
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, memory_dc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
// Clean up memory DC
SelectObject (memory_dc,oldbmp);
DeleteObject (memory_bmp);
DeleteDC (memory_dc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Привет аркс
Большое спасибо за попытку кода - я ценю это. Приятно знать, что это работает для вас.
Но... Я испытываю очень странные результаты. У меня проблема с "размыванием" при работе на компьютере с Windows 7 x64. Однако, пробуя это на виртуальной машине Windows 7 (используя VMWare на той же машине), она работает отлично.
Так что на той же машине изначально она размывается, но практически нет. Я даже попробовал виртуальную машину Windows 8, и снова она работала нормально.
Я обнаружил, что если я выберу тему без Aero, все будет работать нормально (хотя без Aero это выглядит не очень хорошо). И все же на других машинах, где он работает, они выбирают темы Aero. Я действительно не понимаю.
Так что это не совсем решение. Я не хочу просить моих потенциальных клиентов отключить Aero.
Я пытался вызвать многие функции Dwm *, пытаясь найти разницу между рабочими и нерабочими машинами, но ничего не смог найти.
Если я вставлю этот код:
DWMNCRENDERINGPOLICY policy = DWMNCRP_DISABLED;
DwmSetWindowAttribute(hWnd,
DWMWA_NCRENDERING_POLICY,
(void*)&policy,
sizeof(DWMNCRENDERINGPOLICY));
Сразу после создания главного окна все снова работает нормально (хотя, опять же, не выглядит так хорошо без границы Aero).
Так что я действительно в растерянности относительно того, как я могу двигаться вперед. Любые идеи с благодарностью принимаются!
1 ответ
Я думаю, что смогу дать более подробное представление о том, откуда происходит это размытие / размытие и почему вы видите это более (или иначе) в Windows 8/10 Aero.
Тот факт, что ваш код имеет:
wcex.style = CS_HREDRAW | CS_VREDRAW;
это причина, почему вы не видели размывания / размытия на Win7. Это заставляет Windows заполнять новые открытые области окна, которые еще не были нарисованы вашим WM_PAINT, сплошным цветом, который не идеален, но не отвлекает.
Но под Windows 8/10 Aero все по-другому. Приложения не рисуют непосредственно на экране, а рисуют в закадровых буферах, которые затем создаются злым оконным менеджером DWM.exe. Оказывается, что DWM фактически добавляет еще один слой BitBlt
поведение поверх существующей устаревшей XP/Vista/7 BitBlt
поведение, на которое влияет CS_HREDRAW | CS_VREDRAW
,
Блиц-поведение DWM еще более сумасшедшее, потому что они не просто копируют клиентскую область, но фактически копируют пиксели по краям вашей старой клиентской области, чтобы создать новую.
К сожалению, заставить DWM не делать блиц намного сложнее, чем просто передать несколько дополнительных флагов.
У меня нет 100% -ного решения, но, пожалуйста, смотрите этот раздел вопросов и ответов для своего рода трюка с синхронизацией, который можно использовать для значительного уменьшения частоты, с которой DWM портится с вашей клиентской областью окна, что уменьшит размытие / размытие:
Наслаждайтесь!