You need to create a custom wxPGEditor that passes the button event based on the data stored in the property. WxPGProperty can store user data ( wxClientData ) that can be used to store the callback function.
First you must determine the signature of the function handler that will be called in the button event.
typedef bool (wxEvtHandler::*ButtonEventMethod)(wxPGProperty*);
The handler receives the attached property as a parameter and should return true if the property has been changed.
Now, to store the callback, a class based on wxClientData is required:
struct ButtonData : wxClientData { ButtonData(ButtonEventMethod method, wxEvtHandler* handler) : _method(method), _handler(handler) {} bool call(wxPGProperty* property) { return (*_handler.*_method)(property); } private: ButtonEventMethod _method; wxEvtHandler* _handler; };
This class simply stores the address of the method and the class to which it belongs. The editor will extract this object from the property and execute the call() method, which, in turn, performs a callback:
class ButtonEventEditor : public wxPGTextCtrlAndButtonEditor { protected: virtual bool OnEvent(wxPropertyGrid* propgrid, wxPGProperty* property, wxWindow* wnd_primary, wxEvent& event) const {
To wrap it, you can write a function to “bind” a method to a property:
void BindButton(wxPGProperty* property, ButtonEventMethod method, wxEvtHandler* handler) { property->SetClientObject(new ButtonData(method,handler)); }
And a macro to make it even easier:
#define BIND_BUTTON(property,method,handler,editor) \ property->SetEditor(editor); \ BindButton(property,static_cast<ButtonEventMethod>(method),handler)
Now you can bind member functions to properties:
// register the editor wxPGEditor* editor = propertyGrid->RegisterEditorClass(new ButtonEventEditor()); // create a property wxPGProperty* prop = propertyGrid->Append(new wxStringProperty("StringProperty")); // bind method foo to the property BIND_BUTTON(prop,&Frame::foo,this,editor);
And the foo method might look like this:
bool Frame::foo(wxPGProperty* p) { p->SetValue("foo"); return true; }
This is just an example demonstrating how wxPGProperty can store a callback (instead of creating multiple wxPGEditors). The callback store (here ButtonData) can be changed to store std::function or boost::function (which would require C ++ 11 or boost).
An alternative approach would be to store the callback information in an instance of wxPGEditor. However, this will require several instances of the editor, one for each callback function.
UPDATE
the actual "button" does not appear until the line field is clicked
The editor is not activated until a property is selected. You will need to create a custom wxPGProperty that returns a custom wxPGCellRenderer to take control of the property view (until it is edited). Unfortunately, this would create an illusion and require the user to double-click the button: first to activate the property (and the editor), and then the actual button. One solution that comes to mind is to either display text of type Click to edit in the cell, or a brief description of the value of the property.
Although it is possible that a custom property creates a button and ignores the editor system, the property grid is not designed to work this way, and this “hacking” can cause some problems. However, I added that hacking at the end.
there is a string field when I just want the button to occupy the whole property
This is just a side effect of the editor that I used as the base class for the example, and it's easy to change. Since wxTextCtrl is not required, just install the editor on wxPGEditor directly and create the controls yourself (one button):
class ButtonEventEditor : public wxPGEditor { protected: virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid, wxPGProperty* property, const wxPoint& pos, const wxSize& size) const {
with this method, it seems that there can only be one property editor
If you mean total: wxPropertyGrid::RegisterEditorClass just registers the editor with the property grid (the grid goes into the editor’s property and automatically deletes it when the property grid is destroyed). You can register as many editors as you want. You set the editor for a specific property, not for the entire property grid.
If you mean at the same time: yes, unfortunately, only one property editor can be active at any given time.
Hack
Let me finish this with the hack that I already mentioned.
First we need a custom wxPGCellRenderer to put the button in the property grid:
class ButtonMover : public wxPGCellRenderer { public:
Now we can create a custom property:
class ButtonProperty : public wxPGProperty { public:
By removing the need for an editor, you can now bind an event handler to a property:
propertyGrid->Append( new ButtonProperty( propertyGrid, // parent window wxCommandEventHandler(Frame::OnClick1), // event handler "Click me!") // button label ); propertyGrid->Append( new ButtonProperty( propertyGrid, wxCommandEventHandler(Frame::OnClick2), "Edit this!") );
And the handlers will look like this:
void OnClick1(wxCommandEvent& event) {