同时移动多个Windows - DeferWindowPos

时间:2014-01-23 15:34:53

标签: c# windows winapi scroll pinvoke

我需要同时(一起)移动几个外部应用程序窗口作为一组来模拟滚动功能。

如果你的第一个想法是“你为什么要这样做”或“你永远不应该那样做”,那就假装这是一个好主意并且会很棒。

到目前为止,我已尝试过PInvoke方法MoveWindowSetWindowPos和(BeginDeferWindowPos,DeferWindowPos,EndDeferWindowPos)。

所有这些方法都产生大致相同的性能。移动一个窗口是超级活泼的,两个窗口没什么大不了的,但是一旦我尝试移动三个或更多的窗户,事情开始变得难看。这是一个使用延迟方法的片段,向您展示我是如何做事并跟踪绩效的。

private void multiMoveWindows(int moveAmt, int startingIndex)
{
    int tempX;
    int howmanyTimes = 0;
    int numOfWidgetsToMove = 0;
    int moveAmtRemaining = moveAmt;
    IntPtr MultiWindowStructure;
    System.Diagnostics.Stopwatch t = new Stopwatch();            
    WidgetTracker[] tmp_WhichWidgets = new WidgetTracker[10];           

    foreach (KeyValuePair<string, WidgetTracker> entry in m_dictWT)
    {
        WidgetTracker tmp = new WidgetTracker();
        tmp = entry.Value;
        if (tmp.WIndex >= startingIndex)
        {
            tmp_WhichWidgets[numOfWidgetsToMove] = tmp;
            ++numOfWidgetsToMove;
        }
    }

    for (int i = 0; i < moveAmtRemaining; i++)  
    {
    MultiWindowStructure = Native_Methods.BeginDeferWindowPos(numOfWidgetsToMove);
        foreach (WidgetTracker tmp in tmp_WhichWidgets)
        {
            if (tmp != null)
            {
                tmp.surveilWidget();
                tempX = tmp.WidgetRectLeft - 1;                    
                MultiWindowStructure = Native_Methods.DeferWindowPos(
                    MultiWindowStructure, tmp.WidgetHandle, HWND.NOTOPMOST, tempX, tmp.WidgetRectTop, 0, 0, SWP.NOREDRAW | SWP.NOZORDER | SWP.NOACTIVATE | SWP.NOSIZE);
                howmanyTimes++;
            }
        }
        t.Start();
        Native_Methods.EndDeferWindowPos(MultiWindowStructure);
        t.Stop();             
    }
    MessageBox.Show(howmanyTimes.ToString() + " move requests made." + Environment.NewLine + 
        "Execution of EndDeferWindowPos took " + t.Elapsed.Seconds.ToString() + " sec " + t.Elapsed.Milliseconds.ToString() + " ms." );    
}

以下是移动4个窗口的结果,每次移动320px,每次移动1px: enter image description here

你可以想象,等待14.5秒才能看到4个窗口穿过屏幕320像素是很难看的。

我添加了一些SWP标记并提高了性能,但7.5秒仍无法使用。

- 如何以流畅的方式实现这一目标?

是的,我意识到我一次可以移动超过1个像素,但这无法解决根本问题。我理解它的方式,使用任何PInvoke方法移动窗口将消息发布到WinAPI消息泵(WndProc())并在发布下一条消息之前等待消息被关闭/捕获/处理。我认为这是我花费14.5秒的时间 - 等待消息处理。

我尝试过使用SWP ASYNCWINDOWPOS,结果很可怕。每个窗口只能看到几十个看似随机的消息,因此窗口重叠,整个火车几乎不动。

我最接近解决方案是为每个“窗口小部件”分配一个父窗口(例如WindowsFormsHost +一个MDI窗口)并将它们放在窗体/窗口中,然后滚动该窗体/窗口。但是我有几个理由不想这样做。

请帮忙!

更新:有关CodeProject的更多信息,我已复制此问题。

<小时/>

更新

添加SWP标志有很多帮助,但我确定实际上减慢了很多东西是我的测试应用程序。每次移动4个这样的WPF窗口,我把它缩短到大约8.5秒。

sorry for the annoying flicker, first time using Cropper...

当我更换一个标准空记事本的测试窗口时,它下降到0.6秒,这对我来说是可以的。因此,我非常有信心代码是合理的。因此,当使用与时间相关的移动偏移(受控运动)程序实现此代码时,问题变为如何最小化窗口闪烁。 这仍然是一项正在进行的工作,所以我很感激任何建议。

0 个答案:

没有答案