From fbc474f4edf913f2b5d09ab12c45c58fb959f0ec Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 8 Jul 2026 14:59:59 -0600 Subject: [PATCH] Track active wxGrid editor while editing Remember the editor instance used for the shown edit control and use it for visibility checks, painting, hiding, and saving. This keeps the edit control lifetime independent of later attribute changes, so replacing a cell or column editor while editing does not make wxGrid hide or save through the wrong editor. Add a regression covering replacement of a column bool editor while its cell is being edited. Fixes #21986. Closes #26670. --- include/wx/generic/grid.h | 13 +++++++++++++ src/generic/grid.cpp | 19 ++++++++++++------- tests/controls/gridtest.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index b7b287f6b3..9d072677e1 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -5,6 +5,7 @@ // Modified by: Santiago Palacios // Created: 1/08/1999 // Copyright: (c) Michael Bedward +// (c) 2026 wxWidgets development team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -2827,6 +2828,9 @@ protected: bool m_editable; // applies to whole grid bool m_cellEditCtrlEnabled; // is in-place edit currently shown? + // Editor used by the currently active edit control. + wxGridCellEditorPtr m_activeCellEditor; + TabBehaviour m_tabBehaviour; // determines how the TAB key behaves void Init(); // common part of all ctors @@ -3170,6 +3174,15 @@ private: ); } + // Return the editor actually being used by the current edit control. + wxGridCellEditorPtr GetActiveCellEditorPtr() const + { + if ( m_activeCellEditor ) + return m_activeCellEditor; + + return GetCurrentCellEditorPtr(); + } + // Show/hide the cell editor for the current cell unconditionally. // Return false if the editor was activated instead of being shown and also diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 1ee736f306..2e9a94cfca 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -5,6 +5,7 @@ // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios // Created: 1/08/1999 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) +// (c) 2026 wxWidgets development team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -2891,6 +2892,7 @@ wxGrid::~wxGrid() // otherwise we crash later when the editor tries to do something with the // half destroyed grid HideCellEditControl(); + m_activeCellEditor.reset(nullptr); // Must do this or ~wxScrollHelper will pop the wrong event handler SetTargetWindow(this); @@ -3397,7 +3399,7 @@ void wxGrid::CalcDimensions() // take into account editor if shown if ( IsCellEditControlShown() ) { - const wxRect rect = GetCurrentCellEditorPtr()->GetWindow()->GetRect(); + const wxRect rect = GetActiveCellEditorPtr()->GetWindow()->GetRect(); if ( rect.GetRight() > w ) w = rect.GetRight(); if ( rect.GetBottom() > h ) @@ -5150,7 +5152,7 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, ClearSelection(); if ( DoEnableCellEditControl(wxGridActivationSource::From(event)) ) - GetCurrentCellEditorPtr()->StartingClick(); + GetActiveCellEditorPtr()->StartingClick(); m_waitForSlowClick = false; } @@ -6594,7 +6596,7 @@ void wxGrid::OnChar( wxKeyEvent& event ) if ( DoEnableCellEditControl(wxGridActivationSource::From(event)) && !specialEditKey ) - editor->StartingKey(event); + GetActiveCellEditorPtr()->StartingKey(event); } else { @@ -6893,7 +6895,7 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) // Note: However, only if it is really _shown_, i.e. not hidden! if ( isCurrent && IsCellEditControlShown() ) { - attr->GetEditorPtr(this, row, col)->PaintBackground(dc, rect, *attr); + GetActiveCellEditorPtr()->PaintBackground(dc, rect, *attr); } else { @@ -8003,7 +8005,7 @@ bool wxGrid::IsCellEditControlShown() const if ( m_cellEditCtrlEnabled ) { - if ( wxGridCellEditorPtr editor = GetCurrentCellEditorPtr() ) + if ( wxGridCellEditorPtr editor = GetActiveCellEditorPtr() ) { if ( editor->IsCreated() ) { @@ -8022,6 +8024,7 @@ void wxGrid::ShowCellEditControl() if ( !IsVisible( m_currentCellCoords, false ) ) { m_cellEditCtrlEnabled = false; + m_activeCellEditor.reset(nullptr); return; } @@ -8082,6 +8085,7 @@ bool wxGrid::DoShowCellEditControl(const wxGridActivationSource& actSource) // before generating any events in case their user-defined handlers decide // to call EnableCellEditControl() to avoid reentrancy problems. m_cellEditCtrlEnabled = true; + m_activeCellEditor = editor; wxGridWindow *gridWindow = CellToGridWindow(row, col); @@ -8216,7 +8220,7 @@ void wxGrid::HideCellEditControl() void wxGrid::DoHideCellEditControl() { - wxGridCellEditorPtr editor = GetCurrentCellEditorPtr(); + wxGridCellEditorPtr editor = GetActiveCellEditorPtr(); const bool editorHadFocus = editor->GetWindow()->IsDescendant(FindFocus()); if ( editor->GetWindow()->GetParent() != m_gridWin ) @@ -8279,6 +8283,7 @@ void wxGrid::DoAcceptCellEditControl() DoHideCellEditControl(); DoSaveEditControlValue(); + m_activeCellEditor.reset(nullptr); } void wxGrid::SaveEditControlValue() @@ -8296,7 +8301,7 @@ void wxGrid::DoSaveEditControlValue() wxString oldval = GetCellValue(m_currentCellCoords); - wxGridCellEditorPtr editor = GetCurrentCellEditorPtr(); + wxGridCellEditorPtr editor = GetActiveCellEditorPtr(); wxString newval; if ( !editor->EndEdit(row, col, this, oldval, &newval) ) diff --git a/tests/controls/gridtest.cpp b/tests/controls/gridtest.cpp index e12d9dbe88..70ddabab96 100644 --- a/tests/controls/gridtest.cpp +++ b/tests/controls/gridtest.cpp @@ -4,6 +4,7 @@ // Author: Steven Lamerton // Created: 2010-06-25 // Copyright: (c) 2010 Steven Lamerton +// (c) 2026 wxWidgets development team /////////////////////////////////////////////////////////////////////////////// #include "testprec.h" @@ -1541,6 +1542,29 @@ TEST_CASE_METHOD(GridTestCase, "Grid::ReadOnly", "[grid]") #endif } +TEST_CASE_METHOD(GridTestCase, "Grid::ChangeEditorWhileEditing", "[grid]") +{ + wxGridCellAttr* attr = new wxGridCellAttr(); + attr->SetEditor(new wxGridCellBoolEditor); + attr->SetRenderer(new wxGridCellBoolRenderer); + m_grid->SetColAttr(0, attr); + + m_grid->SetCellValue(0, 0, "1"); + m_grid->SetGridCursor(0, 0); + m_grid->EnableCellEditControl(); + + REQUIRE(m_grid->IsCellEditControlShown()); + + attr = new wxGridCellAttr(); + attr->SetEditor(new wxGridCellBoolEditor); + attr->SetRenderer(new wxGridCellBoolRenderer); + m_grid->SetColAttr(0, attr); + + m_grid->DisableCellEditControl(); + + CHECK(!m_grid->IsCellEditControlShown()); +} + TEST_CASE_METHOD(GridTestCase, "Grid::WindowAsEditorControl", "[grid]") { #if wxUSE_UIACTIONSIMULATOR