wxGrid open cell editor after tab

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

wxGrid open cell editor after tab

Post by mael15 »

hi,
I want a cell editor wxGrid to open after the next cell has been chosen. surprisingly, this does not do it:

Code: Select all

void onGridTab(wxGridEvent &evt) {
	OutputDebugString(wxString::Format(wxT("grid tab on %i|%i\n"), evt.GetCol(), evt.GetRow()));
	if (evt.GetCol() < 2) {
		GoToCell(evt.GetRow(), evt.GetCol() + 1);
		ShowCellEditControl();
	}
	//evt.Skip();
}
do I have to do anything else?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Try EnableCellEditControl( true ) instead of ShowCellEditControl().
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Fri May 17, 2019 9:29 am Try EnableCellEditControl( true ) instead of ShowCellEditControl().
Thank you, with EnableCellEditControl it flashes up briefly in the one cell that has a wxGridCellChoiceEditor, nothing can be seen with the standard string cells. What might be wrong?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Which event triggers onGridTab? I tested it with the grid sample and a random menu entry and it worked for me.
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Fri May 17, 2019 12:42 pm Which event triggers onGridTab? I tested it with the grid sample and a random menu entry and it worked for me.

Code: Select all

Connect(wxEVT_GRID_TABBING, wxGridEventHandler(GridBase::onGridTab));
No good?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Try calling event.Skip() and then use CallAfter(...) to execute your code so that it's called after the default TAB behavior.
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Fri May 17, 2019 12:45 pm Try calling event.Skip() and then use CallAfter(...) to execute your code so that it's called after the default TAB behavior.
Thank you, this works only for string cells, not for float of choice. Same CallAfter works fine in a simple left click event with all kind of cells though:

Code: Select all

Connect(wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler(GridBase::onGridLeftClick));
		
void onGridLeftClick(wxGridEvent &evt) {
	CallAfter([this]() { EnableCellEditControl(true); });
	evt.Skip();
}
EDIT: tabs works for all controls BUT string when using Shift + Tab. Very weird.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Try catching only the wxEVT_GRID_SELECT_CELL event. (Just an idea, untested).
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Fri May 17, 2019 2:05 pm Try catching only the wxEVT_GRID_SELECT_CELL event. (Just an idea, untested).
Tried it but it did not work unfortunately.
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

a video would be easies to show this, I try to explain what happens.
I have these five columns:
string | choice | string | float | custom image
a single left click on each shows the editControl just as expected with this code:

Code: Select all

void onGridLeftClick(wxGridEvent &evt) {
	CallAfter([this]() { EnableCellEditControl(true); });
	evt.Skip();
}
I click on an entry in the first column, the editor appears, I hit TAB and this is when an editor appears in each column:
(yes) | no | yes | no | (no editor) // with TAB
no | yes | no | yes | (no editor) // with shift + TAB from the end
i have pretty much the same code for TAB as for left click:

Code: Select all

virtual void onGridTab(wxGridEvent &evt) {
OutputDebugString(wxString::Format(wxT("grid tab on %i|%i\n"), evt.GetRow(), evt.GetCol()));
CallAfter([this]() { 
	if (GetGridCursorCol() < 4) {
		EnableCellEditControl(true);
	}
});
evt.Skip();
}
how can I make the edit controls appear every time?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Can you strip together a running sample?
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Mon May 20, 2019 4:04 pm Can you strip together a running sample?
Yes, at least the tab behaviour can be seen, never mind the not working minus button at the end:

Code: Select all

#pragma once

#include <wx/frame.h>
#include <wx/app.h>
#include <wx/grid.h>

class MyGridCellButtonRenderer : public wxGridCellRenderer {
public:
	MyGridCellButtonRenderer() {}
	MyGridCellButtonRenderer(const MyGridCellButtonRenderer &other) {}
	MyGridCellButtonRenderer *Clone() const {
		return new MyGridCellButtonRenderer(*this);
	}

