CEdit框的NM_KILLFOCUS被调用两次

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CEdit框的NM_KILLFOCUS被调用两次相关的知识,希望对你有一定的参考价值。

我有一个CPropertyPage,我保存了一些编辑框,最值得注意的是基于CPropertySheet的选项卡控件,这是由一个名为CMainPage的类控制。此CPropertySheet选项卡控件由6个相同的CPropertyPages组成,根据是否勾选某些复选框显示它们。这些后续页面由一个名为CPage的单独类控制。

在这些页面上,我有一堆CEdit框,我写了一些数据。我希望以某种方式存储这些数据,而无需用户执行某些操作(例如连续单击保存按钮)。

到目前为止,我已经设法通过使用NM_KILLFOCUS宏捕获ON_NOTIFY消息。然后我将这些数据存储在属于CPage类的结构中。然后将此结构发送到CMainPage类,该类处理它并将数据存储在.xml文件中。

它看起来像这样(只显示相关功能):

CMainPage.h:

CPage::TPageData m_PageData[6];
CPage _page[6];

void SetPageData(int nPageId, CPage::TPageData::pageData);

CMainPage.cpp:

CMainPage::CMainPage()
{
    for(int i = 0; i < 6; i++)
    {
        _page[i].InitUI(this);
        _page[i].SetPageId(i);
    }
}

void
CMainPage::SetPageData(int nPageId, CPage::TPageData pageData)
{
    if( strlen(pageData.Edit1) > 0)
        m_PageData[nPageId].Edit1 = pageData.Edit1

    if( strlen(pageData.Edit2) > 0)
        m_PageData[nPageId].Edit2 = pageData.Edit2
}

CPage.h:

struct TPageData {
    CString Edit1,
    CString Edit2;
};

afx_msg void OnKillFocus(NMHDR *pNMHDR, LRESULT *pResult);
void InitUI(CWnd* pVME);
void SetPageId(int n);

TPageData  m_PageData;
int        m_PageId;
CMainPage* m_pMainPage;

CPage.cpp:

BEGIN_MESSAGE_MAP(Page, CPropertyPage)
    ON_NOTIFY(NM_KILLFOCUS, IDC_EDIT1, &Page::OnKillFocus)
    ON_NOTIFY(NM_KILLFOCUS, IDC_EDIT2, &Page::OnKillFocus)
END_MESSAGE_MAP()

// Called during initialization of each CPage object.
void
CPage::InitUI(CWnd* pVME)
{
    m_pMainPage = reinterpret_cast<CMainPage *>( pVME);
}

void
CPage::SetPageId(int n)
{
    m_PageId = n;
}

void
Page::OnKillFocus(NMHDR *pNMHDR, LRESULT *pResult)
{
    // Get text from edit box
    CString Str;
    GetDlgItem(pNMHDR->idFrom)->GetWindowText(Str);

    switch(pNMHDR->idFrom)
    {
    case IDC_EDIT1:
        {
            m_PageData.Edit1 = Str;
            m_pMainPage->SetPageData(m_PageId, m_PageData);
            break;
        }
    case IDC_EDIT2:
        {
            m_PageData.Edit2 = Str;
            m_pMainPage->SetPageData(m_PageId, m_PageData);
            break;
        }
    }
    *pResult = 1;
}

我现在遇到的问题是,NM_KILLFOCUS消息被调用两次,这意味着OnKillFocus()被调用两次。当我在不同的标签之间切换时,它会被更频繁地调用。我无法弄清楚是什么导致它,有人有任何建议吗?

编辑:在过去,我通过捕获NM_RETURN消息解决了这个问题。这意味着用户必须在完成输入后按Enter键。然而,用户很快就被这个解决方案所困扰,并要求我以不同的方式解决它,因此问题。

截至目前,我将所有数据从单个CPage转移到一个'TPageData'结构数组。一旦用户满意将所有数据传输到阵列,用户就会点击保存,然后将来自该阵列的所有数据解析到磁盘。加载数据时,所有操作都是反向完成的。

解决使用EN_CHANGE!看这里:

BEGIN_MESSAGE_MAP(CPage, CPropertyPage)
    ON_EN_CHANGE(IDC_EDIT1, &CPage::OnEnChange)
    ON_EN_CHANGE(IDC_EDIT1, &CPage::OnEnChange)
END_MESSAGE_MAP()

void
CPage::OnEnChange()
{
    CString Str;

    CWnd* pWnd = GetFocus();
    int iControlID = pWnd->GetDlgCtrlID();
    CEdit* pEditCtrl = (CEdit*)(pWnd);
    pEditCtrl->GetWindowText(Str);

    switch(iControlID)
    {
    case IDC_EDIT1:
        {
             m_PageData.Edit1 = Str;
             m_pMainPage->SetPageData(m_PageId, m_PageData);
             break;
        }
    case IDC_EDIT2:
        {
             m_PageData.Edit1 = Str;
             m_pMainPage->SetPageData(m_PageId, m_PageData);
             break;
         }
    }
}
答案

不是你想要的答案,但有些事情会浮现在脑海中:

  1. 您可以检查缓冲区是否被修改(例如,通过存储缓冲区的哈希)请参阅:https://en.cppreference.com/w/cpp/utility/hash
  2. 您可以使用空闲循环来检查+保存,而不是KillFocus事件。这可能是更适合自动保存的时间。见:https://docs.microsoft.com/en-us/cpp/mfc/reference/cwinapp-class?view=vs-2019#onidle

以上是关于CEdit框的NM_KILLFOCUS被调用两次的主要内容,如果未能解决你的问题,请参考以下文章

小 CEdit 控件的 CSpinButtonCtrl 绘图问题

CEdit使用(Edit Control控件)

事件绑定持有对象引用导致GC不回收对象

用WinAPI编程的时候,如何让一个编辑框在被点击后···

MFC的Dialogbox多行文本框(CEdit)有最大字符限制,默认最大显示长度是?怎么实现显示160KB大小的文件

MFC,是不是有任何方便的方法可以在其成员函数中获取编辑框的内容?