【LibUIDK界面庫系列文章】設置Edit控件的Margin



作者:劉樹偉


在常規方法下。
1. 使用CEdit::SetMargins,可以設置Edit左右邊距,但無法設置上下邊距。
2. 使用CEdit::SetRect,可以設置包含多行屬性的Edit的上下左右邊距,但無法設置單行Edit的邊距。

如果要設置單行Edit的上下左右邊距,可以處理WM_NCCALCSIZE,在WM_NCCALCSIZE消息中,修改客戶區域的大小。代碼如下:

// class CMyEdit : public CEdit
// CRect m_rcMargin表示四個邊的邊距
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // TODO: Add your specialized code here and/or call the base class

 if (message == WM_NCCALCSIZE)
 {
  // Set the margin of text in edit control,
  // If the edit control is multiline, use CEdit::SetRect
  // If the edit control is singleline, and the top and bottom margin is 0, use CEdit::SetMargins.
  // Others, use WM_NCCALCSIZE message to set the margin.
  LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
  BOOL bMultiline = lStyle & ES_MULTILINE;
  if (!bMultiline && (m_rcMargin.top != 0 || m_rcMargin.bottom != 0))
  {
   BOOL bCalcValidRects = wParam;
   if (!bCalcValidRects)
   {
    LPRECT lpRect = LPRECT(lParam);

    lpRect->left += m_rcMargin.left;
    lpRect->top += m_rcMargin.top;
    lpRect->right -= m_rcMargin.right;
    lpRect->bottom -= m_rcMargin.bottom;

    return 0;
   }
  }
 }
 
 return CEdit::WindowProc(message, wParam, lParam);
}

上面的代碼不僅對單行Edit有效,對多行Edit同樣有效。但上述代碼存在一個Bug。當Edit的尺寸發生改變時,Margin被不會被重新計算,這是由於調用MoveWindow改變Edit尺寸時,WM_NCCALCSIZE,wParam參數的值爲TRUE,並沒有進入上面的代碼。所以wParam爲True也需要處理:
LRESULT CMyEdit::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // TODO: Add your specialized code here and/or call the base class

 if (message == WM_NCCALCSIZE)
 {
  // Set the margin of text in edit control,
  // If the edit control is multiline, use CEdit::SetRect
  // If the edit control is singleline, and the top and bottom margin is 0, use CEdit::SetMargins.
  // Others, use WM_NCCALCSIZE message to set the margin.
  LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
  BOOL bMultiline = lStyle & ES_MULTILINE;
  if (!bMultiline && (m_rcMargin.top != 0 || m_rcMargin.bottom != 0))
  {
   BOOL bCalcValidRects = wParam;
   if (bCalcValidRects)
   {
    NCCALCSIZE_PARAMS *pncp = (NCCALCSIZE_PARAMS *)lParam;
    pncp->rgrc[0].left += m_rcMargin.left;
    pncp->rgrc[0].top += m_rcMargin.top;
    pncp->rgrc[0].right -= m_rcMargin.right;
    pncp->rgrc[0].bottom -= m_rcMargin.bottom;

    return 0;
   }
   else
   {
    LPRECT lpRect = LPRECT(lParam);

    lpRect->left += m_rcMargin.left;
    lpRect->top += m_rcMargin.top;
    lpRect->right -= m_rcMargin.right;
    lpRect->bottom -= m_rcMargin.bottom;

    return 0;
   }
  }
 }
 
 return CEdit::WindowProc(message, wParam, lParam);
}

當修改了Margin參數後,要觸發WM_NCCALCSIZE消息執行。一種方式是在Edit創建之間,就設置好Margin值,這樣,在Edit創建時,會觸發WM_NCCALCSIZE消息。另一種方法是在Edit創建之後,通過調用:
 SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_DRAWFRAME);
來觸發。
注意:不能通過GetWindowRect得到Edit座標rcEdit,再調用MoveWindow(rcEdit)來觸發,因爲如果MoveWindow參數所指定的新座標與原來座標一樣的話,WM_NCCALCSIZE不會被觸發。


附1:
WM_NCCALCSIZE消息解釋:
Return Value:
WVR_VALIDRECTS: 此值表示,如果返回WVR_VALIDRECTS,NCCALCSIZE_PARAMS結構體的rgrc[1]和rgrc[2]成員指定的矩形分別包含有效的目標和源矩形。系統組合這兩個矩形,用來計算窗口需要保留的區域。系統把源矩形內任何部分的窗口圖像和剪輯拷貝到目標矩形。這兩個矩形都是相對於相對父窗口或相對屏幕的座標。此標記不能與其它標記組合。


附2:
NCCALCSIZE_PARAMS:
struct NCCALCSIZE_PARAMS
{
    RECT rgrc[3];
    PWINDOWPOS lppos;
}

rgrc:
 一個矩形數組:當處理WM_NCALCSIZE消息時,數組的含義也會改變。
 當窗口過程接收到WM_NCALCSIZE消息,第一個矩形包含窗口移動或縮放的新座標。也就是說,它是建議的新窗口座標。 第二個矩形包含窗口移動或縮放前的座標。第三個矩形包含窗口客戶區移動或縮放前的座標。如果窗口是子窗口,座標相對於父窗口的客戶區。如果窗口是top-level窗口,座標相對於屏幕。
 當窗口過程返回,第一個矩形爲“客戶端”區域移動或縮放後的新座標。第二個矩形爲有效的目標矩形,第三個矩形爲有效的源矩形。最後兩個矩形與WM_NCCALCSIZE消息的返回值一起,決定窗口需要保留的區域。

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