	void Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool isSelected) override;
	wxSize GetBestSize(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, int row, int col) override {
		return wxSize(13, 13);
	}
private:
};

class MyGrid : public wxGrid {
public:
	MyGrid(wxWindow *_par) : wxGrid(_par, wxID_ANY) {
		CreateGrid(0, 5);
		Connect(wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler(MyGrid::onGridLeftClick));
		Connect(wxEVT_GRID_TABBING, wxGridEventHandler(MyGrid::onGridTab));
	}

	void addRows(int addHowMany)
	{
		int rowCountBefore = GetNumberRows();
		AppendRows(addHowMany, false);
		int idxNewRow = 0;

		wxArrayString choices;
		choices.Add(wxT("A"));

		for (int idxNewRow = rowCountBefore; idxNewRow < GetNumberRows(); idxNewRow++) {
			// tiefe
			SetCellAlignment(idxNewRow, 0, wxALIGN_CENTRE, wxALIGN_CENTRE);
			SetCellOverflow(idxNewRow, 0, false);
			SetCellValue(idxNewRow, 0,wxT("10"));

			// code
			SetCellEditor(idxNewRow, 1, new wxGridCellChoiceEditor(choices));
			SetCellAlignment(idxNewRow, 1, wxALIGN_CENTRE, wxALIGN_CENTRE);
			SetCellOverflow(idxNewRow, 1, false);
			SetCellValue(idxNewRow, 1, wxT("I"));

			// position
			SetCellAlignment(idxNewRow, 2, wxALIGN_CENTRE, wxALIGN_CENTRE);
			SetCellOverflow(idxNewRow, 2, false);
			SetCellValue(idxNewRow, 2, wxT("123"));

			// amplitude
			wxString decPnt = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
			SetCellAlignment(idxNewRow, 3, wxALIGN_CENTRE, wxALIGN_CENTRE);
			SetCellOverflow(idxNewRow, 3, false);
			SetCellValue(idxNewRow, 3, wxString::Format(wxT("%4.2f"), 5.67f));

			// "-" button grafik
			SetCellRenderer(idxNewRow, 4, new MyGridCellButtonRenderer);
			SetReadOnly(idxNewRow, 4);
		}
	};

	void onGridLeftClick(wxGridEvent &evt) {
		CallAfter([this]() { EnableCellEditControl(true); });
		evt.Skip();
	}

	void onGridTab(wxGridEvent &evt) {
		OutputDebugString(wxString::Format(wxT("grid tab on %i|%i\n"), evt.GetRow(), evt.GetCol()));
		CallAfter([this]() {
			if (GetGridCursorCol() < 4) {
				EnableCellEditControl(true);
			}
		});
		evt.Skip();
	}
};

class MyFrame1 : public wxFrame 
{
public:
	MyFrame1( wxWindow* parent = NULL, 
		wxWindowID id = wxID_ANY, 
		const wxString& title = wxEmptyString, 
		const wxPoint& pos = wxDefaultPosition, 
		const wxSize& size = wxSize( 500,300 ), 
		long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
	~MyFrame1(){}

	MyGrid *grid = nullptr;

	wxLocale loc;
};

class MyApp : public wxApp {
	virtual bool OnInit();
};

Code: Select all

#include "app.h"
#include <wx/sizer.h>
#include <wx/grid.h>
#include "wx\renderer.h"

bool MyApp::OnInit() {
	MyFrame1 *mainFrame = new MyFrame1();
	mainFrame->Show();
	SetTopWindow(mainFrame);

	return TRUE;
}

wxIMPLEMENT_APP(MyApp);

MyFrame1::MyFrame1( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : 
	wxFrame( parent, id, title, pos, size, style )
{
	loc.Init(wxLanguage::wxLANGUAGE_GERMAN);

	SetSizer(new wxBoxSizer(wxVERTICAL));

	grid = new MyGrid(this);
	// Then we call CreateGrid to set the dimensions of the grid
	// (100 rows and 10 columns in this example)
	
	GetSizer()->Add(grid, 0, wxEXPAND);

	grid->addRows(2);

	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
	this->Centre( wxBOTH );
}

void MyGridCellButtonRenderer::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool isSelected)
{
	wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);

