2014-09-04 4 views
0

Я использую код в первом ответе на этот вопрос: How can we vertically align text in edit box?, чтобы центрировать текст в элементе управления 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

'top' -' bottom' = '106'. Какие еще операции вы выполняете на 'rectClient' между вызовом' GetClientRect' и 'ClientToScreen'? Вы уверены, что эти вызовы сделаны в правильном/одном окне? –

+0

Я не хотел публиковать код еще раз. Я связал ответ с кодом. Там вы можете увидеть, что происходит с clientRect. – Vinzenz

+0

Это просто делает его менее полезным для людей, которые ищут решение этой или подобных проблем. Это также требует, чтобы каждый, кто смотрит на ваш вопрос, следил за ссылкой, чтобы проверить код. Включите в свой вопрос _relevant_ части кода, и вы уменьшите количество усилий для каждого другого. –

ответ

0

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

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

Так что я просто добавил Условный оператор на вершине, чтобы проверить, если функция имеет дело с пустым CRect и если это в случае, просто используйте базовый метод CEdit.

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

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

bottom-top = 106 и right-left = 27 все еще странно, поскольку я создал CEditVC с прямым 'CRect (10,10,100,100)' ... Размеры были бы 90 для нижнего и правого Я думаю, левый. И у меня есть 2 монитора, но его показано на основном: / – Vinzenz