调整窗口大小会导致在右边框附近出现污点

调整窗口大小会导致在右边框附近出现污点

本文介绍了调整窗口大小会导致在右边框附近出现污点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在Visual Studio 2010中创建了一个标准的win32 Windows应用程序.我所做的唯一添加就是WM_PAINT处理程序中的TextOut调用,该调用在位置0、0处显示字母(宽度重复4次).

I have created a standard win32 windows application in Visual Studio 2010. The only addition I have made is a TextOut call in the WM_PAINT handler that displays the alphabet (repeated 4 times for width) at position 0, 0.

我的问题是,当我调整窗口大小,向右扩展时,右侧边框有一些绘制错误.在调整大小/绘制过程中显示黑色块,就像右边缘被拉伸一样.当我调整大小时,结果是奇怪的黑色拖尾"效果.它仅在调整大小时发生;释放鼠标后,窗口看起来正确.

My problem is that when I resize the window, expanding to the right, there is some drawing error by the right side border. Black blocks are shown during the resizing/drawing process as if the right hand edge is being stretched. The result is a strange black "smearing" effect as I resize. It only happens during the resize; once I release the mouse, the window looks correct.

我曾尝试对内存DC进行双缓冲,但效果相同.我没有使用任何Windows主题代码.

I have tried double buffering to a memory DC, but see the same effect. I am not using any windows themes code.

我要删除效果的唯一方法是处理WM_NCPAINT(并返回0)–但是,当然,这意味着没有绘制边框,这是不可接受的解决方案!我提到它是为了防止它对任何人有所帮助.

The only way I can remove the effect is to handle WM_NCPAINT (and return 0) – but, of course, this means the border isn’t painted which won’t be an acceptable solution! I mention it in case it helps anybody with an idea.

@Arx –对不起,我没有说清楚.当我说边界涂抹时,我指的是显示的文本的右边缘,而不是边界本身.

@Arx – Sorry, I hadn’t made myself clear. When I say the borders smear, I meant the right hand edge of the displayed text, not the border itself.

如果我只是在WM_PAINT处理程序中添加TextOut调用,就会发生这种情况.处理WM_ERASEBKGRND并设置窗口类背景画笔没有什么区别.

It happens if I just add the TextOut call in the WM_PAINT handler. Handling WM_ERASEBKGRND and setting the window class background brush makes no difference.

@David –道歉.在新项目向导创建的标准VS 2008 Win32应用程序中仅添加了一行之后,我看到了效果–因此,我看不到只用一行感兴趣的内容发布200余行代码的意义:)

@David – Apologies. I see the effect after adding only one line to the standard VS 2008 Win32 application created by the new project wizard – so I didn’t see the point in posting 200+ lines of code with only one line of interest :)

我将此行添加到WM_PAINT处理程序中:

I added this line to the WM_PAINT handler:

