做MFC編程,Static控件是會經常用到的了,而使Static控件背景透明,以及改變文本的內容、字體、顏色等屬性,都是會比較容易碰到的情況。
王道做法當然是繼承CStatic然後重載OnPaint(),完全自己來畫,這樣能夠獲得最大的靈活性,但就是比較麻煩,像我這種比較懶的,就更喜歡用下面的懶方法了。
同樣創建一個CStatic的派生類,處理父窗口的反射消息WM_CTLCOLOR,即添加HBRUSH CtlColor(CDC *pDC, UINT nCtlColor)這個消息映射函數。注意,不是HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)!我也不知道具體原理,反正我用後者從來沒成功過,甚至程序都不會運行到裏面。。。
其實還有一個方法,就是處理父窗口的OnCtlColor(),更簡單一點,但是不符合封裝的原則,所以這裏就不提了。
- HBRUSH CSample::CtlColor(CDC* pDC, UINT nCtlColor)
- {
- // TODO: Change any attributes of the DC here
- pDC->SetBkMode(TRANSPARENT); // 設置透明背景
- pDC->SetTextColor(RGB(0, 0, 255)); // 設置文本顏色
- // TODO: Return a non-NULL brush if the parent's handler should not be called
- return (HBRUSH)GetStockObject(HOLLOW_BRUSH); // 返回透明畫刷
- }
通過上述代碼,就可以得到彩色的文本以及透明的背景,但是,還存在一個問題,當該Static控件的文本內容或者屬性,在運行過程中發生變化的時候,由於背景一直沒有擦除(爲了實現透明),會出現重影,導致文本模糊成一團。
解決方法是,讓父窗口進行重繪更新,對,不要看錯了,是控件所屬的父窗口,而不是控件本身,讓控件本身重繪也不會解決問題的,同樣我也不太清楚原理。。。
這裏還會引出一個問題,如果重繪整個父窗口,由於GDI並不內嵌雙緩衝,勢必造成嚴重的閃爍問題,解決辦法當然是只讓父窗口重繪控件所佔的部分,其他部分不進行重繪,代碼如下:
- void CSample::SetText(const TCHAR *pszText)
- {
- this->SetWindowText(pszText);
- RECT stRect;
- // 獲取控件位置
- this->GetWindowRect(&stRect);
- // 重要!調用父窗口的S2C函數進行座標轉換
- this->GetParent()->ScreenToClient(&stRect);
- // 重繪控件所在區域,在這裏擦除背景
- this->GetParent()->InvalidateRect(&stRect, true);
- }
這樣就能夠實現動態改變文本屬性而不出現重影現象,注意這裏調用了父窗口的ScreenToClient()函數來進行座標的轉換,調用控件本身的S2C函數的話,得到的座標無法用來進行下一步的重繪工作。
現在還有一個比較隱蔽的問題,就是文本字符串的長度,如果新的字符串的長度比原來的長,而之前拖放Static控件長度又不足的時候,就會造成超出的部分無法顯示,當然你大可以在拖放的時候就儘量弄得長一點,但是如果能隨着文本內容而自動調整控件長度,那不是會好得多麼。
爲了實現這樣的效果,上面的代碼要修改如下:
- void CSample::SetText(const TCHAR *pszText)
- {
- CDC *pDC = this->GetDC();
- // 獲取文本在當前繪圖環境下所佔的寬度和高度
- CSize clSize = pDC->GetTextExtent(pszText, _tcslen(pszText));
- RECT stRect;
- // 獲取控件當前矩形區域
- this->GetWindowRect(&stRect);
- // 調整寬度爲新文本所佔寬度
- stRect.right = stRect.left + clSize.cx;
- // 重要!調用父窗口S2C函數轉換座標
- this->GetParent()->ScreenToClient(&stRect);
- // 調整控件大小以適應新文本
- this->MoveWindow(&stRect);
- // 重繪控件以避免重影
- this->GetWindowRect(&stRect);
- this->GetParent()->ScreenToClient(&stRect);
- this->GetParent()->InvalidateRect(&stRect, true);
- }
同樣,這裏也是調用父窗口的S2C函數,這樣得到的座標才能正確使用。代碼經過上述修改,就實現了控件隨文本動態調整寬度的效果。
以上只是實現Static背景透明、更改文本顏色以及動態調整控件大小的簡單演示,實際的應用中可能還需要考慮很多情況,適當修改代碼,但基本原理是不變的。當然要獲得最大的靈活性,還是得自己來繪製了 - -