2011-06-24 22 views
0

我有一個使用兩個源圖像(填充和未填充)繪製進度條的WIN32所有者繪製的靜態控件。初始繪製效果很好:WIN32:如何告訴所有者繪製靜態控件以自行刷新?

case WM_DRAWITEM: 
    { 
     DRAWITEMSTRUCT* draw = (DRAWITEMSTRUCT*)lparam; 
     // Manually draw the progress bar. 
     if(draw->hwndItem == hwndProgress) 
     { 
      // Progress bar is 526 pixels wide. 
      int left = progressPercent * 526/100; 
      // Paint sections of window with filled and unfilled bitmaps 
      // based on progress bar position. 
      HDC hdcMem = ::CreateCompatibleDC(draw->hDC); 
      ::SelectObject(hdcMem, hBmpProgressFull); 
      ::BitBlt(draw->hDC, 0, 0, left, 36, hdcMem, 0, 0, SRCCOPY); 
      ::DeleteDC(hdcMem); 
      HDC hdcMem2 = ::CreateCompatibleDC(draw->hDC); 
      ::SelectObject(hdcMem2, hBmpProgressEmpty); 
      ::BitBlt(draw->hDC, left, 0, 526-left, 36, hdcMem2, left, 0, SRCCOPY); 
      ::DeleteDC(hdcMem2); 
      return TRUE; 
     } 
    } 
    return 0; 

但是,我似乎無法得到正確的擦除和重新繪製的東西。我試過SendMessage函數與WM_PAINT和RedrawWindow並沒有一個已經做得很正確:

bool SetLoginProgressBar(float value) 
{ 
    if(hwndProgress != NULL) 
    { 
     progressPercent = (int)(value * 100.0); 
     //::RedrawWindow(hwndProgress, NULL, NULL, RDW_INVALIDATE|RDW_INTERNALPAINT); 
     ::SendMessage(hwndProgress, WM_PAINT, NULL, NULL); 
    } 
    return true; 
} 

相反重繪使用新值的窗口,它只是與最初繪製的圖像坐在那裏,而忽略進一步繪製命令。它爲初始值正確繪製了進度,無論是0%還是50%等,並且我都可以驗證是否正在調用WM_DRAWITEM消息處理程序代碼。

那麼,告訴這個控件在WIN32中擦除和重繪的正確方法是什麼?

是否可能需要執行BeginPaint/EndPaint之類的操作,或者刪除DRAWITEMSTRUCT中已通過的hDC?

+1

您是否嘗試過使用覆蓋控制區域的矩形調用InvalidateRect()? – Rom

回答

6

在破壞DC之前,您並未取消選擇內存DC中的位圖。也許位圖處於Windows不允許你再次選擇它們的狀態,所以BitBlts失敗。

P.S. RedrawWindow就是我在這種情況下使用的。 InvalidateRect也可以工作,但前提是您的消息循環正在運行。這導致了另一種觀察:如果您處於長時間運行的操作中,您可能無法回到消息循環,並且您的應用程序將顯示爲掛起狀態,包括更新進度窗口。

+0

如果你的消息循環沒有運行,那麼你會被掛起,故事結束。 –

+0

@David Heffernan,我的意思是「似乎已經掛起」了,這是一個暫時的情況,在某些時候會被清除。 –

+0

我從來沒有必須使用RedrawWindow。我無法想象爲什麼InvalidateRect不夠,但我確信有很好的理由。 –

3

InvalidateRect()是您需要調用的功能。

您永遠不會發送或發佈WM_PAINT消息 - 窗口管理器會在需要時爲您做這些事情(例如窗口拖動窗口)。如果重繪是由於窗口管理器不知道的更改而引起的,則通過調用InvalidateRect()來強制執行重繪循環。 lpRect通過NULL,整個客戶區將被重新繪製。通過TRUEbErase強制背景在重繪週期開始時被擦除。

當您調用InvalidateRect()時發生什麼情況是WM_PAINT消息放置在您的消息隊列中並且InvalidateRect()函數調用返回。當你下一次清除你的消息隊列時,你處理WM_PAINT消息。

我建議你拿到Petzold編程Windows書的副本並閱讀所有相關內容。

相關問題