我正在使用此问题的第一个答案中的代码:How can we vertically align text in edit box?将文本垂直居中在CEdit控件中。
以下是使用过的班级CEditVC
/// HEADER //////////////////////////////////////////
class CEditVC : public CEdit
{
public:
CEditVC();
protected:
CRect m_rectNCBottom;
CRect m_rectNCTop;
public:
virtual ~CEditVC();
protected:
afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);
afx_msg void OnNcPaint();
afx_msg UINT OnGetDlgCode();
DECLARE_MESSAGE_MAP()
};
/// IMPLEMENTATION /////////////////////////////////////////
CEditVC::CEditVC()
: m_rectNCBottom(0, 0, 0, 0)
, m_rectNCTop(0, 0, 0, 0)
{
}
CEditVC::~CEditVC()
{
}
BEGIN_MESSAGE_MAP(CEditVC, CEdit)
ON_WM_NCCALCSIZE()
ON_WM_NCPAINT()
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
void CEditVC::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
CRect rectWnd, rectClient;
//calculate client area height needed for a font
CFont *pFont = GetFont();
CRect rectText;
rectText.SetRectEmpty();
CDC *pDC = GetDC();
CFont *pOld = pDC->SelectObject(pFont);
pDC->DrawText("Ky", rectText, DT_CALCRECT | DT_LEFT);
UINT uiVClientHeight = rectText.Height();
pDC->SelectObject(pOld);
ReleaseDC(pDC);
//calculate NC area to center text.
GetClientRect(rectClient);
GetWindowRect(rectWnd);
ClientToScreen(rectClient);
UINT uiCenterOffset = (rectClient.Height() - uiVClientHeight) / 2;
UINT uiCY = (rectWnd.Height() - rectClient.Height()) / 2;
UINT uiCX = (rectWnd.Width() - rectClient.Width()) / 2;
rectWnd.OffsetRect(-rectWnd.left, -rectWnd.top);
m_rectNCTop = rectWnd;
m_rectNCTop.DeflateRect(uiCX, uiCY, uiCX, uiCenterOffset + uiVClientHeight + uiCY);
m_rectNCBottom = rectWnd;
m_rectNCBottom.DeflateRect(uiCX, uiCenterOffset + uiVClientHeight + uiCY, uiCX, uiCY);
lpncsp->rgrc[0].top +=uiCenterOffset;
lpncsp->rgrc[0].bottom -= uiCenterOffset;
lpncsp->rgrc[0].left +=uiCX;
lpncsp->rgrc[0].right -= uiCY;
}
void CEditVC::OnNcPaint()
{
Default();
CWindowDC dc(this);
CBrush Brush(GetSysColor(COLOR_WINDOW));
dc.FillRect(m_rectNCBottom, &Brush);
dc.FillRect(m_rectNCTop, &Brush);
}
UINT CEditVC::OnGetDlgCode()
{
if(m_rectNCTop.IsRectEmpty())
{
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
}
return CEdit::OnGetDlgCode();
}
我创建了新的CEdit继承控件,如下所示:
// Header File
CEditVC *mp_inputUser;
// Source File
OnInitDialog()
{
mp_inputUser = new CEditVC();
mp_inputUser->Create(WS_VISIBLE | WS_CHILD, CRect(10,10,100,100), this, 1);
}
但控件显示没有光标,如果我输入一个字符,它会将自己分成两部分并且行为非常奇怪。
可能导致这种情况的原因是什么?是否有更好的版本?
答案 0 :(得分:0)
鉴于此:
ClientToScreen(rectClient); // rectClient = {top=-2147483277 bottom=-2147483171 left=748 right=775}
你可以看到:
bottom-top = (-2147483171)-(-2147483277) = 106
和
right-left = (775)-(748) = 27
这些值看起来很熟悉:
GetClientRect(rectClient); // rectClient = {top=0 bottom=106 left=0 right=27}
因此,您拥有相同的矩形尺寸,左上角只是在主显示器左上角的上方和右侧移动。
如果您有多台显示器,请记住主显示器上方的显示器偏移量为top
。您的窗口是否位于主监视器上方的辅助监视器上?
答案 1 :(得分:0)
好的,所以我只是想让你知道,经过大量的调试后,我遇到了OnNcCalcSize
方法导致奇怪输出的问题。
在空的VS 2013 MFC项目中调用OnNcCalcSize方法3次。当没有设置对话框或CEditVC控件时,会发生前两个调用!这导致ClientRect为0,0,0,0。代码UINT uiCenterOffset = (rectClient.Height() - uiVClientHeight) / 2;
将无法按预期工作,因为计算出的uiVClientHeight
大于0并且正在从clientRect高度0
中减去。 UINT将溢出,每次进一步使用都将导致未定义的行为。
因此,在我提出的最新MFC项目中解决这个问题:
void CEditVC::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
CRect rectWnd, rectClient;
GetClientRect(rectClient);
// Workaround for calls with an empty Client Rect
if (rectClient.Height() == 0)
{
CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
return;
}
// Everything is back to default down here
CFont *pFont = GetFont();
CRect rectText;
rectText.SetRectEmpty();
CDC *pDC = GetDC();
CFont *pOld = pDC->SelectObject(pFont);
pDC->DrawText(L"Ky", rectText, DT_CALCRECT | DT_LEFT);
UINT uiVClientHeight = rectText.Height();
pDC->SelectObject(pOld);
ReleaseDC(pDC);
GetWindowRect(rectWnd);
ClientToScreen(rectClient);
UINT uiCenterOffset = (rectClient.Height() - uiVClientHeight) / 2;
UINT uiCY = (rectWnd.Height() - rectClient.Height()) / 2;
UINT uiCX = (rectWnd.Width() - rectClient.Width()) / 2;
rectWnd.OffsetRect(-rectWnd.left, -rectWnd.top);
m_rectNCTop = rectWnd;
m_rectNCTop.DeflateRect(uiCX, uiCY, uiCX, uiCenterOffset + uiVClientHeight + uiCY);
m_rectNCBottom = rectWnd;
m_rectNCBottom.DeflateRect(uiCX, uiCenterOffset + uiVClientHeight + uiCY, uiCX, uiCY);
lpncsp->rgrc[0].top += uiCenterOffset;
lpncsp->rgrc[0].bottom -= uiCenterOffset;
lpncsp->rgrc[0].left += uiCX;
lpncsp->rgrc[0].right -= uiCY;
}
所以我刚刚在顶部添加了if语句来检查函数是否处理空CRect,如果是这种情况,只需使用CEdit的基本方法。
我认为这个类是为类似VS6的旧C ++ MFC环境编写的,当时MFC或WinApi程序有点不同......