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.
This commit is contained in:
Richard
2026-07-20 20:12:44 +02:00
committed by Vadim Zeitlin
parent cb77a4e904
commit fbc474f4ed
3 changed files with 49 additions and 7 deletions
+13
View File
@@ -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
+12 -7
View File
@@ -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) )
+24
View File
@@ -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