如何以原子方式更新HWND的樣式和位置?

[英]How can I update an HWND's style and position atomically?


I'm writing a Win7 desktop app and want to have it seamlessly transition from windowed to windowed-fullscreen (and vice-versa), and have mostly accomplished this by calling SetWindowLongPtr to update its style immediately followed by MoveWindow to update its size and position. The problem is that the window flashes for one frame to show its style updated, but the new size and position are not shown. The next frame everything looks correct but I'm trying to avoid this single-frame artifact.

我正在編寫一個Win7桌面應用程序,並且想讓它從窗口無縫轉換到窗口全屏(反之亦然),並且主要是通過調用SetWindowLongPtr來更新其樣式,然后立即更新其大小和位置的MoveWindow來完成此操作。 。問題是窗口閃爍一幀以顯示其樣式更新,但未顯示新的大小和位置。下一幀看起來都很正確,但我試圖避免這種單幀神器。

I've tried reversing the order in which I call the APIs but it just changes what the artifact looks like. I've also tried hiding the window, calling the APIs, and then showing the window, but this just causes the window to disappear for the one frame.

我已經嘗試顛倒我調用API的順序,但它只是改變了工件的樣子。我也嘗試隱藏窗口,調用API,然后顯示窗口,但這只會導致窗口在一幀中消失。

I know that one option is to create a new window with the desired properties then destroy the old one, but I wanted to find a less expensive alternative.

我知道一個選項是創建一個具有所需屬性的新窗口然后銷毀舊窗口,但我想找到一個更便宜的替代品。

So is there any way to call these APIs and have them be visually reflected atomically? As a bonus, it'd be nice to also have the multiple resulting WM_SIZE messages coalesced into a single event, but I can manage that myself in the message handler.

那么有沒有辦法調用這些API並讓它們以原子方式直觀地反映出來?作為獎勵,將多個結果WM_SIZE消息合並為單個事件也很好,但我可以在消息處理程序中自行管理。

4 个解决方案

#1


2  

Doing this sort of thing reliably is difficult in Windows, particularly since Vista as the DWM can complicate things. It's often a matter of trial and error until you find a solution that works for you.

在Windows中很難可靠地執行此類操作,特別是因為Vista作為DWM會使事情復雜化。在找到適合您的解決方案之前,這通常是一個反復試驗的問題。

SetWindowPos has an SWP_NOREDRAW flag that prevents the window from being redrawn in response to the call. So you could try changing the position first, then updating the styles, and finally a third call to redraw the window in its new location. For example,

SetWindowPos有一個SWP_NOREDRAW標志,可以防止窗口重新繪制以響應調用。因此,您可以先嘗試更改位置,然后更新樣式,最后再嘗試第三次調用以重新繪制新位置的窗口。例如,

SetWindowPos(hWnd, 0, x, y, w, h, SWP_NOREDRAW | SWP_NOZORDER);
SetWindowLongPtr(hWnd, GWL_STYLE, dwNewStyles);
RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE | RDW_FRAME);

#2


1  

MSDN says:

Certain window data is cached, so changes you make using SetWindowLongPtr will not take effect until you call the SetWindowPos function.

某些窗口數據被緩存,因此使用SetWindowLongPtr進行的更改在調用SetWindowPos函數之前不會生效。

So this should work. Perhaps try using SetWindowPos instead of MoveWindow.

所以這應該工作。也許嘗試使用SetWindowPos而不是MoveWindow。

Are you doing anything interesting in your window proc when you get the events that are caused by these calls? In particular, are you "fixing" the size or anything like that?

當你得到這些電話引起的事件時,你在窗口過程中做了什么有趣的事嗎?特別是,你“修理”大小或類似的東西?

#3


1  

Check out WM_SETREDRAW; use it to disable redraw, change the window styles, and then call RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN) to display them atomically.

查看WM_SETREDRAW;用它來禁用重繪,更改窗口樣式,然后調用RedrawWindow(hWnd,NULL,NULL,RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN)以原子方式顯示它們。

#4


0  

What do you mean by "windowed-fullscreen"? Is it the same as maximized?

你是什​​么意思“窗口全屏”?它與最大化一樣嗎?

If so, ShowWindow(hwnd, SW_MAXIMIZE) ?

如果是這樣,ShowWindow(hwnd,SW_MAXIMIZE)?


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/09/26/720f531b27ff0bc62160352789985fd8.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com