作者:劉樹偉
在常規方法下。
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消息的返回值一起,決定窗口需要保留的區域。