]>
Commit | Line | Data |
---|---|---|
1c4293cb VZ |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: propgrid.h | |
3 | // Purpose: topic overview | |
4 | // Author: wxWidgets team | |
5 | // RCS-ID: $Id: | |
6 | // Licence: wxWindows license | |
7 | ///////////////////////////////////////////////////////////////////////////// | |
8 | ||
9 | /** | |
10 | ||
11 | @page overview_propgrid wxPropertyGrid Overview | |
12 | ||
13 | Key Classes: | |
14 | @li wxPGProperty | |
15 | @li wxPropertyGrid | |
16 | @li wxPropertyGridEvent | |
17 | @li wxPropertyGridManager | |
18 | @li wxPropertyGridPage | |
19 | ||
20 | wxPropertyGrid is a specialized grid for editing properties such as strings, | |
21 | numbers, flagsets, fonts, and colours. It is possible, for example, to categorize | |
22 | properties, set up a complete tree-hierarchy, add multiple columns, and set | |
23 | arbitrary per-property attributes. | |
24 | ||
25 | @li @ref basics | |
26 | @li @ref categories | |
27 | @li @ref parentprops | |
28 | @li @ref enumandflags | |
29 | @li @ref advprops | |
30 | @li @ref iterating | |
31 | @li @ref operations | |
32 | @li @ref events | |
33 | @li @ref validating | |
34 | @li @ref populating | |
35 | @li @ref cellrender | |
36 | @li @ref customizing | |
37 | @li @ref usage2 | |
38 | @li @ref subclassing | |
39 | @li @ref misc | |
40 | @li @ref proplist | |
41 | @li @ref userhelp | |
42 | @li @ref notes | |
43 | @li @ref newprops | |
44 | @li @ref neweditors | |
45 | ||
46 | @section basics Creating and Populating wxPropertyGrid | |
47 | ||
48 | As seen here, wxPropertyGrid is constructed in the same way as | |
49 | other wxWidgets controls: | |
50 | ||
51 | @code | |
52 | ||
53 | // Necessary header file | |
54 | #include <wx/propgrid/propgrid.h> | |
55 | ||
56 | ... | |
57 | ||
58 | // Assumes code is in frame/dialog constructor | |
59 | ||
60 | // Construct wxPropertyGrid control | |
61 | wxPropertyGrid* pg = new wxPropertyGrid( | |
62 | this, // parent | |
63 | PGID, // id | |
64 | wxDefaultPosition, // position | |
65 | wxDefaultSize, // size | |
66 | // Here are just some of the supported window styles | |
67 | wxPG_AUTO_SORT | // Automatic sorting after items added | |
68 | wxPG_SPLITTER_AUTO_CENTER | // Automatically center splitter until user manually adjusts it | |
69 | // Default style | |
70 | wxPG_DEFAULT_STYLE ); | |
71 | ||
72 | // Window style flags are at premium, so some less often needed ones are | |
73 | // available as extra window styles (wxPG_EX_xxx) which must be set using | |
74 | // SetExtraStyle member function. wxPG_EX_HELP_AS_TOOLTIPS, for instance, | |
75 | // allows displaying help strings as tooltips. | |
76 | pg->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS ); | |
77 | ||
78 | @endcode | |
79 | ||
80 | (for complete list of new window styles: @link wndflags Additional Window Styles@endlink) | |
81 | ||
82 | wxPropertyGrid is usually populated with lines like this: | |
83 | ||
84 | @code | |
85 | pg->Append( new wxStringProperty(wxT("Label"),wxT("Name"),wxT("Initial Value")) ); | |
86 | @endcode | |
87 | ||
88 | Naturally, wxStringProperty is a property class. Only the first function argument (label) | |
89 | is mandatory. Second one, name, defaults to label and, third, the initial value, to | |
90 | default value. If constant wxPG_LABEL is used as the name argument, then the label is | |
91 | automatically used as a name as well (this is more efficient than manually | |
92 | defining both as the same). Empty name is also allowed, but in this case the | |
93 | property cannot be accessed by its name. Note that all property class constructors have | |
94 | quite similar constructor argument list. | |
95 | ||
96 | To demonstrate other common property classes, here's another code snippet: | |
97 | ||
98 | @code | |
99 | ||
100 | // Add int property | |
101 | pg->Append( new wxIntProperty(wxT("IntProperty"), wxPG_LABEL, 12345678) ); | |
102 | ||
103 | // Add float property (value type is actually double) | |
104 | pg->Append( new wxFloatProperty(wxT("FloatProperty"), wxPG_LABEL, 12345.678) ); | |
105 | ||
106 | // Add a bool property | |
107 | pg->Append( new wxBoolProperty(wxT("BoolProperty"), wxPG_LABEL, false) ); | |
108 | ||
109 | // A string property that can be edited in a separate editor dialog. | |
110 | pg->Append( new wxLongStringProperty(wxT("LongStringProperty"), | |
111 | wxPG_LABEL, | |
112 | wxT("This is much longer string than the ") | |
113 | wxT("first one. Edit it by clicking the button."))); | |
114 | ||
115 | // String editor with dir selector button. | |
116 | pg->Append( new wxDirProperty(wxT("DirProperty"), wxPG_LABEL, ::wxGetUserHome()) ); | |
117 | ||
118 | // wxArrayStringProperty embeds a wxArrayString. | |
119 | pg->Append( new wxArrayStringProperty(wxT("Label of ArrayStringProperty"), | |
120 | wxT("NameOfArrayStringProp"))); | |
121 | ||
122 | // A file selector property. | |
123 | pg->Append( new wxFileProperty(wxT("FileProperty"), wxPG_LABEL, wxEmptyString) ); | |
124 | ||
125 | // Extra: set wildcard for file property (format same as in wxFileDialog). | |
126 | pg->SetPropertyAttribute( wxT("FileProperty"), | |
127 | wxPG_FILE_WILDCARD, | |
128 | wxT("All files (*.*)|*.*") ); | |
129 | ||
130 | @endcode | |
131 | ||
132 | Operations on properties should be done either via wxPropertyGrid's | |
133 | (or wxPropertyGridManager's) methods, or by acquiring pointer to a property | |
134 | (Append returns a wxPGProperty* or wxPGId, which is typedef for same), and then | |
135 | calling its method. Note however that property's methods generally do not | |
136 | automatically update grid graphics. | |
137 | ||
138 | Property container functions operating on properties, such as SetPropertyValue or | |
139 | DisableProperty, all accept a special wxPGPropArg, argument which can automatically | |
140 | convert name of a property to a pointer. For instance: | |
141 | ||
142 | @code | |
143 | // A file selector property. | |
144 | wxPGPropety* p = pg->Append( new wxFileProperty(wxT("FileProperty"), wxPG_LABEL, wxEmptyString) ); | |
145 | ||
146 | // Valid: Set wildcard by name | |
147 | pg->SetPropertyAttribute( wxT("FileProperty"), | |
148 | wxPG_FILE_WILDCARD, | |
149 | wxT("All files (*.*)|*.*") ); | |
150 | ||
151 | // Also Valid: Set wildcard by ptr | |
152 | pg->SetPropertyAttribute( p, | |
153 | wxPG_FILE_WILDCARD, | |
154 | wxT("All files (*.*)|*.*") ); | |
155 | @endcode | |
156 | ||
157 | Using pointer is faster, since it doesn't require hash map lookup. Anyway, you can allways | |
158 | get property pointer (wxPGProperty*) as Append/Insert return value, or by calling | |
159 | GetPropertyByName. | |
160 | ||
161 | Below are samples for using some of the more commong operations. See | |
162 | wxPropertyGridInterface and wxPropertyGrid class references for complete list. | |
163 | ||
164 | @code | |
165 | ||
166 | // wxPGId is a short-hand for wxPGProperty*. Let's use it this time. | |
167 | wxPGId id = pg->GetPropertyByName( wxT("MyProperty") ); | |
168 | ||
169 | // There are many overloaded versions of this method, of which each accept | |
170 | // different type of value. | |
171 | pg->SetPropertyValue( wxT("MyProperty"), 200 ); | |
172 | ||
173 | // Setting a string works for all properties - conversion is done | |
174 | // automatically. | |
175 | pg->SetPropertyValue( id, wxT("400") ); | |
176 | ||
177 | // Getting property value as wxVariant. | |
178 | wxVariant value = pg->GetPropertyValue( wxT("MyProperty") ); | |
179 | ||
180 | // Getting property value as String (again, works for all typs). | |
181 | wxString value = pg->GetPropertyValueAsString( id ); | |
182 | ||
183 | // Getting property value as int. Provokes a run-time error | |
184 | // if used with property which value type is not "long". | |
185 | long value = pg->GetPropertyValueAsLong( wxT("MyProperty") ); | |
186 | ||
187 | // Set new name. | |
188 | pg->SetPropertyName( wxT("MyProperty"), wxT("X") ); | |
189 | ||
190 | // Set new label - we need to use the new name. | |
191 | pg->SetPropertyLabel( wxT("X"), wxT("New Label") ); | |
192 | ||
193 | // Disable the property. It's text will appear greyed. | |
194 | // This is probably the closest you can get if you want | |
195 | // a "read-only" property. | |
196 | pg->DisableProperty( id ); | |
197 | ||
198 | @endcode | |
199 | ||
200 | ||
201 | @section categories Categories | |
202 | ||
203 | wxPropertyGrid has a hierarchial property storage and display model, which | |
204 | allows property categories to hold child properties and even other | |
205 | categories. Other than that, from the programmer's point of view, categories | |
206 | can be treated exactly the same as "other" properties. For example, despite | |
207 | its name, GetPropertyByName also returns a category by name, and SetPropertyLabel | |
208 | also sets label of a category. Note however that sometimes the label of a | |
209 | property category may be referred as caption (for example, there is | |
210 | SetCaptionForegroundColour method that sets text colour of a property category's label). | |
211 | ||
212 | When category is added at the top (i.e. root) level of the hierarchy, | |
213 | it becomes a *current category*. This means that all other (non-category) | |
214 | properties after it are automatically added to it. You may add | |
215 | properties to specific categories by using wxPropertyGrid::Insert or wxPropertyGrid::AppendIn. | |
216 | ||
217 | Category code sample: | |
218 | ||
219 | @code | |
220 | ||
221 | // One way to add category (similar to how other properties are added) | |
222 | pg->Append( new wxPropertyCategory(wxT("Main")) ); | |
223 | ||
224 | // All these are added to "Main" category | |
225 | pg->Append( new wxStringProperty(wxT("Name")) ); | |
226 | pg->Append( new wxIntProperty(wxT("Age"),wxPG_LABEL,25) ); | |
227 | pg->Append( new wxIntProperty(wxT("Height"),wxPG_LABEL,180) ); | |
228 | pg->Append( new wxIntProperty(wxT("Weight")) ); | |
229 | ||
230 | // Another one | |
231 | pg->Append( new wxPropertyCategory(wxT("Attrikbutes")) ); | |
232 | ||
233 | // All these are added to "Attributes" category | |
234 | pg->Append( new wxIntProperty(wxT("Intelligence")) ); | |
235 | pg->Append( new wxIntProperty(wxT("Agility")) ); | |
236 | pg->Append( new wxIntProperty(wxT("Strength")) ); | |
237 | ||
238 | @endcode | |
239 | ||
240 | ||
241 | @section parentprops Tree-like Property Structure | |
242 | ||
243 | As a new feature in version 1.3.1, basicly any property can have children. There | |
244 | are few limitations, however. | |
245 | ||
246 | @remarks | |
247 | - Names of properties with non-category, non-root parents are not stored in hash map. | |
248 | Instead, they can be accessed with strings like "Parent.Child". For instance, in | |
249 | the sample below, child property named "Max. Speed (mph)" can be accessed by global | |
250 | name "Car.Speeds.Max Speed (mph)". | |
251 | - If you want to property's value to be a string composed based on the values of | |
252 | child properties, you must use wxStringProperty as parent and use value "<composed>". | |
253 | - Events (eg. change of value) that occur in parent do not propagate to children. Events | |
254 | that occur in children will propagate to parents, but only if they are wxStringProperties | |
255 | with "<composed>" value. | |
256 | - Old wxParentProperty class is deprecated, and remains as a typedef of wxStringProperty. | |
257 | If you want old value behavior, you must specify "<composed>" as wxStringProperty's | |
258 | value. | |
259 | ||
260 | Sample: | |
261 | ||
262 | @code | |
263 | wxPGId pid = pg->Append( new wxStringProperty(wxT("Car"),wxPG_LABEL,wxT("<composed>")) ); | |
264 | ||
265 | pg->AppendIn( pid, new wxStringProperty(wxT("Model"), | |
266 | wxPG_LABEL, | |
267 | wxT("Lamborghini Diablo SV")) ); | |
268 | ||
269 | pg->AppendIn( pid, new wxIntProperty(wxT("Engine Size (cc)"), | |
270 | wxPG_LABEL, | |
271 | 5707) ); | |
272 | ||
273 | wxPGId speedId = pg->AppendIn( pid, new wxStringProperty(wxT("Speeds"),wxPG_LABEL,wxT("<composed>")) ); | |
274 | pg->AppendIn( speedId, new wxIntProperty(wxT("Max. Speed (mph)"),wxPG_LABEL,290) ); | |
275 | pg->AppendIn( speedId, new wxFloatProperty(wxT("0-100 mph (sec)"),wxPG_LABEL,3.9) ); | |
276 | pg->AppendIn( speedId, new wxFloatProperty(wxT("1/4 mile (sec)"),wxPG_LABEL,8.6) ); | |
277 | ||
278 | // Make sure the child properties can be accessed correctly | |
279 | pg->SetPropertyValue( wxT("Car.Speeds.Max. Speed (mph)"), 300 ); | |
280 | ||
281 | pg->AppendIn( pid, new wxIntProperty(wxT("Price ($)"), | |
282 | wxPG_LABEL, | |
283 | 300000) ); | |
284 | // Displayed value of "Car" property is now: | |
285 | // "Lamborghini Diablo SV; [300; 3.9; 8.6]; 300000" | |
286 | ||
287 | @endcode | |
288 | ||
289 | @section enumandflags wxEnumProperty and wxFlagsProperty | |
290 | ||
291 | wxEnumProperty is used when you want property's (integer or string) value | |
292 | to be selected from a popup list of choices. | |
293 | ||
294 | Creating wxEnumProperty is more complex than those described earlier. | |
295 | You have to provide list of constant labels, and optionally relevant values | |
296 | (if label indexes are not sufficient). | |
297 | ||
298 | @remarks | |
299 | ||
300 | - Value wxPG_INVALID_VALUE (equals 2147483647 which usually equals INT_MAX) is not | |
301 | allowed as value. | |
302 | ||
303 | A very simple example: | |
304 | ||
305 | @code | |
306 | ||
307 | // | |
308 | // Using wxArrayString | |
309 | // | |
310 | wxArrayString arrDiet; | |
311 | arr.Add(wxT("Herbivore")); | |
312 | arr.Add(wxT("Carnivore")); | |
313 | arr.Add(wxT("Omnivore")); | |
314 | ||
315 | pg->Append( new wxEnumProperty(wxT("Diet"), | |
316 | wxPG_LABEL, | |
317 | arrDiet) ); | |
318 | ||
319 | ||
320 | ||
321 | // | |
322 | // Using wxChar* array | |
323 | // | |
324 | const wxChar* arrayDiet[] = | |
325 | { wxT("Herbivore"), wxT("Carnivore"), wxT("Omnivore"), NULL }; | |
326 | ||
327 | pg->Append( new wxEnumProperty(wxT("Diet"), | |
328 | wxPG_LABEL, | |
329 | arrayDiet) ); | |
330 | ||
331 | ||
332 | @endcode | |
333 | ||
334 | Here's extended example using values as well: | |
335 | ||
336 | @code | |
337 | ||
338 | // | |
339 | // Using wxArrayString and wxArrayInt | |
340 | // | |
341 | wxArrayString arrDiet; | |
342 | arr.Add(wxT("Herbivore")); | |
343 | arr.Add(wxT("Carnivore")); | |
344 | arr.Add(wxT("Omnivore")); | |
345 | ||
346 | wxArrayInt arrIds; | |
347 | arrIds.Add(40); | |
348 | arrIds.Add(45); | |
349 | arrIds.Add(50); | |
350 | ||
351 | // Note that the initial value (the last argument) is the actual value, | |
352 | // not index or anything like that. Thus, our value selects "Omnivore". | |
353 | pg->Append( new wxEnumProperty(wxT("Diet"), | |
354 | wxPG_LABEL, | |
355 | arrDiet, | |
356 | arrIds, | |
357 | 50)); | |
358 | ||
359 | ||
360 | // | |
361 | // Using wxChar* and long arrays | |
362 | // | |
363 | const wxChar* array_diet[] = | |
364 | { wxT("Herbivore"), wxT("Carnivore"), wxT("Omnivore"), NULL }; | |
365 | ||
366 | long array_diet_ids[] = | |
367 | { 40, 45, 50 }; | |
368 | ||
369 | // Value can be set from string as well | |
370 | pg->Append( new wxEnumProperty(wxT("Diet"), | |
371 | wxPG_LABEL, | |
372 | array_diet, | |
373 | array_diet_ids); | |
374 | ||
375 | @endcode | |
376 | ||
377 | wxPGChoices is a class where wxEnumProperty, and other properties which | |
378 | require label storage, actually stores strings and values. It is used | |
379 | to facilitiate reference counting, and therefore recommended way of | |
380 | adding items when multiple properties share the same set. | |
381 | ||
382 | You can use wxPGChoices directly as well, filling it and then passing it | |
383 | to the constructor. Infact, if you wish to display bitmaps next to labels, | |
384 | your best choice is to use this approach. | |
385 | ||
386 | @code | |
387 | ||
388 | wxPGChoices chs; | |
389 | chs.Add(wxT("Herbivore"),40); | |
390 | chs.Add(wxT("Carnivore"),45); | |
391 | chs.Add(wxT("Omnivore"),50); | |
392 | ||
393 | // Let's add an item with bitmap, too | |
394 | chs.Add(wxT("None of the above"), wxBitmap(), 60); | |
395 | ||
396 | // Note: you can add even whole arrays to wxPGChoices | |
397 | ||
398 | pg->Append( new wxEnumProperty(wxT("Diet"), | |
399 | wxPG_LABEL, | |
400 | chs) ); | |
401 | ||
402 | // Add same choices to another property as well - this is efficient due | |
403 | // to reference counting | |
404 | pg->Append( new wxEnumProperty(wxT("Diet 2"), | |
405 | wxPG_LABEL, | |
406 | chs) ); | |
407 | ||
408 | @endcode | |
409 | ||
410 | If you later need to change choices used by a property, there is function | |
411 | for that as well. | |
412 | ||
413 | @code | |
414 | ||
415 | // | |
416 | // Example 1: Add one extra item | |
417 | wxPGChoices& choices = pg->GetPropertyChoices(wxT("Diet")); | |
418 | choices.Add(wxT("Custom"),55); | |
419 | ||
420 | // | |
421 | // Example 2: Replace all the choices | |
422 | wxPGChoices chs; | |
423 | chs.Add(wxT("<No valid items yet>"),0); | |
424 | pg->SetPropertyChoices(wxT("Diet"),chs); | |
425 | ||
426 | @endcode | |
427 | ||
428 | If you want to create your enum properties with simple (label,name,value) | |
429 | constructor, then you need to create a new property class using one of the | |
430 | supplied macro pairs. See @ref newprops for details. | |
431 | ||
432 | <b>wxEditEnumProperty</b> is works exactly like wxEnumProperty, except | |
433 | is uses non-readonly combobox as default editor, and value is stored as | |
434 | string when it is not any of the choices. | |
435 | ||
436 | wxFlagsProperty is similar: | |
437 | ||
438 | @code | |
439 | ||
440 | const wxChar* flags_prop_labels[] = { wxT("wxICONIZE"), | |
441 | wxT("wxCAPTION"), wxT("wxMINIMIZE_BOX"), wxT("wxMAXIMIZE_BOX"), NULL }; | |
442 | ||
443 | // this value array would be optional if values matched string indexes | |
444 | long flags_prop_values[] = { wxICONIZE, wxCAPTION, wxMINIMIZE_BOX, | |
445 | wxMAXIMIZE_BOX }; | |
446 | ||
447 | pg->Append( new wxFlagsProperty(wxT("Window Style"), | |
448 | wxPG_LABEL, | |
449 | flags_prop_labels, | |
450 | flags_prop_values, | |
451 | wxDEFAULT_FRAME_STYLE) ); | |
452 | ||
453 | @endcode | |
454 | ||
455 | wxFlagsProperty can use wxPGChoices just the same way as wxEnumProperty | |
456 | (and also custom property classes can be created with similar macro pairs). | |
457 | <b>Note: </b> When changing "choices" (ie. flag labels) of wxFlagsProperty, | |
458 | you will need to use SetPropertyChoices - otherwise they will not get updated | |
459 | properly. | |
460 | ||
461 | @section advprops Specialized Properties | |
462 | ||
463 | This section describes the use of less often needed property classes. | |
464 | To use them, you have to include <wx/propgrid/advprops.h>. | |
465 | ||
466 | @code | |
467 | ||
468 | // Necessary extra header file | |
469 | #include <wx/propgrid/advprops.h> | |
470 | ||
471 | ... | |
472 | ||
473 | // Date property. | |
474 | pg->Append( new wxDateProperty(wxT("MyDateProperty"), | |
475 | wxPG_LABEL, | |
476 | wxDateTime::Now()) ); | |
477 | ||
478 | // Image file property. Wildcard is auto-generated from available | |
479 | // image handlers, so it is not set this time. | |
480 | pg->Append( new wxImageFileProperty(wxT("Label of ImageFileProperty"), | |
481 | wxT("NameOfImageFileProp")) ); | |
482 | ||
483 | // Font property has sub-properties. Note that we give window's font as | |
484 | // initial value. | |
485 | pg->Append( new wxFontProperty(wxT("Font"), | |
486 | wxPG_LABEL, | |
487 | GetFont()) ); | |
488 | ||
489 | // Colour property with arbitrary colour. | |
490 | pg->Append( new wxColourProperty(wxT("My Colour 1"), | |
491 | wxPG_LABEL, | |
492 | wxColour(242,109,0) ) ); | |
493 | ||
494 | // System colour property. | |
495 | pg->Append( new wxSystemColourProperty(wxT("My SysColour 1"), | |
496 | wxPG_LABEL, | |
497 | wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) ); | |
498 | ||
499 | // System colour property with custom colour. | |
500 | pg->Append( new wxSystemColourProperty(wxT("My SysColour 2"), | |
501 | wxPG_LABEL, | |
502 | wxColour(0,200,160) ) ); | |
503 | ||
504 | // Cursor property | |
505 | pg->Append( new wxCursorProperty(wxT("My Cursor"), | |
506 | wxPG_LABEL, | |
507 | wxCURSOR_ARROW)); | |
508 | ||
509 | @endcode | |
510 | ||
511 | ||
512 | @section iterating Iterating through a property container | |
513 | ||
514 | You can use somewhat STL'ish iterator classes to iterate through the grid. | |
515 | Here is a simple example of forward iterating through all individual | |
516 | properties (not categories or sub-propeties that are normally 'transparent' | |
517 | to application code): | |
518 | ||
519 | @code | |
520 | ||
521 | wxPropertyGridIterator it; | |
522 | ||
523 | for ( it = pg->GetIterator(); | |
524 | !it.AtEnd(); | |
525 | it++ ) | |
526 | { | |
527 | wxPGProperty* p = *it; | |
528 | // Do something with the property | |
529 | } | |
530 | ||
531 | @endcode | |
532 | ||
533 | As expected there is also a const iterator: | |
534 | ||
535 | @code | |
536 | ||
537 | wxPropertyGridConstIterator it; | |
538 | ||
539 | for ( it = pg->GetIterator(); | |
540 | !it.AtEnd(); | |
541 | it++ ) | |
542 | { | |
543 | const wxPGProperty* p = *it; | |
544 | // Do something with the property | |
545 | } | |
546 | ||
547 | @endcode | |
548 | ||
549 | You can give some arguments to GetIterator to determine which properties | |
550 | get automatically filtered out. For complete list of options, see | |
551 | @link iteratorflags List of Property Iterator Flags@endlink. GetIterator() | |
552 | also accepts other arguments. See wxPropertyGridInterface::GetIterator() | |
553 | for details. | |
554 | ||
555 | This example reverse-iterates through all visible items: | |
556 | ||
557 | @code | |
558 | ||
559 | wxPropertyGridIterator it; | |
560 | ||
561 | for ( it = pg->GetIterator(wxPG_ITERATE_VISIBLE, wxBOTTOM); | |
562 | !it.AtEnd(); | |
563 | it-- ) | |
564 | { | |
565 | wxPGProperty* p = *it; | |
566 | // Do something with the property | |
567 | } | |
568 | ||
569 | @endcode | |
570 | ||
571 | <b>wxPython Note:</b> Instead of ++ operator, use Next() method, and instead of | |
572 | * operator, use GetProperty() method. | |
573 | ||
574 | GetIterator() only works with wxPropertyGrid and the individual pages | |
575 | of wxPropertyGridManager. In order to iterate through an arbitrary | |
576 | property container, you need to use wxPropertyGridInterface::GetVIterator(). | |
577 | Note however that this virtual iterater is limited to forward iteration. | |
578 | ||
579 | @code | |
580 | ||
581 | wxPGVIterator it; | |
582 | ||
583 | for ( it = manager->GetVIterator(); | |
584 | !it.AtEnd(); | |
585 | it.Next() ) | |
586 | { | |
587 | wxPGProperty* p = it.GetProperty(); | |
588 | // Do something with the property | |
589 | } | |
590 | ||
591 | @endcode | |
592 | ||
593 | ||
594 | @section operations More About Operating with Properties | |
595 | ||
596 | Getting value of selected wxSystemColourProperty (which value type is derived | |
597 | from wxObject): | |
598 | ||
599 | @code | |
600 | ||
601 | wxPGId id = pg->GetSelection(); | |
602 | ||
603 | if ( id ) | |
604 | { | |
605 | // Get name of property | |
606 | const wxString& name = pg->GetPropertyName( id ); | |
607 | ||
608 | // If type is not correct, GetColour() method will produce run-time error | |
609 | if ( pg->GetPropertyValueType() == wxT("wxColourPropertyValue") ) ) | |
610 | { | |
611 | wxColourPropertyValue* pcolval = | |
612 | wxDynamicCast(pg->GetPropertyValueAsWxObjectPtr(id), | |
613 | wxColourPropertyValue); | |
614 | ||
615 | // Report value | |
616 | wxString text; | |
617 | if ( pcolval->m_type == wxPG_CUSTOM_COLOUR ) | |
618 | text.Printf( wxT("It is custom colour: (%i,%i,%i)"), | |
619 | (int)pcolval->m_colour.Red(), | |
620 | (int)pcolval->m_colour.Green(), | |
621 | (int)pcolval->m_colour.Blue()); | |
622 | else | |
623 | text.Printf( wxT("It is wx system colour (number=%i): (%i,%i,%i)"), | |
624 | (int)pcolval->m_type, | |
625 | (int)pcolval->m_colour.Red(), | |
626 | (int)pcolval->m_colour.Green(), | |
627 | (int)pcolval->m_colour.Blue()); | |
628 | ||
629 | wxMessageBox( text ); | |
630 | } | |
631 | } | |
632 | ||
633 | @endcode | |
634 | ||
635 | @section populating Populating wxPropertyGrid Automatically | |
636 | ||
637 | @subsection fromvariants Populating from List of wxVariants | |
638 | ||
639 | Example of populating an empty wxPropertyGrid from a values stored | |
640 | in an arbitrary list of wxVariants. | |
641 | ||
642 | @code | |
643 | ||
644 | // This is a static method that initializes *all* builtin type handlers | |
645 | // available, including those for wxColour and wxFont. Refers to *all* | |
646 | // included properties, so when compiling with static library, this | |
647 | // method may increase the executable size significantly. | |
648 | pg->InitAllTypeHandlers(); | |
649 | ||
650 | // Get contents of the grid as a wxVariant list | |
651 | wxVariant all_values = pg->GetPropertyValues(); | |
652 | ||
653 | // Populate the list with values. If a property with appropriate | |
654 | // name is not found, it is created according to the type of variant. | |
655 | pg->SetPropertyValues( my_list_variant ); | |
656 | ||
657 | // In order to get wxObject ptr from a variant value, | |
658 | // wxGetVariantCast(VARIANT,CLASSNAME) macro has to be called. | |
659 | // Like this: | |
660 | wxVariant v_txcol = pg->GetPropertyValue(wxT("Text Colour")); | |
661 | const wxColour& txcol = wxGetVariantCast(v_txcol,wxColour); | |
662 | ||
663 | @endcode | |
664 | ||
665 | @subsection fromfile Loading Population from a Text-based Storage | |
666 | ||
667 | Class wxPropertyGridPopulator may be helpful when writing code that | |
668 | loads properties from a text-source. In fact, the supplied xrc handler | |
669 | (src/xh_propgrid.cpp) uses it. See that code for more info. | |
670 | NOTE: src/xh_propgrid.cpp is not included in the library by default, | |
671 | to avoid dependency to wxXRC. You will need to add it to your application | |
672 | separately. | |
673 | ||
674 | @subsection editablestate Saving and Restoring User-Editable State | |
675 | ||
676 | You can use wxPGEditableState and wxPGMEditableState classes, and | |
677 | wxPropertyGrid::SaveEditableState() and wxPropertyGrid::RestoreEditableState() | |
678 | to save and restore user-editable state (selected property, expanded/ | |
679 | collapsed properties, and scrolled position). For convience with | |
680 | program configuration, wxPGEditableState has functions to save/load | |
681 | its value in wxString. For instance: | |
682 | ||
683 | @code | |
684 | // Save state into config | |
685 | wxPGEditableState edState; | |
686 | pg->SaveEditableState(&edState); | |
687 | programConfig->Store(wxT("PropertyGridState"), edState.GetAsString()); | |
688 | ||
689 | // Restore state from config | |
690 | wxPGEditableState edState; | |
691 | edState.SetFromString(programConfig->Load(wxT("PropertyGridState"))); | |
692 | pg->RestoreEditableState(edState); | |
693 | @endcode | |
694 | ||
695 | ||
696 | @section events Event Handling | |
697 | ||
698 | Probably the most important event is the Changed event which occurs when | |
699 | value of any property is changed by the user. Use EVT_PG_CHANGED(id,func) | |
700 | in your event table to use it. | |
701 | ||
702 | For complete list of event types, see wxPropertyGrid class reference. | |
703 | ||
704 | The custom event class, wxPropertyGridEvent, has methods to directly | |
705 | access the property that triggered the event. | |
706 | ||
707 | Here's a small sample: | |
708 | ||
709 | @code | |
710 | ||
711 | // Portion of an imaginary event table | |
712 | BEGIN_EVENT_TABLE(MyForm, wxFrame) | |
713 | ||
714 | ... | |
715 | ||
716 | // This occurs when a property value changes | |
717 | EVT_PG_CHANGED( PGID, MyForm::OnPropertyGridChange ) | |
718 | ||
719 | ... | |
720 | ||
721 | END_EVENT_TABLE() | |
722 | ||
723 | void MyForm::OnPropertyGridChange( wxPropertyGridEvent& event ) | |
724 | { | |
725 | wxPGProperty *property = event.GetProperty(); | |
726 | ||
727 | // It may be NULL | |
728 | if ( !property ) | |
729 | return; | |
730 | ||
731 | // Get name of changed property | |
732 | const wxString& name = property->GetName(); | |
733 | ||
734 | // Get resulting value | |
735 | wxVariant value = property->GetValue(); | |
736 | } | |
737 | ||
738 | @endcode | |
739 | ||
740 | Another event type you might find useful is EVT_PG_CHANGING, which occurs | |
741 | just prior property value is being changed by user. You can acquire pending | |
742 | value using wxPropertyGridEvent::GetValue(), and if it is not acceptable, | |
743 | call wxPropertyGridEvent::Veto() to prevent the value change from taking | |
744 | place. | |
745 | ||
746 | @code | |
747 | ||
748 | // Portion of an imaginary event table | |
749 | BEGIN_EVENT_TABLE(MyForm, wxFrame) | |
750 | ||
751 | ... | |
752 | ||
753 | // This occurs when a property value changes | |
754 | EVT_PG_CHANGING( PGID, MyForm::OnPropertyGridChanging ) | |
755 | ||
756 | ... | |
757 | ||
758 | END_EVENT_TABLE() | |
759 | ||
760 | void MyForm::OnPropertyGridChanging( wxPropertyGridEvent& event ) | |
761 | { | |
762 | wxPGProperty* property = event.GetProperty(); | |
763 | ||
764 | if ( property == m_pWatchThisProperty ) | |
765 | { | |
766 | // GetValue() returns the pending value, but is only | |
767 | // supported by wxEVT_PG_CHANGING. | |
768 | if ( event.GetValue().GetString() == g_pThisTextIsNotAllowed ) | |
769 | { | |
770 | event.Veto(); | |
771 | return; | |
772 | } | |
773 | } | |
774 | } | |
775 | ||
776 | @endcode | |
777 | ||
778 | @remarks On Sub-property Event Handling | |
779 | - For aggregate type properties (wxFontProperty, wxFlagsProperty, etc), events | |
780 | occur for the main parent property only. For other properties events occur | |
781 | for the children themselves.. | |
782 | ||
783 | - When property's child gets changed, you can use wxPropertyGridEvent::GetMainParent | |
784 | to obtain its topmost non-category parent (useful, if you have deeply nested | |
785 | properties). | |
786 | ||
787 | ||
788 | @section validating Validating Property Values | |
789 | ||
790 | There are various ways to make sure user enters only correct values. First, you | |
791 | can use wxValidators similar to as you would with ordinary controls. Use | |
792 | wxPropertyGridInterface::SetPropertyValidator() to assign wxValidator to | |
793 | property. | |
794 | ||
795 | Second, you can subclass a property and override wxPGProperty::ValidateValue(), | |
796 | or handle wxEVT_PG_CHANGING for the same effect. Both of these methods do not | |
797 | actually prevent user from temporarily entering invalid text, but they do give | |
798 | you an opportunity to warn the user and block changed value from being committed | |
799 | in a property. | |
800 | ||
801 | Various validation failure options can be controlled globally with | |
802 | wxPropertyGrid::SetValidationFailureBehavior(), or on an event basis by | |
803 | calling wxEvent::SetValidationFailureBehavior(). Here's a code snippet of | |
804 | how to handle wxEVT_PG_CHANGING, and to set custom failure behaviour and | |
805 | message. | |
806 | ||
807 | @code | |
808 | void MyFrame::OnPropertyGridChanging(wxPropertyGridEvent& event) | |
809 | { | |
810 | wxPGProperty* property = event.GetProperty(); | |
811 | ||
812 | // You must use wxPropertyGridEvent::GetValue() to access | |
813 | // the value to be validated. | |
814 | wxVariant pendingValue = event.GetValue(); | |
815 | ||
816 | if ( property->GetName() == wxT("Font") ) | |
817 | { | |
818 | // Make sure value is not unspecified | |
819 | if ( !pendingValue.IsNull() ) | |
820 | { | |
821 | wxFont font << pendingValue; | |
822 | ||
823 | // Let's just allow Arial font | |
824 | if ( font.GetFaceName() != wxT("Arial") ) | |
825 | { | |
826 | event.Veto(); | |
827 | event.SetValidationFailureBehavior(wxPG_VFB_STAY_IN_PROPERTY | | |
828 | wxPG_VFB_BEEP | | |
829 | wxPG_VFB_SHOW_MESSAGE); | |
830 | } | |
831 | } | |
832 | } | |
833 | } | |
834 | @endcode | |
835 | ||
836 | ||
837 | @section cellrender Customizing Individual Cell Appearance | |
838 | ||
839 | You can control text colour, background colour, and attached image of | |
840 | each cell in the property grid. Use wxPropertyGridInterface::SetPropertyCell() or | |
841 | wxPGProperty::SetCell() for this purpose. | |
842 | ||
843 | In addition, it is possible to control these characteristics for | |
844 | wxPGChoices list items. See wxPGChoices::Item() and wxPGChoiceEntry class | |
845 | reference for more info. | |
846 | ||
847 | ||
848 | @section customizing Customizing Properties (without sub-classing) | |
849 | ||
850 | In this section are presented miscellaneous ways to have custom appearance | |
851 | and behavior for your properties without all the necessary hassle | |
852 | of sub-classing a property class etc. | |
853 | ||
854 | @subsection customimage Setting Value Image | |
855 | ||
856 | Every property can have a small value image placed in front of the | |
857 | actual value text. Built-in example of this can be seen with | |
858 | wxColourProperty and wxImageFileProperty, but for others it can | |
859 | be set using wxPropertyGrid::SetPropertyImage method. | |
860 | ||
861 | @subsection customvalidator Setting Validator | |
862 | ||
863 | You can set wxValidator for a property using wxPropertyGrid::SetPropertyValidator. | |
864 | ||
865 | Validator will work just like in wxWidgets (ie. editorControl->SetValidator(validator) | |
866 | is called). | |
867 | ||
868 | @subsection customeditor Setting Property's Editor Control(s) | |
869 | ||
870 | You can set editor control (or controls, in case of a control and button), | |
871 | of any property using wxPropertyGrid::SetPropertyEditor. Editors are passed | |
872 | using wxPG_EDITOR(EditorName) macro, and valid built-in EditorNames are | |
873 | TextCtrl, Choice, ComboBox, CheckBox, TextCtrlAndButton, ChoiceAndButton, | |
874 | SpinCtrl, and DatePickerCtrl. Two last mentioned ones require call to | |
875 | static member function wxPropertyGrid::RegisterAdditionalEditors(). | |
876 | ||
877 | Following example changes wxColourProperty's editor from default Choice | |
878 | to TextCtrlAndButton. wxColourProperty has its internal event handling set | |
879 | up so that button click events of the button will be used to trigger | |
880 | colour selection dialog. | |
881 | ||
882 | @code | |
883 | ||
884 | wxPGId colProp = pg->Append(wxColourProperty(wxT("Text Colour"))); | |
885 | ||
886 | pg->SetPropertyEditor(colProp,wxPG_EDITOR(TextCtrlAndButton)); | |
887 | ||
888 | @endcode | |
889 | ||
890 | Naturally, creating and setting custom editor classes is a possibility as | |
891 | well. For more information, see wxPGEditor class reference. | |
892 | ||
893 | @subsection editorattrs Property Attributes Recognized by Editors | |
894 | ||
895 | <b>SpinCtrl</b> editor can make use of property's "Min", "Max", "Step" and "Wrap" attributes. | |
896 | ||
897 | @subsection multiplebuttons Adding Multiple Buttons Next to an Editor | |
898 | ||
899 | See wxPGMultiButton class reference. | |
900 | ||
901 | @subsection customeventhandling Handling Events Passed from Properties | |
902 | ||
903 | <b>wxEVT_COMMAND_BUTTON_CLICKED </b>(corresponds to event table macro EVT_BUTTON): | |
904 | Occurs when editor button click is not handled by the property itself | |
905 | (as is the case, for example, if you set property's editor to TextCtrlAndButton | |
906 | from the original TextCtrl). | |
907 | ||
908 | @subsection attributes Property Attributes | |
909 | ||
910 | Miscellaneous values, often specific to a property type, can be set | |
911 | using wxPropertyGrid::SetPropertyAttribute and wxPropertyGrid::SetPropertyAttributeAll | |
912 | methods. | |
913 | ||
914 | Attribute names are strings and values wxVariant. Arbitrary names are allowed | |
915 | inorder to store user values. Constant equivalents of all attribute string names are | |
916 | provided. Some of them are defined as cached strings, so using constants can provide | |
917 | for smaller binary size. | |
918 | ||
919 | For complete list of attributes, see @link attrids Property Attributes@endlink. | |
920 | ||
921 | @subsection boolcheckbox Setting wxBoolProperties to Use Check Box | |
922 | ||
923 | To have all wxBoolProperties to use CheckBox editor instead of Choice, use | |
924 | following (call after bool properties have been added): | |
925 | ||
926 | @code | |
927 | pg->SetPropertyAttributeAll(wxPG_BOOL_USE_CHECKBOX,true); | |
928 | @endcode | |
929 | ||
930 | ||
931 | @section usage2 Using wxPropertyGridManager | |
932 | ||
933 | wxPropertyGridManager is an efficient multi-page version of wxPropertyGrid, | |
934 | which can optionally have toolbar for mode and page selection, and a help text | |
935 | box. | |
936 | ||
937 | wxPropertyGridManager inherits from wxPropertyGridInterface, and as such | |
938 | it has most property manipulation functions. However, only some of them affect | |
939 | properties on all pages (eg. GetPropertyByName() and ExpandAll()), while some | |
940 | (eg. Append()) only apply to the currently selected page. | |
941 | ||
942 | To operate explicitly on properties on specific page, use wxPropertyGridManager::GetPage() | |
943 | to obtain pointer to page's wxPropertyGridPage object. | |
944 | ||
945 | Visual methods, such as SetCellBackgroundColour and GetNextVisible are only | |
946 | available in wxPropertyGrid. Use wxPropertyGridManager::GetGrid() to obtain | |
947 | pointer to it. | |
948 | ||
949 | Iteration methods will not work in wxPropertyGridManager. Instead, you must acquire | |
950 | the internal grid (GetGrid()) or wxPropertyGridPage object (GetPage()). | |
951 | ||
952 | wxPropertyGridManager constructor has exact same format as wxPropertyGrid | |
953 | constructor, and basicly accepts same extra window style flags (albeit also | |
954 | has some extra ones). | |
955 | ||
956 | Here's some example code for creating and populating a wxPropertyGridManager: | |
957 | ||
958 | @code | |
959 | ||
960 | wxPropertyGridManager* pgMan = new wxPropertyGridManager(this, PGID, | |
961 | wxDefaultPosition, wxDefaultSize, | |
962 | // These and other similar styles are automatically | |
963 | // passed to the embedded wxPropertyGrid. | |
964 | wxPG_BOLD_MODIFIED|wxPG_SPLITTER_AUTO_CENTER| | |
965 | // Include toolbar. | |
966 | wxPG_TOOLBAR | | |
967 | // Include description box. | |
968 | wxPG_DESCRIPTION | | |
969 | // Include compactor. | |
970 | wxPG_COMPACTOR | | |
971 | // Plus defaults. | |
972 | wxPGMAN_DEFAULT_STYLE | |
973 | ); | |
974 | ||
975 | wxPropertyGridPage* page; | |
976 | ||
977 | // Adding a page sets target page to the one added, so | |
978 | // we don't have to call SetTargetPage if we are filling | |
979 | // it right after adding. | |
980 | pgMan->AddPage(wxT("First Page")); | |
981 | page = pgMan->GetLastPage(); | |
982 | ||
983 | page->Append( new wxPropertyCategory(wxT("Category A1")) ); | |
984 | ||
985 | page->Append( new wxIntProperty(wxT("Number"),wxPG_LABEL,1) ); | |
986 | ||
987 | page->Append( new wxColourProperty(wxT("Colour"),wxPG_LABEL,*wxWHITE) ); | |
988 | ||
989 | pgMan->AddPage(wxT("Second Page")); | |
990 | page = pgMan->GetLastPage(); | |
991 | ||
992 | page->Append( wxT("Text"),wxPG_LABEL,wxT("(no text)") ); | |
993 | ||
994 | page->Append( new wxFontProperty(wxT("Font"),wxPG_LABEL) ); | |
995 | ||
996 | @endcode | |
997 | ||
998 | @subsection propgridpage wxPropertyGridPage | |
999 | ||
1000 | wxPropertyGridPage is holder of properties for one page in manager. It is derived from | |
1001 | wxEvtHandler, so you can subclass it to process page-specific property grid events. Hand | |
1002 | over your page instance in wxPropertyGridManager::AddPage. | |
1003 | ||
1004 | Please note that the wxPropertyGridPage itself only sports subset of wxPropertyGrid API | |
1005 | (but unlike manager, this include item iteration). Naturally it inherits from | |
1006 | wxPropertyGridMethods and wxPropertyGridPageState. | |
1007 | ||
1008 | ||
1009 | @section subclassing Subclassing wxPropertyGrid and wxPropertyGridManager | |
1010 | ||
1011 | Few things to note: | |
1012 | ||
1013 | - Only a small percentage of member functions are virtual. If you need more, | |
1014 | just e-mail to wx-dev mailing list. | |
1015 | ||
1016 | - Data manipulation is done in wxPropertyGridPageState class. So, instead of | |
1017 | overriding wxPropertyGrid::Insert, you'll probably want to override wxPropertyGridPageState::DoInsert. | |
1018 | ||
1019 | - Override wxPropertyGrid::CreateState to instantiate your derivate wxPropertyGridPageState. | |
1020 | For wxPropertyGridManager, you'll need to subclass wxPropertyGridPage instead (since it | |
1021 | is derived from wxPropertyGridPageState), and hand over instances in wxPropertyGridManager::AddPage | |
1022 | calls. | |
1023 | ||
1024 | - You can use a derivate wxPropertyGrid with manager by overriding wxPropertyGridManager::CreatePropertyGrid | |
1025 | member function. | |
1026 | ||
1027 | ||
1028 | @section misc Miscellaneous Topics | |
1029 | ||
1030 | @subsection namescope Property Name Scope | |
1031 | ||
1032 | - All properties which parent is category or root have their names | |
1033 | globally accessible. | |
1034 | ||
1035 | - Sub-properties (i.e. private child properties which have parent that is not category or | |
1036 | root or non-aggregate property) can not be accessed globally by their name. Instead, use | |
1037 | "<property>.<subproperty>". | |
1038 | ||
1039 | @subsection boolproperty wxBoolProperty | |
1040 | ||
1041 | There are few points about wxBoolProperty that require futher discussion: | |
1042 | - wxBoolProperty can be shown as either normal combobox or as a checkbox. | |
1043 | Property attribute wxPG_BOOL_USE_CHECKBOX is used to change this. | |
1044 | For example, if you have a wxFlagsProperty, you can | |
1045 | set its all items to use check box using the following: | |
1046 | @code | |
1047 | pg->SetPropertyAttribute(wxT("MyFlagsProperty"),wxPG_BOOL_USE_CHECKBOX,true,wxPG_RECURSE); | |
1048 | @endcode | |
1049 | ||
1050 | - Default item names for wxBoolProperty are [wxT("False"),wxT("True")]. This can be | |
1051 | changed using wxPropertyGrid::SetBoolChoices(trueChoice,falseChoice). | |
1052 | ||
1053 | @subsection textctrlupdates Updates from wxTextCtrl Based Editor | |
1054 | ||
1055 | Changes from wxTextCtrl based property editors are committed (ie. | |
1056 | wxEVT_PG_CHANGED is sent etc.) *only* when (1) user presser enter, (2) | |
1057 | user moves to edit another property, or (3) when focus leaves | |
1058 | the grid. | |
1059 | ||
1060 | Because of this, you may find it useful, in some apps, to call | |
1061 | wxPropertyGrid::CommitChangesFromEditor() just before you need to do any | |
1062 | computations based on property grid values. Note that CommitChangesFromEditor() | |
1063 | will dispatch wxEVT_PG_CHANGED with ProcessEvent, so any of your event handlers | |
1064 | will be called immediately. | |
1065 | ||
1066 | @subsection splittercentering Centering the Splitter | |
1067 | ||
1068 | If you need to center the splitter, but only once when the program starts, | |
1069 | then do <b>not</b> use the wxPG_SPLITTER_AUTO_CENTER window style, but the | |
1070 | wxPropertyGrid::CenterSplitter() method. <b>However, be sure to call it after | |
1071 | the sizer setup and SetSize calls!</b> (ie. usually at the end of the | |
1072 | frame/dialog constructor) | |
1073 | ||
1074 | @subsection splittersetting Setting Splitter Position When Creating Property Grid | |
1075 | ||
1076 | Splitter position cannot exceed grid size, and therefore setting it during | |
1077 | form creation may fail as initial grid size is often smaller than desired | |
1078 | splitter position, especially when sizers are being used. | |
1079 | ||
1080 | @subsection colourproperty wxColourProperty and wxSystemColourProperty | |
1081 | ||
1082 | Through subclassing, these two property classes provide substantial customization | |
1083 | features. Subclass wxSystemColourProperty if you want to use wxColourPropertyValue | |
1084 | (which features colour type in addition to wxColour), and wxColourProperty if plain | |
1085 | wxColour is enough. | |
1086 | ||
1087 | Override wxSystemColourProperty::ColourToString() to redefine how colours are | |
1088 | printed as strings. | |
1089 | ||
1090 | Override wxSystemColourProperty::GetCustomColourIndex() to redefine location of | |
1091 | the item that triggers colour picker dialog (default is last). | |
1092 | ||
1093 | Override wxSystemColourProperty::GetColour() to determine which colour matches | |
1094 | which choice entry. | |
1095 | ||
1096 | @section proplist Property Class Descriptions | |
1097 | ||
1098 | See @ref pgproperty_properties | |
1099 | ||
1100 | */ | |
1101 |