【问题标题】:MFC C++ Derive from CEdit and derive GetWindowTextMFC C++ 派生自 CEdit 并派生 GetWindowText
【发布时间】:2018-04-08 10:14:00
【问题描述】:

我是从 CEdit 派生的,用于制作自定义控件。如果像 MFC 功能包控件(掩码、可浏览)一样,我可以更改 GetWindowText 以实际报告不是控件上通常显示的内容(例如,将数据在十六进制和十进制之间转换,然后返回字符串)。

在派生的 CEdit 中这可能吗?

【问题讨论】:

  • 或许可以,但确实不是个好主意。只需提供一个额外的功能来执行转换。还有,我要问你为什么要在 2017 年写 MFC 代码?
  • 遗留代码。我有一个很大的代码库,我想插入并用另一个替换我的一些编辑控件,我不需要更改任何控制代码,只需插入派生的代码,它可以让用户编辑为十进制或十六进制,但仍返回原始方式。怎么做?
  • @NeilButterworth:您似乎知道另一个支持 Windows 上本地桌面应用程序开发的框架。是哪一个?
  • MFC 类的源代码应该在"VS-path\VC\atlmfc\src\mfc" 中可用,位置取决于VS 版本。 CMFCMaskedEdit 拦截输入并检查掩码。
  • @ivanmoskalev:WTL 没有官方支持。 ATL 适用于 COM,但作为通用应用程序框架还不够。无论如何,这个问题是关于 MFC 的。建议不要使用 MFC 既不是答案,也不是有用的评论。

标签: c++ mfc mfc-feature-pack


【解决方案1】:

WM_GETTEXTWM_GETTEXTLENGTH 的消息映射条目添加到派生的CEdit 类:

BEGIN_MESSAGE_MAP( CMyEdit, CEdit )
    ON_WM_GETTEXT()
    ON_WM_GETTEXTLENGTH()
END_MESSAGE_MAP()

当我们覆盖这些消息时,我们需要一种方法来获取编辑控件的原始文本,而无需进行无休止的递归。为此我们可以直接调用名为DefWindowProc的默认窗口过程:

CStringW CMyEdit::GetTextInternal()
{
    CStringW text;
    LRESULT len = DefWindowProcW( WM_GETTEXTLENGTH, 0, 0 );
    if( len > 0 )
    {
        // WPARAM = len + 1 because the length must include the null terminator.
        len = DefWindowProcW( WM_GETTEXT, len + 1, reinterpret_cast<LPARAM>( text.GetBuffer( len ) ) );
        text.ReleaseBuffer( len );
    }
    return text;
}

以下方法获取原始窗口文本并对其进行转换。在这里一切皆有可能,包括在 hex 和 dec 之间转换的示例。为简单起见,我只是将文本括在破折号中。

CStringW CMyEdit::GetTransformedText()
{
    CStringW text = GetTextInternal();
    return L"--" + text + L"--";
}

现在是WM_GETTEXT 的实际处理程序,它将转换后的文本复制到输出缓冲区。

int CMyEdit::OnGetText( int cchDest, LPWSTR pDest )
{
    // Sanity checks
    if( cchDest <= 0 || ! pDest )
        return 0;

    CStringW text = GetTransformedText();

    // Using StringCchCopyExW() to make sure that we don't write outside of the bounds of the pDest buffer.
    // cchDest defines the maximum number of characters to be copied, including the terminating null character. 
    LPWSTR pDestEnd = nullptr;
    HRESULT hr = StringCchCopyExW( pDest, cchDest, text.GetString(), &pDestEnd, nullptr, 0 );
    // If our text is greater in length than cchDest - 1, the function will truncate the text and
    // return STRSAFE_E_INSUFFICIENT_BUFFER.
    if( SUCCEEDED( hr ) || hr == STRSAFE_E_INSUFFICIENT_BUFFER )
    {
        // The return value is the number of characters copied, not including the terminating null character. 
        return pDestEnd - pDest;
    }
    return 0;
}

WM_GETTEXTLENGTH 的处理程序不言自明:

UINT CMyEdit::OnGetTextLength()
{
    return GetTransformedText().GetLength();
}

【讨论】:

  • 这也会改变显示中编辑控件的内容!所以它会改变任何输出......这不起作用。
  • 好的。有趣的。所以编辑控件中的 OnPaint 直接使用内部缓冲区。奇怪的是,在 CMFCMaskedEdit 中显示了内部覆盖缓冲区(m_str)......但这接缝 OT。
【解决方案2】:

感谢大家为我指明正确的方向。我尝试了OnGetText,但问题似乎是我无法获取底层字符串,或者在调用GetWindowText(或者只是再次调用OnGetText......并且找不到底层字符串)时它会崩溃。

在看到他们在蒙面控制上做了什么之后,我做了一个更简单的答案。有什么缺点吗?它似乎没有引起任何问题或副作用......

直接从GetWindowText派生

void CConvertibleEdit::GetWindowText(CString& strString) const
{
    CEdit::GetWindowText(strString);

    ConvertibleDataType targetDataType;
    if (currentDataType == inputType)
    {

    }
    else
    {
        strString = ConvertEditType(strString, currentDataType, inputType);
    }
}

【讨论】:

  • 我无法获取底层字符串 - 使用参数 DefWindowProc 调用 WM_GETTEXTLENGTH 以获取字符串长度,然后再次使用 WM_GETTEXT 获取底层字符串。这样你就不会再调用你自己的处理程序了。如果这仍然不清楚,我可能会在我的答案中添加一些代码。
  • 顺便说一句,您在这里所做的称为屏蔽CWnd::GetWindowText(),因为该方法不是虚拟的。缺点是如果有人使用基类获取窗口文本,您的方法将不会被调用,这在使用 MFC 时很常见。想象一下有人枚举所有子窗口,他们将收到每个窗口的CWnd 指针。当他们调用CWnd::GetWindowText() 时,您的方法不会被调用。
  • 为了记录,那个掩码是在原来的掩码控件中完成的?如果您可以在示例中添加更多内容,以获取基础字符串。这是似乎缺少的主要部分。
  • 我已经添加了一个方法GetTextInternal() 可以做到这一点。
  • 所以我猜你的问题与CMFCMaskedEdit 无关,例如,它可以用来强制用户只输入整数。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
相关资源
最近更新 更多