0

この質問の最初の回答のコードを使用しています:編集ボックスでテキストを垂直方向に配置するにはどうすればよいですか? 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 つに分かれて非常に奇妙な動作をします。

何が原因でしょうか? これを行うためのより新しい(より良い)バージョンはありますか?

4

2 に答える 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オフセットがあることに注意してください。ウィンドウは、プライマリ モニターの上にあるセカンダリ モニターに配置されていますか?

于 2014-09-04T23:42:00.350 に答える
0

OnNcCalcSizeわかりましたので、多くのデバッグの後、メソッドが奇妙な出力をもたらす問題の背後にあることをお知らせしたいと思います。

OnNcCalcSize メソッドは、空の VS 2013 MFC プロジェクトで 3 回呼び出されます。最初の 2 つの呼び出しは、ダイアログまたは CEditVC コントロールがセットアップされていない場合に発生します。その結果、ClientRect は 0,0,0,0 になります。計算された値が 0 を超えており、 clientRect の高さから減算されているため、コードUINT uiCenterOffset = (rectClient.Height() - uiVClientHeight) / 2;は期待どおりに機能しません。UINT はオーバーフローし、さらに使用すると未定義の動作が発生します。uiVClientHeight0

したがって、私が思いついた最新の 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 を処理するかどうかを確認するために if ステートメントを一番上に追加し、その場合は CEdit の基本メソッドを使用します。

MFCまたはWinApiの手順が少し異なっていたとき、クラスはVS6のような古いC++ MFC環境用に書かれたと思います...

于 2014-09-08T22:22:08.070 に答える