The problem I have recently run into is that when using a wxGridCellChoiceEditor I seem to be able to only catch 2 events, the cell changing event and the cell changed event. The cell changed event isn't emitted until the cell loses focus to another cell. I want to validate and store data when the combobox closes but I need the grid's ID, Row, and Column. If the combobox closeup event is caught the ID is negative and not assigned until the grid cell is activated. So here's what I want to do, catch the combobox event in the grid class and get the index. If I can only get the selection then I can iterate through the array string used to load the cell choice editor to get this. Then I want to emit a custom event from the grid that will carry with it the grid's id, the index from the selection, the current row and current column in the grid. From there I will catch the event in the parent frame and based on the id and other values pulled from the event I will be able to store the data in the appropriate location of the appropriate array.
I've dealt with custom event handlers written inside control classes before, and I've logged the closeup events when they are emitted so I don't think that catching the combobox inside the grid class will be an issue.
I have no experience with writing my own events. I am just starting to look into this and have yet to begin writing the simple grid class that I will use to test all of this. So, does one of the samples do anything similar to this or does anybody know of a good reference I should look while I sift through search results and various class documentation? Has anybody already done something like this for cell choice editors?
Custom events with/from wxComboBox and wxGrid Topic is solved
-
- Knows some wx things
- Posts: 27
- Joined: Sun Jun 24, 2012 6:00 pm
Re: Custom events with/from wxComboBox and wxGrid
Why is wxEVT_GRID_CELL_CHANGING not sufficient for your purpose?
Use the source, Luke!
-
- Knows some wx things
- Posts: 27
- Joined: Sun Jun 24, 2012 6:00 pm
Re: Custom events with/from wxComboBox and wxGrid
using the event handler macro EVT_GRID_CMD_CELL_CHANGING(GRID_ID, myFrame::ConcGridCellChanging) the function ConcGridCellChanging does not get hit until you click off of the GridCellChoiceEditor. I want to have the data stored without the cell having to lose focus. I would have thought the changing event would have fired without losing focus but stepping through the debugger tells me that it doesn't.
Re: Custom events with/from wxComboBox and wxGrid
You can create your own cell editor, deriving from a wx's one. You must override some virtual methods:
You can learn more in the wx docs. And in the source code for wxGridCellEditor.
Code: Select all
class myGridCellChoiceEditor : public wxGridCellChoiceEditor
{
public:
......
virtual void Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler);
virtual wxGridCellEditor *Clone() const;
virtual void BeginEdit(int row, int col, wxGrid* grid);
virtual bool EndEdit(int row, int col, const wxGrid* grid, const wxString& oldval, wxString *newval);
virtual void ApplyEdit(int row, int col, wxGrid* grid);
.....
private:
wxDECLARE_NO_COPY_CLASS(myGridCellChoiceEditor );
};
Re: Custom events with/from wxComboBox and wxGrid
Hi,
Please consider using cell changing event for verification.
It is bad practice to do the verification with every single key press and user usually will be confused when you display errors on every key press.
Thank you.
Please consider using cell changing event for verification.
It is bad practice to do the verification with every single key press and user usually will be confused when you display errors on every key press.
Thank you.
-
- Knows some wx things
- Posts: 27
- Joined: Sun Jun 24, 2012 6:00 pm
Re: Custom events with/from wxComboBox and wxGrid
I accomplished it with the following:
in the .h
in the .cpp
in myFrame.cpp
I tried to strip this down to just what needs to be there for the specific case of creating a grid that will emit a useful event as soon as the GridCellChoiceEditor selection is made. Hopefully I haven't left any code remnants that would be specific to my project (other than those commented) and hopefully I haven't omitted anything as I was editing for this post.
in the .h
Code: Select all
#ifndef CUSTOM_GRID_H
#define CUSTOM_GRID_H
#include <vector>
#include "wx/grid.h"
wxDECLARE_EVENT(EVT_GRID_CHOICEEDITOR_CLOSED, wxGridEvent);
class Custom_Grid : public wxGrid
{
public:
Custom_Grid(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize,
long style=wxWANTS_CHARS, wxString name=wxGridNameStr);
virtual ~Custom_Grid();
//function to store information required to find combobox index and call SetCellChoiceEditor
void CreateCellChoiceEditor(int row, int col, size_t count, const wxString choices[]);
protected:
private:
wxWindowID m_id;
void OnComboBox(wxCommandEvent& evt);
void OnChoiceEditorClosed(wxGridEvent& evt);
std::vector<std::vector <wxString>> m_choices; //choices in the GridCellChoiceEditor loaded into vector
std::vector<std::vector <int>> m_choiceEditor; //row, column, index to keep track of the index
//for location in GridCellChoiceEditor string vector
//each GridCellChoiceEditor location has it's own array of strings
DECLARE_EVENT_TABLE()
};
#endif // CUSTOM_GRID_H
Code: Select all
#include "custom_grid.h"
wxDEFINE_EVENT(EVT_GRID_CHOICEEDITOR_CLOSED, wxGridEvent);
Custom_Grid::Custom_Grid(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, wxString name):
wxGrid(parent, id, pos, size, style, name)
{
//ctor
m_id = id; //store the grid's id <-- I didn't look closely to see if this was already done in base class
// Bind the new event
Bind(EVT_GRID_CHOICEEDITOR_CLOSED, &Custom_Grid::OnChoiceEditorClosed, this);
}
Custom_Grid::~Custom_Grid()
{
//dtor
}
void Custom_Grid::OnComboBox(wxCommandEvent& evt)
{
int row = m_currentCellCoords.GetRow(); //get the current row
int col = m_currentCellCoords.GetCol(); //get the current column
int index; // to store GridCellChoiceEditor index
bool found = false;
wxString tempstring;
//Save the current control's value otherwise the string returned by GetCellValue(row,col)
//will be the value before changing the choice
SaveEditControlValue();
wxString val = GetCellValue(row,col); //get the string value in the cell
wxGridEvent event(m_id, EVT_GRID_CHOICEEDITOR_CLOSED, this, row,col); //create a custom wxGridEvent
event.SetString(val); //set the string value in the event
while(!found)
{
//I'm sure this part can be immproved for performance
//The arrays I am dealing with are small and I do not
//have multiple columns with ChoiceEditors in them
//so the vectors aren't getting very large
for(size_t i=0; i<m_choiceEditor.size(); ++i)
{
if( !found )
{ //I'm sure this part can be immproved for performance
//The arrays I am dealing with are small and I do not
//have multiple columns with ChoiceEditors in them
//so the vectors aren't getting very large
if(m_choiceEditor.at(i).at(0) == row && m_choiceEditor.at(i).at(1)== col)
{
for(size_t j=0; j<m_choices.at(i).size(); ++j)
{
if(val.IsSameAs(m_choices.at(i).at(j)))
{
found = true;
if(j==0 || j==1)
{
index = 0;
//first the first two items are an empty string and
//a string to clear the row
}
else
{
index = (int)j-1;
//for consistency with legacy application the value
//I need is actually index-1. Change this for the
//value that you need relative to the actual index
}
}
}
}
}
}
}
event.SetInt(index); //set the Int value in the event
wxPostEvent(this, event); //EVT_GRID_CHOICEEDITOR_CLOSED emitted with string value, index, row, and column
//to be used upstream
}
void Custom_Grid::OnChoiceEditorClosed(wxGridEvent& evt)
{
// event can be caught here
// call Skip() to catch event elsewhere
evt.Skip();
}
void Custom_Grid::CreateCellChoiceEditor(int row, int col, size_t count, const wxString choices[])
{
int newEditor = m_choices.size()+1; //create a new index for m_choices vector
std::vector<int> temp;
temp.push_back(row);
temp.push_back(col);
temp.push_back(newEditor);
m_choiceEditor.push_back(temp); // store {row, col, index} in choiceEditor <-- that is probably a bad name
wxString tempstring;
std::vector<wxString> tempChoices;
for(size_t i = 0; i<count; ++i)
{
tempstring.Clear();
tempstring.Append(choices[i]);
tempChoices.push_back(tempstring);
}
m_choices.push_back(tempChoices); // store a vector of strings for this ChoiceEditor in a vector
SetCellEditor(row, col, new wxGridCellChoiceEditor(count,choices)); //use wxGrid::SetCellEditor to actually create
}
BEGIN_EVENT_TABLE(Custom_Grid,wxGrid)
EVT_COMBOBOX(wxID_ANY, Custom_Grid::OnComboBox)
END_EVENT_TABLE()
Code: Select all
#include "custom_grid.h"
...
//(insert lines below into constructor)
// Bind Custom Events
Bind(EVT_GRID_CHOICEEDITOR_CLOSED, &myFrame::OnChoiceEditorClosed, this);
...
-
- Knows some wx things
- Posts: 27
- Joined: Sun Jun 24, 2012 6:00 pm
Re: Custom events with/from wxComboBox and wxGrid
The cell changing event doesn't fire for wxGridCellChoiceEditor until the wxGridCellChoiceEditor is losing focus and since a cell (and therefore the ChoiceEditor) may not lose focus this seemed like the most reasonable way to proceed.ONEEYEMAN wrote:Hi,
Please consider using cell changing event for verification.
It is bad practice to do the verification with every single key press and user usually will be confused when you display errors on every key press.
Thank you.
As for verifying things with every single key press, in the case of something like a wxTextCtrl, I actually don't see the problem. Clearly you would like to keep invalid characters from being displayed. You don't have to display an error, you can use wxBell() when you veto the event so it should be obvious that the keystroke was invalid. Most text controls that I am dealing with display strings that represent a float value and in some cases I need to store a value and use it for a calculation that will live update. I take care of a couple of very simple and very generic validations of a keystroke before either stopping the event from propagating or calling Skip(). Real data validation is still handled by the application and my controls only accept numeric input with a single decimal point and the negative sign if the control value can be negative. When they lose focus they properly format the string for the format of the number by prepending or appending 0 as needed.
Now, I haven't dealt with char events in the grid for cells that should be formatted as floats but I know that I will be adding a check that will disallow '+' when it is entered.
Re: Custom events with/from wxComboBox and wxGrid
Hi,
I understand all this. I even agree that the wrong charactewrs should be filtered.
But data validation should be handled either on pressing "OK"/"Accept"/"Apply" button (in case of dialog) or on lose focus event (in case of the TLW).
This is not just because of the performance (event handlers should not execute a long function), but because 99.999999% of the applications do it this way and it will be very surprising for the user.
Thank you.
I understand all this. I even agree that the wrong charactewrs should be filtered.
But data validation should be handled either on pressing "OK"/"Accept"/"Apply" button (in case of dialog) or on lose focus event (in case of the TLW).
This is not just because of the performance (event handlers should not execute a long function), but because 99.999999% of the applications do it this way and it will be very surprising for the user.
Thank you.