	// draw a check mark in the centre (ignoring alignment - TODO)
	wxSize size = GetBestSize(grid, attr, dc, row, col);

	// don't draw outside the cell
	wxCoord minSize = wxMin(rect.width, rect.height);
	if (size.x >= minSize || size.y >= minSize)
	{
		// and even leave (at least) 1 pixel margin
		size.x = size.y = minSize;
	}

	// draw a border around checkmark
	int vAlign, hAlign;
	attr.GetAlignment(&hAlign, &vAlign);

	wxRect rectBorder;
	if (hAlign == wxALIGN_CENTRE)
	{
		rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
		rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
		rectBorder.width = size.x;
		rectBorder.height = size.y;
	}
	else if (hAlign == wxALIGN_LEFT)
	{
		rectBorder.x = rect.x + 2;
		rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
		rectBorder.width = size.x;
		rectBorder.height = size.y;
	}
	else if (hAlign == wxALIGN_RIGHT)
	{
		rectBorder.x = rect.x + rect.width - size.x - 2;
		rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
		rectBorder.width = size.x;
		rectBorder.height = size.y;
	}

	bool value;
	if (grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
	{
		value = grid.GetTable()->GetValueAsBool(row, col);
	}
	else
	{
		wxString cellval(grid.GetTable()->GetValue(row, col));
		value = wxGridCellBoolEditor::IsTrueValue(cellval);
	}

	int flags = 0;

	wxRendererNative::Get().DrawPushButton(&grid, dc, rectBorder, flags);
	dc.SetPen(wxColour(74, 73, 66));
	dc.DrawLine(rectBorder.x + 4, rectBorder.y + 6, rectBorder.x + 9, rectBorder.y + 6);
}
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Unfortunately i didn't have enough time tonight to dig deep into it. But i traced through the code and the wxChoice editor definitely gets created and shown, but it closes again very quickly.

I think even with CallAfter, the call to EnableCellEditControl() comes too early in this case. The next step would be to find out which event causes the editor to close and delay the creation until then. But i didn't have enough time to do this today.

As a test, you could try to use a timer and call EnableCellEditControl() with a 0.5s delay. If that works, you know you're on the right track.
Use the source, Luke!
mael15
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 539
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxGrid open cell editor after tab

Post by mael15 »

doublemax wrote: Mon May 20, 2019 10:06 pm Unfortunately i didn't have enough time tonight to dig deep into it. But i traced through the code and the wxChoice editor definitely gets created and shown, but it closes again very quickly.

I think even with CallAfter, the call to EnableCellEditControl() comes too early in this case. The next step would be to find out which event causes the editor to close and delay the creation until then. But i didn't have enough time to do this today.

As a test, you could try to use a timer and call EnableCellEditControl() with a 0.5s delay. If that works, you know you're on the right track.
Thanx, this somehow works, but the focus jumps out of the grid when pressing tab in the choiceEditor. Do you think this is something to post as a wxwidgets bug? I mean the necessity to use CallAfter or a timer, not the focus thing.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid open cell editor after tab

Post by doublemax »

Thanx, this somehow works, but the focus jumps out of the grid when pressing tab in the choiceEditor.
That was just a test. The next step would be to find out what exactly make the choice editor disappear.
Do you think this is something to post as a wxwidgets bug? I mean the necessity to use CallAfter or a timer, not the focus thing.
You could try. But i wouldn't consider this a bug. You're just try to force a new behavior on wxGrid which it was not designed for :)
Use the source, Luke!
Post Reply