调整窗口大小会导致右边框附近出现涂抹
Resizing Window causes smearing near the right border
我在Visual Studio 2010中创建了一个标准的win32 windows应用程序。我所做的唯一增加的是在WM_PAINT处理程序中显示字母(重复4次宽度)在位置0,0的TextOut调用。
我的问题是,当我调整窗口的大小,向右扩展,有一些绘制错误的右侧边界。在调整大小/绘图过程中显示黑色块,好像右手边正在拉伸。当我调整大小时,结果是一个奇怪的黑色"涂抹"效果。它只在调整大小时发生;一旦我松开鼠标,窗口看起来是正确的。
我已经尝试了双缓冲到内存DC,但看到相同的效果。我不使用任何windows主题代码。
我可以删除效果的唯一方法是处理WM_NCPAINT(并返回0)-但是,当然,这意味着边界不被绘制,这将不是一个可接受的解决方案!我提到它,也许它能帮助任何人有一个想法。
感谢您的任何建议或帮助!
@Arx -对不起,我没有说清楚。当我说边框涂抹时,我指的是显示文本的右手边,而不是边框本身。
如果我只是在WM_PAINT处理程序中添加TextOut调用,它就会发生。处理WM_ERASEBKGRND和设置窗口类背景刷没有区别。
@David -抱歉在新项目向导创建的标准VS 2008 Win32应用程序中只添加一行后,我就看到了效果-所以我不认为只有一行感兴趣的代码发布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;
}
嗨Arx
非常感谢您尝试代码-我很感激。很高兴知道这对你有用。
但是…我正在经历一些非常奇怪的结果。我在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边框看起来不那么好)。
所以我真的不知道该如何前进。任何想法,感谢收到!
我想我可以提供一些更多的见解,关于涂抹/模糊是从哪里来的,为什么你看到它更多(或不同)在Windows 8/10 Aero。
你的代码有:
wcex.style = CS_HREDRAW | CS_VREDRAW;
是你在Win7上看不到涂抹/模糊的原因。这会导致窗口用纯色填充尚未由WM_PAINT绘制的窗口新暴露区域,这不是完美的,但不会分散注意力。
但是在Windows 8/10 Aero下,情况就不同了。应用程序不直接绘制到屏幕上,而是绘制到屏幕外的缓冲区,然后由邪恶的DWM.exe窗口管理器合成。事实证明,DWM实际上在现有的受CS_HREDRAW | CS_VREDRAW
影响的遗留XP/Vista/7 BitBlt
行为之上增加了另一层BitBlt
类型的行为。
DWM blit的行为更疯狂,因为他们不只是复制客户端区域,但他们实际上复制像素的边缘,你的旧客户端区域,使新的。
不幸的是,让DWM不做blit比仅仅传递一些额外的标志要困难得多。
我没有100%的解决方案,但请参阅这个问题& a的一种定时技巧,可以用来大大减少DWM与您的窗口客户端区域混淆的频率,这将减少涂抹/模糊:
如何平滑丑陋的抖动/闪烁/跳跃时调整窗口的大小,特别是拖动左/上边框(Win 7-10;bg、bitbit和DWM)?
享受吧!
- SDL2 调整窗口大小后如何缩放鼠标坐标?
- 如何设置与其背景图像大小相对应的窗口大小?
- 如何防止opengl绘图拉伸到窗口大小?
- 使用 Win32 将 GDI 绘制大小缩放为窗口大小
- 恢复Qt窗口大小和位置问题
- 与WM_DPICHANGED消息一起发送的建议窗口大小太大
- 快板获取当前窗口大小
- 当窗口大小更改时,如何自动缩放QT中的图表
- 尝试在 win 32 中禁用窗口大小调整时,窗口样式行为不一致
- OpenGL纹理闪烁/有时在窗口大小上移动
- QGraphics手动调整窗口大小后场景宽度/高度没有变化
- Qt - 防止在拖动标题栏时调整窗口大小
- 在 Direct2D 绘图中,调整窗口大小后尺寸会更改
- 在窗口大小上绘制的OpenGL消失
- XDG-Shell:如何更改窗口大小
- WinAPI.检查窗口大小调整是否已完成
- Win32 透明全屏仅在窗口大小溢出桌面时才有效
- 如何设置启用setFixize后再次调整主窗口大小
- C ,QT,防止窗口大小大于实际布局高度
- 调整窗口大小会导致右边框附近出现涂抹