2010-10-11 108 views
5

好的,所以在我的應用程序中,有一堆winAPI和一些自定義控件。耶...雙緩存winAPI

現在,通常,他們只是靜靜地重繪自己的動畫,狀態改變,等....它一切正常。

但我有一個名爲fix()的Window類的方法。這被稱爲每當整個窗口需要更新。它調整了控件的大小並使窗口無效。

發生這種情況時,會繪製背景,然後是選項卡控件,然後是所有其他頂部。這會導致非常惱人的閃爍,尤其是在調整窗口大小時(由於不斷調用fix())。

我曾嘗試:

  • WS_EX_COMPOSITED。這只是雙緩衝單個控件。它是一種改進,但閃爍不可避免地依然存在。
  • 關閉背景圖。幾乎沒有解決問題,實際上使情況變得更糟。

所以:我需要一種技術/方法/無論如何讓我雙緩衝整個窗口。我認爲自己處理WM_PAINT消息可能是一個解決方案,但我不知道從哪裏開始。我有一種可怕的感覺,這是不可能的...

請幫助,這是一個關鍵問題。當這個愚蠢的小問題得到解決時,我會很放心。

+0

也許檢查此頁面嗎? http://www.gamedev.net/community/forums/topic.asp?topic_id=411559 – 2010-10-11 08:04:23

回答

4

正是在這個時候,人們才意識到微軟對本土開發者的漠視。實際上,人們可能會開始懷疑微軟有意破壞本地繪畫以強制本地開發人員轉向WPF的偏執狂妄想。

首先,考慮WS_EX_COMPOSITEDWS_EX_COMPOSITED似乎是芥末: - 它表示它強制執行一個botton來爲子控件的頂部繪製訂單,並且基本上WM_PAINT消息被批處理。它說它是在Windows 2000(5.0)中添加的,並且只有幾行,它不支持啓用桌面組合。即從Windows Vista(6.0)開始它將停止工作,除非關閉了航空玻璃杯,誰會這樣做?

然後,有兩種可能的「黑客」,以嘗試並獲得無閃爍的繪畫工作:

  • 首先,你需要mimimize overpainting量。有必要確保窗戶的任何特定區域只塗一次。 BeginDeferWindowPos也是必要的批量調整操作,以確保暫時狀態 - 其中一個窗口與另一個窗口重疊 - 不會發生(即窗口A已調整大小,但窗口B沒有)。

當然,當您嘗試繪製皮膚對話框,或使用組框或選項卡控件或任何數量的其他限制時,WS_EX_CLIPSIBLINGS是不恰當的。

  • WM_SETREDRAW是一個神奇的信息。沒有API可以訪問這個功能:WM_SETREDRAW直接由DefWindowProc處理,以在整個過程中將窗口標記爲隱藏。在發送WM_SETREDRAW, FALSE後,使用父窗口句柄(及其所有子項)調用GetDC/GetDCEx/GetWindowDC等將返回一個不會在屏幕上繪製的DC。當你完成發送WM_SETREDRAW,TRUE(然後手動重新繪製窗口)時,這給了你一個對子窗口做各種東西的機會。所有的子窗口當然都會在自己的時間內繪製,並且在父窗口完成擦除背景之後,WM_SETREDRAW不是萬能的。

打破WS_EX_COMPOSITED,在.NET的WinForms和WPF重新寫了從地面控制最多不宜使用本機的控制,使他們能夠在緩衝畫烤後出現。也支持alpha。

0

沒有代碼我很難想象什麼是實際情況... 但是你可以嘗試處理WM_ERASEBKGND,只要你收到它們就跳過擦除就返回TRUE。

+0

我試過這個。它只是一團糟。你知道當你不清除背景時會發生什麼? – 2010-10-11 07:43:19

+0

背景顯然不是「擦除」:>。那麼如果你的畫覆蓋了整個區域,那麼它的刪除與否就無關緊要了。 – YeenFei 2010-10-12 00:42:37

1

嗯。在人們衝入並關閉這個話題之前,我最好提一提你的問題本身不是雙緩衝,而是在重新定位控制時閃爍,因爲「手動」雙緩衝只是幾種解決方案之一。

可能是,例如, BeginDeferWindowPos &朋友可以修復閃爍。免責聲明:我曾經知道幾乎所有的Win16 API的細節,但是我做了API級編程已經有幾年了。

乾杯&心連心,

- 阿爾夫

+0

這是win32 ... – 2010-10-11 07:34:36

+0

@亞歷山大,win32只是win16s少了邪惡的雙胞胎。 – 2010-10-11 08:04:07

0

手柄WM_ERASEBKGND爲你的窗口,並在執行排除每個子控件的rects,然後適當地填補剩餘的背景,告訴框架,您通過返回true來描繪​​自己的背景。 對所有其他子控件執行相同的操作,而這些子控件依次持有其他控件,如選項卡控件。對於使用MFC的示例,請參閱here

+0

這是一個不受歡迎的解決方案。也許作爲最後的手段... – 2010-10-11 07:43:53

1

在.net中有ControlStyle.AllPaintingInWmPaint應該在每個容器窗口(所以主窗口和選項卡)上設置。我無法找到相當於winapi的。但是,這樣做是將背景的繪畫從WM_ERASEBKGND移動到WM_PAINT。 它也會從父級中減去子控件的區域以避免閃爍,可能是您需要手動執行此操作。

我很驚訝WS_EX_COMPOSITED沒有幫助。如果你在頂層窗口中設置它,並且不要在子控件上調用RedrawWindow,那就應該有效。

此外請務必使用和不使用DWM/Aero進行測試。你可以得到不同的結果。

+0

P.S.我在早先的答案中放了一段C#代碼示例。您可以修改它以展示您看到的效果。 HTTP://計算器。com/questions/3735121/direct2d-gdi-and-slow-windows-forms-drawing-what-c​​an-done/3735328#3735328 – 2010-10-11 07:16:50

+0

我可以手動清除WM_PAINT中的背景。 – 2010-10-11 07:44:16

+0

@Alexander:這就是你需要做的。您還需要在WM_ERASEBKGND上返回true。從繪畫中排除子窗口rects也可能是必要的(也許添加WS_CLIPCHILDREN將會起作用)。 – 2010-10-11 07:51:09