How to avoid EN_CHANGE notifications when sending WM_SETTEXT?

你。 提交于 2020-08-24 07:06:06

问题


I have a CEdit derived control that displays the string "N/A" when the undelying data is null. I recently added code to empty the control(SetWindowText("");) when it gains focus and set if back to "N/A"(SetWindowText("N/A")) when the focus is lost if the user left the control empty.

The only problem is that setting the window text to "" or "N/A" triggers EN_CHANGE, so my dialog thinks that the data has changed.

How can I avoid EN_CHANGE from being fired when calling SetWindowText (WM_SETTEXT)?

NOTES

-I know I can set the edit control to Multiline=TRUE but that's not accpectable for me.

-My application is MBCS so I can't use SetCueBanner

-I want an elegant solution. Setting the parent window to NULL temporarily is not an elegant solution.

EDIT:

-I want the solution to be in my custom control, not in each dialog

Thanks


回答1:


The way I've done it before (last time, like 20 minutes ago; in fact I was thinking about asking the same question), is by setting a flag. When I'm about to set the text programatically, I set the flag, and I check it in the EN_CHANGE handler:

void CMyDialog::MyFunction()
{    
    setEditTextProgramatically = true;  
    c_Edit.SetWindowText(_T("Whatever"));  
    setEditTextProgramatically = false;
}

void CMyDialog::OnEnChangeEdit()
{
    if (!setEditTextProgramatically)
    {
        // Do whatever you need to do
    }
}

I know it's not the most elegant solution, but it works, at least for me.

I've always wondered why MFC doesn't provide a way to distinguish user input from changes from code, but that's the way it is.




回答2:


I finally found a suitable solution to my problem.

First, I added a flag to my derived control's header file and I initialized it to false in the constructor

bool m_bNoEnChange;

I overrode the OnChildNotify in my derived control's header file and in the implementation, I checked for the WM_COMMAND message with the EN_CHANGE parameter. I then returned TRUE to prevent the message from being sent to the parent(dialog/page)

virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult);

BOOL CADEdit::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) 
{
    if(message == WM_COMMAND && HIWORD(wParam) == EN_CHANGE)
    {
        //If the flag is set, don't send the message to the parent window
        if(m_bNoEnChange)
            return TRUE;
    }

    return CEdit::OnChildNotify(message, wParam, lParam, pLResult);
}

Finally, when the control gains and loses focus, I wrapped the problematic SetWindowText with my flag

m_bNoEnChange = true;
SetWindowText(_T(""));
m_bNoEnChange = false;

This solution is the best in my case because I don't have to modify each dialog.




回答3:


You could disable (EnableWindow(FALSE) or send WM_ENABLE with param FALSE) the control prior to sending WM_SETTEXT then enabling it afterwards. That should prevent the EN_CHANGE

There is probably some more elegant method :p




回答4:


The below code uses a C++ 11 feature, but that can easily be changed.

HEADER

// CEditOptionalNotify.h
//
// CEdit derived class allowing the control's text value to be
// set without (optionally) causing EN_CHANGE processing.
//
#pragma once

class CEditOptionalNotify : public CEdit
{
    //DECLARE_DYNAMIC(CEditOptionalNotify)
    // Enable use of RUNTIME_CLASS macro and CObject::IsKindOf()

public:

    CEditOptionalNotify();
    virtual ~CEditOptionalNotify();

    enum class PerformOnChangeProcessing { No, Yes };
    void vSetText(const TCHAR* pText, PerformOnChangeProcessing e);

protected:

    afx_msg BOOL bConsiderEnChangeAsHandled();

    bool m_bChangeNotificationsEnabled;

    DECLARE_MESSAGE_MAP()
};

IMPLEMENTATION

// EditOptionalNotify.cpp : implementation file
//

#include "stdafx.h"
#include <EditOptionalNotify.h>

//IMPLEMENT_DYNAMIC(CEditOptionalNotify, CEdit)

CEditOptionalNotify::CEditOptionalNotify() :
    m_bChangeNotificationsEnabled(true)
{ 
}

CEditOptionalNotify::~CEditOptionalNotify()
{
}


BEGIN_MESSAGE_MAP(CEditOptionalNotify, CEdit)
    ON_CONTROL_REFLECT_EX(EN_CHANGE, bConsiderEnChangeAsHandled)
END_MESSAGE_MAP()


BOOL CEditOptionalNotify::bConsiderEnChangeAsHandled()
{
    return (m_bChangeNotificationsEnabled ? FALSE : TRUE);
}


void CEditOptionalNotify::vSetText(const TCHAR* pText, PerformOnChangeProcessing e)
{
    bool bChangeNotificationsDesired = (PerformOnChangeProcessing::No == e ? false : true);

    if (bChangeNotificationsDesired != m_bChangeNotificationsEnabled)
    {
        m_bChangeNotificationsEnabled = bChangeNotificationsDesired;
        CEdit::SetWindowText(pText);
        m_bChangeNotificationsEnabled = (bChangeNotificationsDesired ? false : true);
    }
    else
        CEdit::SetWindowText(pText);
}



回答5:


LRESULT CMainDlg::OnEnUpdateEditID(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{   
    //using static variable
    static bool isCodeChangeText = false;
    if(isCodeChangeText) 
        return 0;

    ……//Deal Window Text

    if(old == new)
        return 0; 

    int nSel = m_editPID.GetSel();//record cursor pos

    isCodeChangeText = true;
    m_editID.SetWindowText(new);
    m_editID.SetSel(nSel);
    isCodeChangeText = false;

    return 0;
}



回答6:


In case somebody else finds this discussion...

As Steven wrote UpdateData does not cause an EN_CHANGE being sent.

Under the hood MFC calls AfxSetWindowText with which one can specify one hwnd.



来源:https://stackoverflow.com/questions/11314082/how-to-avoid-en-change-notifications-when-sending-wm-settext

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!