You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CEditEx调用SetWindowText后无法触发撤销(CTRL+Z)问题咨询

问题描述

我在派生的CEditEx类中使用:

SetWindowText(strText);

这段代码能正常更新控件内容,但无法支持撤销操作(CTRL + Z)。手动输入修改时撤销功能正常,请问有没有办法让这类代码修改也被纳入撤销追踪?

示例函数:

void CEditEx::Encode(const CString strTagOpen, const CString strTagClose)
{
    int iStartIndex{};
    int iEndIndex{};

    GetSel(iStartIndex, iEndIndex);
    if (iEndIndex > iStartIndex)
    {
        CString strText;
        GetWindowText(strText);

        strText.Insert(iStartIndex, strTagOpen);
        strText.Insert(iEndIndex + strTagOpen.GetLength(), strTagClose);

        SetWindowText(strText);

        SetSel(iStartIndex, iEndIndex + strTagOpen.GetLength() + strTagClose.GetLength());
    }
}
解决方案

要让代码修改支持撤销,核心是不要用SetWindowText直接替换全部内容,而是用控件认可的编辑操作接口,让它自动记录撤销步骤。

推荐方法:用ReplaceSel替代SetWindowText

ReplaceSel内部调用EM_REPLACESEL消息,这个操作会被编辑控件视为用户手动编辑,自动纳入撤销追踪。调整你的示例函数如下:

void CEditEx::Encode(const CString strTagOpen, const CString strTagClose)
{
    int iStartIndex{};
    int iEndIndex{};

    GetSel(iStartIndex, iEndIndex);
    if (iEndIndex > iStartIndex)
    {
        CString strSelected;
        GetSelText(strSelected);
        // 构造要替换的内容:标签+选中文本+标签
        CString strReplacement = strTagOpen + strSelected + strTagClose;
        
        // 替换选中内容,此操作会被记录到撤销栈
        ReplaceSel(strReplacement);

        // 调整选中范围,保持选中原来的文本部分
        int newStart = iStartIndex + strTagOpen.GetLength();
        int newEnd = newStart + strSelected.GetLength();
        SetSel(newStart, newEnd);
    }
}

原理说明

SetWindowText是直接覆盖控件的全部内容,属于“批量替换”,不会触发编辑控件的撤销追踪逻辑;而EM_REPLACESEL是模拟用户的选中替换操作,控件会自动把这个操作记录到撤销栈,所以CTRL+Z就能撤销。


内容的提问来源于stack exchange,提问作者Andrew Truckle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:20:29