Static control 透明,重影,長度問題

 

做MFC編程,Static控件是會經常用到的了,而使Static控件背景透明,以及改變文本的內容、字體、顏色等屬性,都是會比較容易碰到的情況。

王道做法當然是繼承CStatic然後重載OnPaint(),完全自己來畫,這樣能夠獲得最大的靈活性,但就是比較麻煩,像我這種比較懶的,就更喜歡用下面的懶方法了。

同樣創建一個CStatic的派生類,處理父窗口的反射消息WM_CTLCOLOR,即添加HBRUSH CtlColor(CDC *pDC, UINT nCtlColor)這個消息映射函數注意,不是HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)!我也不知道具體原理,反正我用後者從來沒成功過,甚至程序都不會運行到裏面。。。

其實還有一個方法,就是處理父窗口的OnCtlColor(),更簡單一點,但是不符合封裝的原則,所以這裏就不提了。

C++代碼
  1. HBRUSH CSample::CtlColor(CDC* pDC, UINT nCtlColor)
  2. {
  3. // TODO: Change any attributes of the DC here
  4. pDC->SetBkMode(TRANSPARENT); // 設置透明背景
  5. pDC->SetTextColor(RGB(0, 0, 255)); // 設置文本顏色
  6. // TODO: Return a non-NULL brush if the parent's handler should not be called
  7. return (HBRUSH)GetStockObject(HOLLOW_BRUSH); // 返回透明畫刷
  8. }

通過上述代碼,就可以得到彩色的文本以及透明的背景,但是,還存在一個問題,當該Static控件的文本內容或者屬性,在運行過程中發生變化的時候,由於背景一直沒有擦除(爲了實現透明),會出現重影,導致文本模糊成一團。

解決方法是,讓父窗口進行重繪更新,對,不要看錯了,是控件所屬的父窗口,而不是控件本身,讓控件本身重繪也不會解決問題的,同樣我也不太清楚原理。。。

這裏還會引出一個問題,如果重繪整個父窗口,由於GDI並不內嵌雙緩衝,勢必造成嚴重的閃爍問題,解決辦法當然是只讓父窗口重繪控件所佔的部分,其他部分不進行重繪,代碼如下:

C++代碼
  1. void CSample::SetText(const TCHAR *pszText)
  2. {
  3. this->SetWindowText(pszText);
  4. RECT stRect;
  5. // 獲取控件位置
  6. this->GetWindowRect(&stRect);
  7. // 重要!調用父窗口的S2C函數進行座標轉換
  8. this->GetParent()->ScreenToClient(&stRect);
  9. // 重繪控件所在區域,在這裏擦除背景
  10. this->GetParent()->InvalidateRect(&stRect, true);
  11. }

這樣就能夠實現動態改變文本屬性而不出現重影現象,注意這裏調用了父窗口的ScreenToClient()函數來進行座標的轉換,調用控件本身的S2C函數的話,得到的座標無法用來進行下一步的重繪工作。

現在還有一個比較隱蔽的問題,就是文本字符串的長度,如果新的字符串的長度比原來的長,而之前拖放Static控件長度又不足的時候,就會造成超出的部分無法顯示,當然你大可以在拖放的時候就儘量弄得長一點,但是如果能隨着文本內容而自動調整控件長度,那不是會好得多麼。

爲了實現這樣的效果,上面的代碼要修改如下:

C++代碼
  1. void CSample::SetText(const TCHAR *pszText)
  2. {
  3. CDC *pDC = this->GetDC();
  4. // 獲取文本在當前繪圖環境下所佔的寬度和高度
  5. CSize clSize = pDC->GetTextExtent(pszText, _tcslen(pszText));
  6. RECT stRect;
  7. // 獲取控件當前矩形區域
  8. this->GetWindowRect(&stRect);
  9. // 調整寬度爲新文本所佔寬度
  10. stRect.right = stRect.left + clSize.cx;
  11. // 重要!調用父窗口S2C函數轉換座標
  12. this->GetParent()->ScreenToClient(&stRect);
  13. // 調整控件大小以適應新文本
  14. this->MoveWindow(&stRect);
  15. // 重繪控件以避免重影
  16. this->GetWindowRect(&stRect);
  17. this->GetParent()->ScreenToClient(&stRect);
  18. this->GetParent()->InvalidateRect(&stRect, true);
  19. }

同樣,這裏也是調用父窗口的S2C函數,這樣得到的座標才能正確使用。代碼經過上述修改,就實現了控件隨文本動態調整寬度的效果。

以上只是實現Static背景透明、更改文本顏色以及動態調整控件大小的簡單演示,實際的應用中可能還需要考慮很多情況,適當修改代碼,但基本原理是不變的。當然要獲得最大的靈活性,還是得自己來繪製了 - -

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章