wxPropertyGrid is a specialized for editing properties such as strings, numbers, flagsets, fonts, and colours. It allows hierarchial, collapsible properties (via so-called categories that can hold child properties), sub-properties, and has strong wxVariant support.
Documentation for wxPython bindings: For a tutorial see the accompanied wxPython readme file and the test_propgrid.py sample. Otherwise, individual member functions should work very much the same as with the C++ wxWidgets, so you'll probably find wxPropertyGrid and wxPropertyGridManager class references handy.
Key Classes:
wxPropertyGrid
wxPropertyGridManager
wxPropertyGridEvent
Header files:
wx/propgrid/propgrid.h: Mandatory when using wxPropertyGrid.
wx/propgrid/advprops.h: For less often used property classes.
wx/propgrid/manager.h: Mandatory when using wxPropertyGridManager.
wx/propgrid/propdev.h: Mandatory when implementing custom property classes.
What's new in wxPropertyGrid 1.4?
Creating and Populating wxPropertyGrid
Categories
Tree-like Property Structure
wxEnumProperty and wxFlagsProperty
Specialized Properties
Iterating through a property container
More About Operating with Properties
Event Handling
Validating Property Values
Populating wxPropertyGrid Automatically
Customizing Individual Cell Appearance
Customizing Properties (without sub-classing)
Using wxPropertyGridManager
Subclassing wxPropertyGrid and wxPropertyGridManager
Miscellaneous Topics
Property Class Descriptions
Using wxPropertyGrid control
Design Notes
Creating New Properties
Creating Custom Property Editor
For people implementing custom property classes the differences are extensive, so if you are coming from wxPropertyGrid 1.2.x, it is recommended that you take a look.
// Necessary header file #include <wx/propgrid/propgrid.h> ... // Assumes code is in frame/dialog constructor // Construct wxPropertyGrid control wxPropertyGrid* pg = new wxPropertyGrid( this, // parent PGID, // id wxDefaultPosition, // position wxDefaultSize, // size // Some specific window styles - for all additional styles, // see Modules->PropertyGrid Window Styles wxPG_AUTO_SORT | // Automatic sorting after items added wxPG_SPLITTER_AUTO_CENTER | // Automatically center splitter until user manually adjusts it // Default style wxPG_DEFAULT_STYLE ); // Window style flags are at premium, so some less often needed ones are // available as extra window styles (wxPG_EX_xxx) which must be set using // SetExtraStyle member function. wxPG_EX_HELP_AS_TOOLTIPS, for instance, // allows displaying help strings as tooltips. pg->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
(for complete list of new window styles: Additional Window Styles)
wxPropertyGrid is usually populated with lines like this:
pg->Append( new wxStringProperty(wxT("Label"),wxT("Name"),wxT("Initial Value")) );
Naturally, wxStringProperty is a property class. Only the first function argument (label) is mandatory. Second one, name, defaults to label and, third, the initial value, to default value. If constant wxPG_LABEL is used as the name argument, then the label is automatically used as a name as well (this is more efficient than manually defining both as the same). Use of empty name is discouraged and will sometimes result in run-time error. Note that all property class constructors have quite similar constructor argument list.
To demonstrate other common property classes, here's another code snippet:
// Add int property pg->Append( new wxIntProperty(wxT("IntProperty"), wxPG_LABEL, 12345678) ); // Add float property (value type is actually double) pg->Append( new wxFloatProperty(wxT("FloatProperty"), wxPG_LABEL, 12345.678) ); // Add a bool property pg->Append( new wxBoolProperty(wxT("BoolProperty"), wxPG_LABEL, false) ); // A string property that can be edited in a separate editor dialog. pg->Append( new wxLongStringProperty(wxT("LongStringProperty"), wxPG_LABEL, wxT("This is much longer string than the ") wxT("first one. Edit it by clicking the button."))); // String editor with dir selector button. pg->Append( new wxDirProperty(wxT("DirProperty"), wxPG_LABEL, ::wxGetUserHome()) ); // wxArrayStringProperty embeds a wxArrayString. pg->Append( new wxArrayStringProperty(wxT("Label of ArrayStringProperty"), wxT("NameOfArrayStringProp"))); // A file selector property. pg->Append( new wxFileProperty(wxT("FileProperty"), wxPG_LABEL, wxEmptyString) ); // Extra: set wildcard for file property (format same as in wxFileDialog). pg->SetPropertyAttribute( wxT("FileProperty"), wxPG_FILE_WILDCARD, wxT("All files (*.*)|*.*") );
Operations on properties should be done either via wxPropertyGrid's (or wxPropertyGridManager's) methods, or by acquiring pointer to a property (Append returns a wxPGProperty* or wxPGId, which is typedef for same), and then calling its method. Note however that property's methods generally do not automatically update grid graphics.
Property container functions operating on properties, such as SetPropertyValue or DisableProperty, all accept a special wxPGPropArg, argument which can automatically convert name of a property to a pointer. For instance:
// A file selector property. wxPGPropety* p = pg->Append( new wxFileProperty(wxT("FileProperty"), wxPG_LABEL, wxEmptyString) ); // Valid: Set wildcard by name pg->SetPropertyAttribute( wxT("FileProperty"), wxPG_FILE_WILDCARD, wxT("All files (*.*)|*.*") ); // Also Valid: Set wildcard by ptr pg->SetPropertyAttribute( p, wxPG_FILE_WILDCARD, wxT("All files (*.*)|*.*") );
Using pointer is faster, since it doesn't require hash map lookup. Anyway, you can allways get property pointer (wxPGProperty*) as Append/Insert return value, or by calling GetPropertyByName.
Below are samples for using some of the more commong operations. See wxPropertyGridInterface and wxPropertyGrid class references for complete list.
// wxPGId is a short-hand for wxPGProperty*. Let's use it this time. wxPGId id = pg->GetPropertyByName( wxT("MyProperty") ); // There are many overloaded versions of this method, of which each accept // different type of value. pg->SetPropertyValue( wxT("MyProperty"), 200 ); // Setting a string works for all properties - conversion is done // automatically. pg->SetPropertyValue( id, wxT("400") ); // Getting property value as wxVariant. wxVariant value = pg->GetPropertyValue( wxT("MyProperty") ); // Getting property value as String (again, works for all typs). wxString value = pg->GetPropertyValueAsString( id ); // Getting property value as int. Provokes a run-time error // if used with property which value type is not "long". long value = pg->GetPropertyValueAsLong( wxT("MyProperty") ); // Set new name. pg->SetPropertyName( wxT("MyProperty"), wxT("X") ); // Set new label - we need to use the new name. pg->SetPropertyLabel( wxT("X"), wxT("New Label") ); // Disable the property. It's text will appear greyed. // This is probably the closest you can get if you want // a "read-only" property. pg->DisableProperty( id );
When category is added at the top (i.e. root) level of the hierarchy, it becomes a *current category*. This means that all other (non-category) properties after it are automatically added to it. You may add properties to specific categories by using wxPropertyGrid::Insert or wxPropertyGrid::AppendIn.
Category code sample:
// One way to add category (similar to how other properties are added) pg->Append( new wxPropertyCategory(wxT("Main")) ); // All these are added to "Main" category pg->Append( new wxStringProperty(wxT("Name")) ); pg->Append( new wxIntProperty(wxT("Age"),wxPG_LABEL,25) ); pg->Append( new wxIntProperty(wxT("Height"),wxPG_LABEL,180) ); pg->Append( new wxIntProperty(wxT("Weight")) ); // Another one pg->Append( new wxPropertyCategory(wxT("Attrikbutes")) ); // All these are added to "Attributes" category pg->Append( new wxIntProperty(wxT("Intelligence")) ); pg->Append( new wxIntProperty(wxT("Agility")) ); pg->Append( new wxIntProperty(wxT("Strength")) );
wxPGId pid = pg->Append( new wxStringProperty(wxT("Car"),wxPG_LABEL,wxT("<composed>")) ); pg->AppendIn( pid, new wxStringProperty(wxT("Model"), wxPG_LABEL, wxT("Lamborghini Diablo SV")) ); pg->AppendIn( pid, new wxIntProperty(wxT("Engine Size (cc)"), wxPG_LABEL, 5707) ); wxPGId speedId = pg->AppendIn( pid, new wxStringProperty(wxT("Speeds"),wxPG_LABEL,wxT("<composed>")) ); pg->AppendIn( speedId, new wxIntProperty(wxT("Max. Speed (mph)"),wxPG_LABEL,290) ); pg->AppendIn( speedId, new wxFloatProperty(wxT("0-100 mph (sec)"),wxPG_LABEL,3.9) ); pg->AppendIn( speedId, new wxFloatProperty(wxT("1/4 mile (sec)"),wxPG_LABEL,8.6) ); // Make sure the child properties can be accessed correctly pg->SetPropertyValue( wxT("Car.Speeds.Max. Speed (mph)"), 300 ); pg->AppendIn( pid, new wxIntProperty(wxT("Price ($)"), wxPG_LABEL, 300000) ); // Displayed value of "Car" property is now: // "Lamborghini Diablo SV; [300; 3.9; 8.6]; 300000"
Creating wxEnumProperty is more complex than those described earlier. You have to provide list of constant labels, and optionally relevant values (if label indexes are not sufficient).
A very simple example:
// // Using wxArrayString // wxArrayString arrDiet; arr.Add(wxT("Herbivore")); arr.Add(wxT("Carnivore")); arr.Add(wxT("Omnivore")); pg->Append( new wxEnumProperty(wxT("Diet"), wxPG_LABEL, arrDiet) ); // // Using wxChar* array // const wxChar* arrayDiet[] = { wxT("Herbivore"), wxT("Carnivore"), wxT("Omnivore"), NULL }; pg->Append( new wxEnumProperty(wxT("Diet"), wxPG_LABEL, arrayDiet) );
Here's extended example using values as well:
// // Using wxArrayString and wxArrayInt // wxArrayString arrDiet; arr.Add(wxT("Herbivore")); arr.Add(wxT("Carnivore")); arr.Add(wxT("Omnivore")); wxArrayInt arrIds; arrIds.Add(40); arrIds.Add(45); arrIds.Add(50); // Note that the initial value (the last argument) is the actual value, // not index or anything like that. Thus, our value selects "Omnivore". pg->Append( new wxEnumProperty(wxT("Diet"), wxPG_LABEL, arrDiet, arrIds, 50)); // // Using wxChar* and long arrays // const wxChar* array_diet[] = { wxT("Herbivore"), wxT("Carnivore"), wxT("Omnivore"), NULL }; long array_diet_ids[] = { 40, 45, 50 }; // Value can be set from string as well pg->Append( new wxEnumProperty(wxT("Diet"), wxPG_LABEL, array_diet, array_diet_ids);
wxPGChoices is a class where wxEnumProperty, and other properties which require label storage, actually stores strings and values. It is used to facilitiate reference counting, and therefore recommended way of adding items when multiple properties share the same set.
You can use wxPGChoices directly as well, filling it and then passing it to the constructor. Infact, if you wish to display bitmaps next to labels, your best choice is to use this approach.
wxPGChoices chs; chs.Add(wxT("Herbivore"),40); chs.Add(wxT("Carnivore"),45); chs.Add(wxT("Omnivore"),50); // Let's add an item with bitmap, too chs.Add(wxT("None of the above"), wxBitmap(), 60); // Note: you can add even whole arrays to wxPGChoices pg->Append( new wxEnumProperty(wxT("Diet"), wxPG_LABEL, chs) ); // Add same choices to another property as well - this is efficient due // to reference counting pg->Append( new wxEnumProperty(wxT("Diet 2"), wxPG_LABEL, chs) );
If you later need to change choices used by a property, there is function for that as well.
// // Example 1: Add one extra item wxPGChoices& choices = pg->GetPropertyChoices(wxT("Diet")); choices.Add(wxT("Custom"),55); // // Example 2: Replace all the choices wxPGChoices chs; chs.Add(wxT("<No valid items yet>"),0); pg->SetPropertyChoices(wxT("Diet"),chs);
If you want to create your enum properties with simple (label,name,value) constructor, then you need to create a new property class using one of the supplied macro pairs. See Creating New Properties for details.
wxEditEnumProperty is works exactly like wxEnumProperty, except is uses non-readonly combobox as default editor, and value is stored as string when it is not any of the choices.
wxFlagsProperty is similar:
const wxChar* flags_prop_labels[] = { wxT("wxICONIZE"), wxT("wxCAPTION"), wxT("wxMINIMIZE_BOX"), wxT("wxMAXIMIZE_BOX"), NULL }; // this value array would be optional if values matched string indexes long flags_prop_values[] = { wxICONIZE, wxCAPTION, wxMINIMIZE_BOX, wxMAXIMIZE_BOX }; pg->Append( new wxFlagsProperty(wxT("Window Style"), wxPG_LABEL, flags_prop_labels, flags_prop_values, wxDEFAULT_FRAME_STYLE) );
wxFlagsProperty can use wxPGChoices just the same way as wxEnumProperty (and also custom property classes can be created with similar macro pairs). Note: When changing "choices" (ie. flag labels) of wxFlagsProperty, you will need to use SetPropertyChoices - otherwise they will not get updated properly.
// Necessary extra header file #include <wx/propgrid/advprops.h> ... // Date property. pg->Append( new wxDateProperty(wxT("MyDateProperty"), wxPG_LABEL, wxDateTime::Now()) ); // Image file property. Wildcard is auto-generated from available // image handlers, so it is not set this time. pg->Append( new wxImageFileProperty(wxT("Label of ImageFileProperty"), wxT("NameOfImageFileProp")) ); // Font property has sub-properties. Note that we give window's font as // initial value. pg->Append( new wxFontProperty(wxT("Font"), wxPG_LABEL, GetFont()) ); // Colour property with arbitrary colour. pg->Append( new wxColourProperty(wxT("My Colour 1"), wxPG_LABEL, wxColour(242,109,0) ) ); // System colour property. pg->Append( new wxSystemColourProperty(wxT("My SysColour 1"), wxPG_LABEL, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) ); // System colour property with custom colour. pg->Append( new wxSystemColourProperty(wxT("My SysColour 2"), wxPG_LABEL, wxColour(0,200,160) ) ); // Cursor property pg->Append( new wxCursorProperty(wxT("My Cursor"), wxPG_LABEL, wxCURSOR_ARROW));
wxPropertyGridIterator it; for ( it = pg->GetIterator(); !it.AtEnd(); it++ ) { wxPGProperty* p = *it; // Do something with the property }
As expected there is also a const iterator:
wxPropertyGridConstIterator it; for ( it = pg->GetIterator(); !it.AtEnd(); it++ ) { const wxPGProperty* p = *it; // Do something with the property }
You can give some arguments to GetIterator to determine which properties get automatically filtered out. For complete list of options, see List of Property Iterator Flags. GetIterator() also accepts other arguments. See wxPropertyGridInterface::GetIterator() for details.
This example reverse-iterates through all visible items:
wxPropertyGridIterator it; for ( it = pg->GetIterator(wxPG_ITERATE_VISIBLE, wxBOTTOM); !it.AtEnd(); it-- ) { wxPGProperty* p = *it; // Do something with the property }
wxPython Note: Instead of ++ operator, use Next() method, and instead of operator, use GetProperty() method.
GetIterator() only works with wxPropertyGrid and the individual pages of wxPropertyGridManager. In order to iterate through an arbitrary property container, you need to use wxPropertyGridInterface::GetVIterator(). Note however that this virtual iterater is limited to forward iteration.
wxPGVIterator it; for ( it = manager->GetVIterator(); !it.AtEnd(); it.Next() ) { wxPGProperty* p = it.GetProperty(); // Do something with the property }
wxPGId id = pg->GetSelection(); if ( id ) { // Get name of property const wxString& name = pg->GetPropertyName( id ); // If type is not correct, GetColour() method will produce run-time error if ( pg->GetPropertyValueType() == wxT("wxColourPropertyValue") ) ) { wxColourPropertyValue* pcolval = wxDynamicCast(pg->GetPropertyValueAsWxObjectPtr(id), wxColourPropertyValue); // Report value wxString text; if ( pcolval->m_type == wxPG_CUSTOM_COLOUR ) text.Printf( wxT("It is custom colour: (%i,%i,%i)"), (int)pcolval->m_colour.Red(), (int)pcolval->m_colour.Green(), (int)pcolval->m_colour.Blue()); else text.Printf( wxT("It is wx system colour (number=%i): (%i,%i,%i)"), (int)pcolval->m_type, (int)pcolval->m_colour.Red(), (int)pcolval->m_colour.Green(), (int)pcolval->m_colour.Blue()); wxMessageBox( text ); } }
// This is a static method that initializes *all* builtin type handlers // available, including those for wxColour and wxFont. Refers to *all* // included properties, so when compiling with static library, this // method may increase the executable size significantly. pg->InitAllTypeHandlers(); // Get contents of the grid as a wxVariant list wxVariant all_values = pg->GetPropertyValues(); // Populate the list with values. If a property with appropriate // name is not found, it is created according to the type of variant. pg->SetPropertyValues( my_list_variant ); // In order to get wxObject ptr from a variant value, // wxGetVariantCast(VARIANT,CLASSNAME) macro has to be called. // Like this: wxVariant v_txcol = pg->GetPropertyValue(wxT("Text Colour")); const wxColour& txcol = wxGetVariantCast(v_txcol,wxColour);
For complete list of event types, see wxPropertyGrid class reference.
The custom event class, wxPropertyGridEvent, has methods to directly access the property that triggered the event.
Here's a small sample:
// Portion of an imaginary event table BEGIN_EVENT_TABLE(MyForm, wxFrame) ... // This occurs when a property value changes EVT_PG_CHANGED( PGID, MyForm::OnPropertyGridChange ) ... END_EVENT_TABLE() void MyForm::OnPropertyGridChange( wxPropertyGridEvent& event ) { wxPGProperty *property = event.GetProperty(); // It may be NULL if ( !property ) return; // Get name of changed property const wxString& name = property->GetName(); // Get resulting value wxVariant value = property->GetValue(); }
Another event type you might find useful is EVT_PG_CHANGING, which occurs just prior property value is being changed by user. You can acquire pending value using wxPropertyGridEvent::GetValue(), and if it is not acceptable, call wxPropertyGridEvent::Veto() to prevent the value change from taking place.
// Portion of an imaginary event table BEGIN_EVENT_TABLE(MyForm, wxFrame) ... // This occurs when a property value changes EVT_PG_CHANGING( PGID, MyForm::OnPropertyGridChanging ) ... END_EVENT_TABLE() void MyForm::OnPropertyGridChanging( wxPropertyGridEvent& event ) { wxPGProperty* property = event.GetProperty(); if ( property == m_pWatchThisProperty ) { // GetValue() returns the pending value, but is only // supported by wxEVT_PG_CHANGING. if ( event.GetValue().GetString() == g_pThisTextIsNotAllowed ) { event.Veto(); return; } } }
Second, you can subclass a property and override wxPGProperty::ValidateValue(), or handle wxEVT_PG_CHANGING for the same effect. Both of these methods do not actually prevent user from temporarily entering invalid text, but they do give you an opportunity to warn the user and block changed value from being committed in a property.
Various validation failure options can be controlled globally with wxPropertyGrid::SetValidationFailureBehavior(), or on an event basis by calling wxEvent::SetValidationFailureBehavior(). Here's a code snippet of how to handle wxEVT_PG_CHANGING, and to set custom failure behaviour and message.
void MyFrame::OnPropertyGridChanging(wxPropertyGridEvent& event) { wxPGProperty* property = event.GetProperty(); // You must use wxPropertyGridEvent::GetValue() to access // the value to be validated. wxVariant pendingValue = event.GetValue(); if ( property->GetName() == wxT("Font") ) { // Make sure value is not unspecified if ( !pendingValue.IsNull() ) { wxFont font << pendingValue; // Let's just allow Arial font if ( font.GetFaceName() != wxT("Arial") ) { event.Veto(); event.SetValidationFailureBehavior(wxPG_VFB_STAY_IN_PROPERTY | wxPG_VFB_BEEP | wxPG_VFB_SHOW_MESSAGE); } } } }
In addition, it is possible to control these characteristics for wxPGChoices list items. See wxPGChoices::Item() and wxPGChoiceEntry class reference for more info.
Validator will work just like in wxWidgets (ie. editorControl->SetValidator(validator) is called).
Following example changes wxColourProperty's editor from default Choice to TextCtrlAndButton. wxColourProperty has its internal event handling set up so that button click events of the button will be used to trigger colour selection dialog.
wxPGId colProp = pg->Append(wxColourProperty(wxT("Text Colour"))); pg->SetPropertyEditor(colProp,wxPG_EDITOR(TextCtrlAndButton));
Naturally, creating and setting custom editor classes is a possibility as well. For more information, see wxPGEditor class reference.
Attribute names are strings and values wxVariant. Arbitrary names are allowed inorder to store user values. Constant equivalents of all attribute string names are provided. Some of them are defined as cached strings, so using constants can provide for smaller binary size.
For complete list of attributes, see Property Attributes.
pg->SetPropertyAttributeAll(wxPG_BOOL_USE_CHECKBOX,true);
wxPropertyGridManager inherits from wxPropertyGridInterface, and as such it has most property manipulation functions. However, only some of them affect properties on all pages (eg. GetPropertyByName() and ExpandAll()), while some (eg. Append()) only apply to the currently selected page.
To operate explicitly on properties on specific page, use wxPropertyGridManager::GetPage() to obtain pointer to page's wxPropertyGridPage object.
Visual methods, such as SetCellBackgroundColour and GetNextVisible are only available in wxPropertyGrid. Use wxPropertyGridManager::GetGrid() to obtain pointer to it.
Iteration methods will not work in wxPropertyGridManager. Instead, you must acquire the internal grid (GetGrid()) or wxPropertyGridPage object (GetPage()).
wxPropertyGridManager constructor has exact same format as wxPropertyGrid constructor, and basicly accepts same extra window style flags (albeit also has some extra ones).
Here's some example code for creating and populating a wxPropertyGridManager:
wxPropertyGridManager* pgMan = new wxPropertyGridManager(this, PGID, wxDefaultPosition, wxDefaultSize, // These and other similar styles are automatically // passed to the embedded wxPropertyGrid. wxPG_BOLD_MODIFIED|wxPG_SPLITTER_AUTO_CENTER| // Include toolbar. wxPG_TOOLBAR | // Include description box. wxPG_DESCRIPTION | // Include compactor. wxPG_COMPACTOR | // Plus defaults. wxPGMAN_DEFAULT_STYLE ); wxPropertyGridPage* page; pgMan->AddPage(wxT("First Page")); page = pgMan->GetLastPage(); page->Append( new wxPropertyCategory(wxT("Category A1")) ); page->Append( new wxIntProperty(wxT("Number"),wxPG_LABEL,1) ); page->Append( new wxColourProperty(wxT("Colour"),wxPG_LABEL,*wxWHITE) ); pgMan->AddPage(wxT("Second Page")); page = pgMan->GetLastPage(); page->Append( wxT("Text"),wxPG_LABEL,wxT("(no text)") ); page->Append( new wxFontProperty(wxT("Font"),wxPG_LABEL) );
Please note that the wxPropertyGridPage itself only sports subset of wxPropertyGrid API (but unlike manager, this include item iteration). Naturally it inherits from wxPropertyGridMethods and wxPropertyGridState.
pg->SetPropertyAttribute(wxT("MyFlagsProperty"),wxPG_BOOL_USE_CHECKBOX,true,wxPG_RECURSE);
Because of this, you may find it useful, in some apps, to call wxPropertyGrid::CommitChangesFromEditor() just before you need to do any computations based on property grid values. Note that CommitChangesFromEditor() will dispatch wxEVT_PG_CHANGED with ProcessEvent, so any of your event handlers will be called immediately.
Events wxEVT_PG_LABEL_EDIT_BEGIN and wxEVT_PG_LABEL_EDIT_ENDING are generated as appropriate. You can veto these events to prevent label editor from (dis)appearing.
Override wxSystemColourProperty::ColourToString() to redefine how colours are printed as strings.
Override wxSystemColourProperty::GetCustomColourIndex() to redefine location of the item that triggers colour picker dialog (default is last).
Override wxSystemColourProperty::GetColour() to determine which colour matches which choice entry.
wxPG_INCLUDE_MANAGER: Defines as 0 to exclude wxPropertyGridManager from compilation.
wxPG_INCLUDE_ADVPROPS: Defines as 0 to exclude properties and editors defined in advprops.h and advprops.cpp.
wxPG_USE_WXMODULE: Define as 0 to not use wxModule to manage global variables. This may be needed in cases where wxPropertyGrid is linked as a plugin DLL, or when wxPropertyGrid is linked statically in a DLL.
WXMAKINGLIB_PROPGRID: Define if you are linking wxPropertyGrid statically but wxWidgets itself is DLL.
WXMAKINGDLL_PROPGRID: Define when building wxPropertyGrid as a DLL. This should be automatically defined correctly by the Bakefile-generated makefiles.
wxPG_USE_STL: Define as 1 to let wxPropertyGrid use STL classes in API as much as possible. Default value equals wxUSE_STL.
wxPG_COMPATIBILITY_1_2_0: Define as 1 to make wxPropertyGrid more compatible with the old 1.2.x releases.
wxPG_COMPATIBILITY_1_0_0: Define to make wxPropertyGrid more compatible with the old 1.0.x releases.
Simple string property. wxPG_STRING_PASSWORD attribute may be used to echo value as asterisks and use wxTE_PASSWORD for wxTextCtrl.
Represents wxColour. wxButton is used to trigger a colour picker dialog.
wxControl* ctrl = new wxControl(); #ifdef __WXMSW__ ctrl->Hide(); #endif ctrl->Create(parent,id,...); ...further initialize, move, resize, etc... #ifdef __WXMSW__ ctrl->Show(); #endif
For instance:
#include <wx/propgrid/propdev.h> // // wxLongStringProperty has wxString as value type and TextCtrlAndButton as editor. // Here we will derive a new property class that will show single choice dialog // on button click. // class MyStringProperty : public wxLongStringProperty { DECLARE_DYNAMIC_CLASS(MyStringProperty) public: // Default constructor MyStringProperty() { } // Normal property constructor. MyStringProperty(const wxString& label, const wxString& name = wxPG_LABEL, const wxString& value = wxEmptyString) : wxLongStringProperty(label, name, value) { // Prepare choices m_choices.Add(wxT("Cat")); m_choices.Add(wxT("Dog")); m_choices.Add(wxT("Gibbon")); m_choices.Add(wxT("Otter")); } // Do something special when button is clicked. virtual wxPGEditorDialogAdapter* GetEditorDialog() const { return new wxSingleChoiceDialogAdapter(m_choices); } protected: wxPGChoices m_choices; }; IMPLEMENT_DYNAMIC_CLASS(MyStringProperty, wxLongStringProperty) // // Actually implement the editor dialog adapter // Naturally, in real code this would have to come // before wxPGProperty::GetEditorDialog() // implementation. // class wxSingleChoiceDialogAdapter : public wxPGEditorDialogAdapter { public: wxSingleChoiceDialogAdapter( const wxPGChoices& choices ) : wxPGEditorDialogAdapter(), m_choices(choices) { } virtual bool DoShowDialog( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property) ) { wxString s = ::wxGetSingleChoice(wxT("Message"), wxT("Caption"), m_choices.GetLabels()); if ( s.length() ) { SetValue(s); return true; } return false; } protected: const wxPGChoices& m_choices; };
You can then create a property instance, for instance:
pg->Append( new MyStringProperty(label, name, value) );
If you want to change editor used, use code like below (continues our sample above).
Note that built-in editors include: TextCtrl, Choice, ComboBox, TextCtrlAndButton, ChoiceAndButton, CheckBox, SpinCtrl, and DatePickerCtrl.
// In class body: virtual const wxPGEditor* DoGetEditorClass() const { return wxPG_EDITOR(TextCtrl); }
You can change the 'value type' of a property by simply assigning different type of variant with SetValue. It is mandatory to implement wxVariantData class for all data types used as property values. Also, it is further recommended to derive your class from wxPGVariantData (see class documentation for more info).
In header:
WX_PG_DECLARE_STRING_PROPERTY(PROPNAME)
In source:
// FLAGS can be wxPG_NO_ESCAPE if escape sequences shall not be expanded. WX_PG_IMPLEMENT_STRING_PROPERTY(PROPNAME, FLAGS) bool PROPNAME::OnButtonClick( wxPropertyGrid* propgrid, wxString& value ) { // // TODO: Show dialog, read initial string from value. If changed, // store new string to value and return TRUE. // NB: You must use wxPGProperty::SetValueInEvent(). // }
FLAGS is either wxPG_NO_ESCAPE (newlines and tabs are not translated to and from escape sequences) or wxPG_ESCAPE (newlines and tabs are transformed into C-string escapes).
There is also WX_PG_IMPLEMENT_STRING_PROPERTY_WITH_VALIDATOR variant which also allows setting up a validator for the property. Like this:
WX_PG_IMPLEMENT_STRING_PROPERTY_WITH_VALIDATOR(PROPNAME, FLAGS) bool PROPNAME::OnButtonClick( wxPropertyGrid* propgrid, wxString& value ) { // // TODO: Show dialog, read initial string from value. If changed, // store new string to value and return TRUE. // NB: You must use wxPGProperty::SetValueInEvent(). // } wxValidator* PROPNAME::DoGetValidator() const { // // TODO: Return pointer to a new wxValidator instance. In most situations, // code like this should work well: // // WX_PG_DOGETVALIDATOR_ENTRY() // // wxMyValidator* validator = new wxMyValidator(...); // // ... prepare validator... // // WX_PG_DOGETVALIDATOR_EXIT(validator) // // Macros are used to maintain only one actual validator instance // (ie. on a second call, function exits within the first macro). // // For real examples, search props.cpp for ::DoGetValidator, it should // have several. // }
In header:
WX_PG_DECLARE_CUSTOM_FLAGS_PROPERTY(PROPNAME)
In source:
// LABELS are VALUES are as in the arguments to wxFlagsProperty // constructor. DEFVAL is the new default value (normally it is 0). WX_PG_IMPLEMENT_CUSTOM_FLAGS_PROPERTY(PROPNAME,LABELS,VALUES,DEFAULT_FLAGS)
The new property class will have simple (label,name,value) constructor.
In header:
WX_PG_DECLARE_ARRAYSTRING_PROPERTY(wxMyArrayStringProperty)
In source:
// second argument = string delimiter. '"' for C string style (default), // and anything else for str1<delimiter> str2<delimiter> str3 style // (so for example, using ';' would result to str1; str2; str3). // third argument = const wxChar* text for the custom button. If NULL // then no button is added. WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY(wxMyArrayStringProperty,',',wxT("Browse")) bool wxMyArrayStringProperty::OnCustomStringEdit(wxWindow* parent, wxString& value) { // // TODO: Show custom editor dialog, read initial string from value. // If changed, store new string to value and return TRUE. // }
Use version that doesn't have _USES_WXCOLOUR in macro names to have wxColourPropertyValue as value type instead of plain wxColour (in this case values array might also make sense).
In header:
#include <wx/propgrid/advprops.h>
WX_PG_DECLARE_CUSTOM_COLOUR_PROPERTY_USES_WXCOLOUR(wxMyColourProperty)
In source:
// Colour labels. Last (before NULL, if any) must be Custom. static const wxChar* mycolprop_labels[] = { wxT("Black"), wxT("Blue"), wxT("Brown"), wxT("Custom"), (const wxChar*) NULL }; // Relevant colour values as unsigned longs. static unsigned long mycolprop_colours[] = { wxPG_COLOUR(0,0,0), wxPG_COLOUR(0,0,255), wxPG_COLOUR(166,124,81), wxPG_COLOUR(0,0,0) }; // Implement property class. Third argument is optional values array, // but in this example we are only interested in creating a shortcut // for user to access the colour values. WX_PG_IMPLEMENT_CUSTOM_COLOUR_PROPERTY_USES_WXCOLOUR(wxMyColourProperty, mycolprop_labels, (long*)NULL, mycolprop_colours)