We've covered sets in past issues of C++Builder Developer's Journal, but one particular aspect of sets bears repeating. That aspect deals specifically with adding elements to a set when a set property includes a write method. First, let's look at the syntax for adding elements to a set in C++Builder:
// Declare a set of characters from A to Z. Set<char, 'A', 'Z'> mySet; // Add A to the set. mySet << 'A'; // Add B and C to the set. mySet << 'B' << 'C'; // Remove B from the set. mySet >> 'B';All of the above code is valid and works just as the comments indicate. Now let's take the case of a property that's a set. The Font class' Style property provides a perfect example. To change the font style of a label to bold, you might, logically, write code like this:
Label1->Font->Style << fsBold;The problem is that this code doesn't have the desired effect--the label's font doesn't change to bold. To understand why this code doesn't work, you need to understand how the VCL deals with properties. Some properties use direct access. When you write to the property, the property's underlying data variable is simply assigned a value. Other properties have write methods. If a write method exists for a property, that method is called whenever a value is assigned to the property. This is what causes a form to move when its Top property is assigned a value, an edit control to display a value when its Text property is modified, or a label's font style to change when its Font->Style property is written to.
The problem when writing to a set property is that the set insertion (<<) and extraction (>>) operators don't result in an assignment. Because there's no direct assignment, the property's write method is never called. Therefore, the property's value never changes.
Label1->Font->Style = Label1->Font->Style << fsBold;Right-to-left code generation ensures that the fsBold element is added to the set and then the result is assigned to the Style property. This allows the write method for the Style property to be called and the label's style to be properly modified. Another way to perform an assignment to a set is to create a temporary set, add elements to the set, and then assign the temporary set to the property. For example:
TFontStyles style; style << fsBold; Label1->Font->Style = style;This code can be condensed as follows:
Label1->Font->Style = TFontStyles() << fsBold;In both of these examples, a direct assignment is involved and the Style property is properly updated as a result. It's important to understand that the two methods shown for modifying a set property aren't identical. The first method takes an existing set, adds a value, and assigns the result back to the set. The second method creates a new empty set, adds one or more values, and assigns the new set to the property. The second method can easily be modified to emulate the first as follows:
TFontStyles style = Label1->Font->Style; Label1->Font->Style = style << fsBold;Regardless of which method you use, be sure that you always make an assignment when dealing with properties that have a set as the underlying data type.