[CListCtrl]改變行高

由於MFC裡的CListCtrl並無提供改變行高的函式,因此就需要透過改變繪圖方式,來達到改變行高的效果。

這邊找到的參考資料如下:
1.Report control - with category
2.Changing Row Height in an owner drawn Control
3.CListCtrl 行高问题最终解决方法

裡面提到的方式都是使用OnSetFont()以及MeasureItem()來搭配使用。

另一種就是直接在OnNMCustomdrawLst()裡面,進行文字繪製。
Expandable List Control to Accept Multilines

OnNMCustomdrawLst()使用方式可參考[CListCtrl]改變儲存格文字顏色

由於使用OnNMCustomdrawLst()的方式比較複雜,所以底下就針對DrawItem()以及MeasureItem()兩個函式來說明。

在.h的部份:(SetFont()的部分稍後說明)
 void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) ;  
 afx_msg LRESULT    OnSetFont(WPARAM wParam, LPARAM lParam);  
 afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);  

在message map部分:(無效的部份稍後說明)
 BEGIN_MESSAGE_MAP(CXListCtrl, CListCtrl)  
 //Multi-line  
     ON_MESSAGE(WM_SETFONT, OnSetFont)    //NOTE:無效  
     ON_WM_MEASUREITEM_REFLECT()        //NOTE:無效  
     ON_WM_MEASUREITEM()                //NOTE:無效  
 END_MESSAGE_MAP()  

在.cpp裡面要加上下列4個函式:
1.OnMeasureItem()
 void CXListCtrl::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
   CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct);  
 }  

這邊為何要又呼叫一次CListCtrl::OnMeasureItem我就不曉得原因了,因上面參考連結是有這項。但程式卻都沒進入到此函式。所以不加應該也沒關係吧?!XD

2.MeasureItem()
 void CXListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
     // Get the LOGFONT for the current font.  
     LOGFONT lf;  
     ::ZeroMemory(&lf, sizeof(lf));  
     CFont* pFont = GetFont();  
     ASSERT_VALID(pFont);  
     if (pFont)   
         VERIFY(pFont->GetLogFont(&lf));  
     int nAdj(2) ;        //Sample is 4  
     m_nLinesPerRow = max(m_nLinesPerRow, 1);  
     if (lf.lfHeight < 0)   
         lpMeasureItemStruct->itemHeight = ((-lf.lfHeight+nAdj) * (m_nLinesPerRow));  
     else   
         lpMeasureItemStruct->itemHeight = ((lf.lfHeight+nAdj) * (m_nLinesPerRow));  
 }  

這邊實際上用來變更高度的是lpMeasureItemStruct->itemHeight,但由於抓到的並不是完整的文字高度,單行沒問題,三行以上就出錯了。所以在範例的部份,有加上平移值。這邊測試結果,如果平移值與顯示行數差值大於等於2時,最後一行文字就會被蓋掉。所以這個值還是要做動態的會比較好。
如有需要做到每行高度不同的話,後面乘上的顯示行數就需要針對顯示文字的行是做動態處理。
目前還沒想到好作法,之後再回來補充。

3.OnSetFont()
 LRESULT CXListCtrl::OnSetFont(WPARAM wParam, LPARAM lParam)  
 {  
     CRect rc;  
     GetWindowRect(&rc);  
     WINDOWPOS wp;  
     wp.hwnd = this->m_hWnd;  
     wp.cx = rc.Width() ;  
     wp.cy = rc.Height() ;  
     wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;  
     LRESULT lrReturn(Default());  
     SendMessage(WM_WINDOWPOSCHANGED, 0, reinterpret_cast<LPARAM> (&wp));  
     return lrReturn;  
 }  

在範例裡,這個函式僅是用來觸發MeasureItem()更新動作的一個事件而已。觸發MeasureItem()的事件很獨特,就是讓畫面有所變動,然後系統就會送回重新繪製item的訊息,接下來就會進到MeasureItem()來重新繪製每個item的狀況。
此方法在範例中能成功,但我不管怎麼試,就是試不出來,也找不到原因。最後就在DrawItem()結束後,直接送出視窗訊息。

以上就是改變行高的作法

No comments:

Post a Comment

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...