在调用本机方法 MoveWindow 期间闪烁

Posted

技术标签:

【中文标题】在调用本机方法 MoveWindow 期间闪烁【英文标题】:Flickering during call to native method MoveWindow 【发布时间】:2021-03-31 16:53:55 【问题描述】:

我有一个 WPF 应用程序,它使用 Process.Start() 方法打开一个新进程 (Notepad.exe)。我编写的代码阻止用户移动记事本窗口,其中窗口的 Top 属性不能小于 130 像素。我使用了来自 SO question 的信息,我最终使用以下代码来管理这个动作

这是我在移动目标窗口时定义的 windows 事件委托:

    protected void TargetMoved(IntPtr hWinEventHook, Hook.SWEH_Events eventType, IntPtr hWnd, Hook.SWEH_ObjectId idObject, long idChild, uint dwEventThread, uint dwmsEventTime)
    
        if (hWnd == targethWnd &&
            eventType == Hook.SWEH_Events.EVENT_OBJECT_LOCATIONCHANGE &&
            idObject == (Hook.SWEH_ObjectId)Hook.SWEH_CHILDID_SELF)
        
            rect = Hook.GetWindowRect(hWnd);
            int x = rect.Left;
            int y = rect.Top;
            int width = rect.Right - rect.Left;
            int height = rect.Bottom - rect.Top;

            if (rect.Left <= 0)
                x = 0;
            if (rect.Top <= 130)
                y = 130;
                
            UnsafeNativeMethods.MoveWindow(targethWnd, x, y, width, height, true);
            
        
    

这段代码工作正常,它使窗口保持在边界内,但有一个烦人的问题:当窗口被拖动到 130 像素标记以上时(当 Top 小于 130 时),窗口在之间来回闪烁我在哪里拖动它,它在哪里停止。

如何消除这种闪烁?

【问题讨论】:

你不能。它在所有 4 个方面都很烦人,由于标题栏,在顶部更加明显。真正的修复需要代码注入来子类化窗口并拦截 WM_MOVING 和 WM_SIZING,C# 不是合适的工具。并不是说任何语言都是这种hackorama的理想工具:) "如何消除这种闪烁?"简短的回答是你可能不能(合理地)。闪烁的发生是因为窗口被移动到新位置,然后你抓住它并将它移回原来的位置,并且像这样快速连续绘制两次会导致闪烁。所以不要那样做。 Notepad.exe 基本上只是一个带有最少包装的 Windows 编辑控件,所以不要使用它。只需创建您自己的包含编辑控件的窗口。在那里您可以处理WM_NCCALCSIZE 以确保窗口的位置/大小而不会闪烁。 【参考方案1】:

当你拖动一个窗口时,WM_WINDOWPOSCHANGINGWM_WINDOWPOSCHANGED 将被发送到窗口过程,然后重新绘制所做的更改。如果这个窗口过程是你自己创建的,那么你可以处理这两条消息,并将left和top限制为0和130。

case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:

    WINDOWPOS* pos = (PWINDOWPOS)lParam;
    if (pos->x <= 0)
        pos->x = 0;
    if (pos->y <= 130)
        pos->y = 130;
    return 0;

如果这不是你的窗口过程,你需要SetWindowSubclass,但是你不能跨线程子类化一个窗口,你还需要使用代码注入。

所以,对于记事本窗口,你不能简单地解决这个问题, 正如评论所说,您可以简单地将编辑控件集成到您自己的窗口中。然后像上面的代码一样处理窗口消息。

【讨论】:

以上是关于在调用本机方法 MoveWindow 期间闪烁的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Windows 的最大化窗口上无缝调用 MoveWindow?

MFC中改变窗口大小MoveWindow...

在 FlowLayoutPanel 滚动期间,背景扭曲 + 闪烁

DiffableDataSource - 无动画,但在删除操作期间闪烁

Swift UIView 在更改 alpha 期间闪烁

diffable 数据源节标题在更新期间闪烁