TextOut (hdc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ", 104);

这是代码的完整版本,其中添加了双缓冲.当窗口扩展时,仍会在右侧(窗口边缘)涂抹文本.

Here is the full version of the code with double buffering added. The smearing of the text on the right hand side (by the window edge) as the window is expanded still occurs.

// 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


Hi Arx

非常感谢您试用代码-非常感谢.很高兴知道它为您工作.

Many thanks for trying out the code – I appreciate it. Good to know it’s working for you.

但是…我遇到了一些非常奇怪的结果.在Windows 7 x64计算机上运行时,出现模糊"问题.但是,在Windows 7虚拟机(在SAME机器上使用VMWare)中进行尝试,它可以完美地工作.

But … I am experiencing some very strange results. I have the "blurring" issue when running on a Windows 7 x64 machine. However, trying it out in a Windows 7 virtual machine (using VMWare on the SAME machine), it works perfectly.

因此,在同一台计算机上,它本来就模糊了,但实际上并没有.我什至尝试了Windows 8虚拟机,然后再次正常工作.

So on the same machine, natively it blurs, but virtually it doesn’t. I even tried a Windows 8 virtual machine, and again it worked fine.

我发现,如果我选择NON-Aero主题,则一切正常(尽管如果没有Aero,它看起来会不太好).但是,在其他正在运行的机器上,确实选择了Aero主题.我真的不明白.

What I have found is that if I select a NON-Aero theme, all works ok (although it’s doesn’t look so good without Aero). And yet on the other machines where it IS working, they DO have Aero themes selected. I really don’t get it.

所以这不是真正的解决方案.我不想让我的潜在客户关闭Aero.

So that’s not really a solution. I don’t want to have to ask my potential customers to turn Aero off.

我尝试了许多Dwm *函数的调用,试图找出工作机和非工作机之间的差异,但找不到任何东西.

I have tried calls to many of the Dwm* functions trying to find a difference between the working and non-working machines but cannot find anything.

如果我插入此代码:

DWMNCRENDERINGPOLICY policy = DWMNCRP_DISABLED;
DwmSetWindowAttribute(hWnd,
                      DWMWA_NCRENDERING_POLICY,
                      (void*)&policy,
                      sizeof(DWMNCRENDERINGPOLICY));

仅在创建主窗口之后,所有功能都可以正常工作(尽管再一次,如果没有Aero边框,效果会不佳).

Just after creating the main window then all works fine again (although, once again, doesn’t look as good without the Aero border).

所以我对前进的方式真的感到茫然.任何想法深表感谢!

So am I really at a loss as to how I can move forward. Any ideas gratefully received!

推荐答案

我想我可以提供更多有关这些污点/模糊来自何处以及为什么您在Windows 8/10 Aero中看到更多(或有所不同)的见解.

I think I can provide some more insight about where that smearing/blurring is coming from and why you see it more (or differently) in Windows 8/10 Aero.

您的代码具有以下事实:

The fact that your code has:

wcex.style = CS_HREDRAW | CS_VREDRAW;

是您在Win7上看不到拖尾/模糊的原因.这会导致Windows用纯色填充WM_PAINT尚未绘制的窗口的新暴露区域,虽然不是很完美,但不会分散注意力.

is the reason why you didn't see the smearing/blurring on Win7. This causes Windows to fill in newly exposed areas of the window that have not yet been drawn by your WM_PAINT with a solid color, which is not perfect but not that distracting.

但是在Windows 8/10 Aero下,情况有所不同.应用程序不会直接绘制到屏幕上,而是绘制到屏幕外缓冲区,然后由邪恶的DWM.exe窗口管理器合成.事实证明,DWM实际上在受 CS_HREDRAW | IDS影响的现有旧版XP/Vista/7 BitBlt 行为之上又添加了 BitBlt 类型的行为的另一层.CS_VREDRAW .

But under Windows 8/10 Aero, things are different. Apps don't draw directly to the screen, but rather draw to offscreen buffers that are then composited by the evil DWM.exe window manager. It turns out that DWM actually adds another layer of BitBlt-type behavior on top of the existing legacy XP/Vista/7 BitBlt behavior that is affected by CS_HREDRAW | CS_VREDRAW.

DWM blit行为更加疯狂,因为它们不仅复制客户区,而且实际上在旧客户区的边缘复制像素以制作新客户区.

And the DWM blit behavior is even more crazy because they don't just copy the client area, but they actually replicate pixels at the edges of your old client area to make the new one.

不幸的是,使DWM不做它的行为比仅传递一些额外的标志要困难得多.

Unfortunately, making DWM not do its blit is much harder than just passing some extra flags.

我没有100%的解决方案,但请参阅此问答以了解一种计时技巧,该技巧可用于大大减少DWM干扰您的窗口客户区域的频率,这将减少拖尾现象/模糊:

I don't have a 100% solution, but please see this Q&A for a sort of timing trick that can be used to greatly reduce the frequency with which DWM messes with your window client area, which will reduce the smearing/blurring:

如何消除丑陋的抖动/flicker/jumping调整窗口大小时,尤其是拖动左/上边框(Win 7-10; bg,bitblt和DWM)?

享受!

这篇关于调整窗口大小会导致在右边框附近出现污点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 11:44