changed the code to be really sure that exactly one update event is sent when SetValue() is called

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30781 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2004-11-25 14:43:54 +00:00
parent 034e304169
commit 2c62dd25cd
2 changed files with 64 additions and 41 deletions

View File

@@ -247,9 +247,9 @@ protected:
int m_verRichEdit; int m_verRichEdit;
#endif // wxUSE_RICHEDIT #endif // wxUSE_RICHEDIT
// if true, SendUpdateEvent() will eat the next event (see comments in the // number of EN_UPDATE events sent by Windows when we change the controls
// code as to why this is needed) // text ourselves: we want this to be exactly 1
bool m_suppressNextUpdate; int m_updatesCount;
virtual wxVisualAttributes GetDefaultAttributes() const; virtual wxVisualAttributes GetDefaultAttributes() const;

View File

@@ -102,6 +102,36 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
#endif // wxUSE_RICHEDIT #endif // wxUSE_RICHEDIT
// a small class used to set m_updatesCount to 0 (to filter duplicate events if
// necessary) and to reset it back to -1 afterwards
class UpdatesCountFilter
{
public:
UpdatesCountFilter(int& count)
: m_count(count)
{
wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") );
m_count = 0;
}
~UpdatesCountFilter()
{
m_count = -1;
}
// return true if an event has been received
bool GotUpdate() const
{
return m_count == 1;
}
private:
int& m_count;
DECLARE_NO_COPY_CLASS(UpdatesCountFilter)
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// event tables and other macros // event tables and other macros
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -218,7 +248,7 @@ void wxTextCtrl::Init()
#endif // wxUSE_RICHEDIT #endif // wxUSE_RICHEDIT
m_privateContextMenu = NULL; m_privateContextMenu = NULL;
m_suppressNextUpdate = false; m_updatesCount = -1;
m_isNativeCaretShown = true; m_isNativeCaretShown = true;
m_isCaretAtEnd = true; m_isCaretAtEnd = true;
} }
@@ -751,13 +781,8 @@ wxTextCtrl::StreamIn(const wxString& value,
// the cast below is needed for broken (very) old mingw32 headers // the cast below is needed for broken (very) old mingw32 headers
eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn; eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn;
// we're going to receive 2 EN_CHANGE notifications if we got any selection // same problem as in DoWriteText(): we can get multiple events here
// (same problem as in DoWriteText()) UpdatesCountFilter ucf(m_updatesCount);
if ( selectionOnly && HasSelection() )
{
// so suppress one of them
m_suppressNextUpdate = true;
}
::SendMessage(GetHwnd(), EM_STREAMIN, ::SendMessage(GetHwnd(), EM_STREAMIN,
SF_TEXT | SF_TEXT |
@@ -765,6 +790,8 @@ wxTextCtrl::StreamIn(const wxString& value,
(selectionOnly ? SFF_SELECTION : 0), (selectionOnly ? SFF_SELECTION : 0),
(LPARAM)&eds); (LPARAM)&eds);
wxASSERT_MSG( ucf.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") );
if ( eds.dwError ) if ( eds.dwError )
{ {
wxLogLastError(_T("EM_STREAMIN")); wxLogLastError(_T("EM_STREAMIN"));
@@ -906,36 +933,20 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
#endif // wxUSE_RICHEDIT #endif // wxUSE_RICHEDIT
{ {
// in some cases we get 2 EN_CHANGE notifications after the SendMessage // in some cases we get 2 EN_CHANGE notifications after the SendMessage
// call below which is confusing for the client code and so should be // call (this happens for plain EDITs with EM_REPLACESEL and under some
// avoided // -- undetermined -- conditions with rich edit) and sometimes we don't
// // get any events at all (plain EDIT with WM_SETTEXT), so ensure that
// these cases are: (a) plain EDIT controls if EM_REPLACESEL is used // we generate exactly one of them by ignoring all but the first one in
// and there is a non empty selection currently and (b) rich text // SendUpdateEvent() and generating one ourselves if we hadn't got any
// controls in any case // notifications from Windows
if ( UpdatesCountFilter ucf(m_updatesCount);
#if wxUSE_RICHEDIT
IsRich() ||
#endif // wxUSE_RICHEDIT
(selectionOnly && HasSelection()) )
{
m_suppressNextUpdate = true;
}
::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT, ::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
0, (LPARAM)valueDos.c_str()); 0, (LPARAM)valueDos.c_str());
// OTOH, non rich text controls don't generate any events at all when if ( !ucf.GotUpdate() )
// we use WM_SETTEXT -- have to emulate them here
if ( !selectionOnly
#if wxUSE_RICHEDIT
&& !IsRich()
#endif // wxUSE_RICHEDIT
)
{ {
// Windows already sends an update event for single-line SendUpdateEvent();
// controls.
if ( m_windowStyle & wxTE_MULTILINE )
SendUpdateEvent();
} }
} }
} }
@@ -1801,13 +1812,25 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
bool wxTextCtrl::SendUpdateEvent() bool wxTextCtrl::SendUpdateEvent()
{ {
// is event reporting suspended? switch ( m_updatesCount )
if ( m_suppressNextUpdate )
{ {
// do process the next one case 0:
m_suppressNextUpdate = false; // remember that we've got an update
m_updatesCount++;
break;
return false; case 1:
// we had already sent one event since the last control modification
return false;
default:
wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") );
// fall through
case -1:
// we hadn't updated the control ourselves, this event comes from
// the user, don't need to ignore it nor update the count
break;
} }
wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());