【LibUIDK界面库系列文章】设置Edit控件的Margin

来源:互联网 发布:云计算对教育的影响 编辑:程序博客网 时间:2024/04/29 20:49


作者:刘树伟


在常规方法下。
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消息的返回值一起,决定窗口需要保留的区域。

阅读全文
0 0
原创粉丝点击