Унаследованный элемент управления CEdit (для вертикально центрированного текста) ведет себя странно

Я использую код в первом ответе на этот вопрос: Как мы можем выровнять текст по вертикали в окне редактирования? центрировать текст в элементе управления 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);
}

Но элемент управления не показывает курсор, и если я набираю символ, он разделяется на 2 части и действует очень странно.

Что может вызвать это? Есть ли более поздняя (лучшая) версия этого?

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 смещение. Ваше окно находится на дополнительном мониторе, который находится над основным монитором?

0

Другие решения

Хорошо, так что я просто хочу, чтобы вы знали, что после многих отладок я решил, почему OnNcCalcSize метод приводит к странному выводу.

Метод OnNcCalcSize вызывается 3 раза в пустом проекте VS 2013 MFC. Первые два вызова происходят, когда нет даже диалогового окна или настройки CEditVC Control! В результате ClientRect будет 0,0,0,0. Код UINT uiCenterOffset = (rectClient.Height() - uiVClientHeight) / 2; НЕ будет работать, как ожидалось, как рассчитано uiVClientHeight что-то выше 0 и вычитается из высоты clientRect, которая 0, UINT будет переполнен, и каждое дальнейшее использование приведет к неопределенному поведению.

Поэтому, чтобы обойти эту проблему в последних проектах МФЦ, я придумал:

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.

Я полагаю, что класс был написан для старых сред C ++ MFC, таких как VS6, когда процедуры MFC или WinApi немного отличались …

0

По вопросам рекламы [email protected]