As you probably know by now, the VCL that comes with C++Builder is written in Pascal. While this isn't a problem, the situation does raise certain issues for the C++Builder programmer--some features found in Pascal don't exist in C++, and vice versa. One Pascal feature that C++ doesn't have is the set. In this article, we'll explore sets and how C++Builder handles them. Let's begin with a little background information.
Typically, the individual elements you use with a set come from an enumeration. For instance, the font styles we just mentioned come from the TFontStyle enumeration. The TFontStyles set, then, is created as a set of TFontStyle values. The VCL source declaring these objects is as follows:
TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut); TFontStyles = set of TFontStyle;Most of the sets you'll use in VCL follow this same architecture--you have an enumeration that declares a set, which can contain values of that enumeration.
Typically, you'll turn the font's individual Style values on or off at design time. Sometimes, however, you need to set the font Style property at runtime. In that case, you'd use code like the following:
Font.Style := []; Font.Style := [fsBold, fsItalic];The first line clears the Style set by assigning an empty set (designated by empty brackets) to the Style property. The next line adds the fsBold and fsItalic values to the set. When you use the font, your text will appear in bold italics. (Note that the first line of code in this example isn't really necessary. I included it to show you how to clear a set.)
Now, let's say that you want the font to be bold and underlined, but not italic. You need to remove the italic style and add the underline style, while leaving the bold style in the set:
Font.Style := Font.Style - [fsItalic]; Font.Style := Font.Style + [fsUnderline];And that, my friends, is how you add elements to--and remove them from--a set in Pascal.
Besides changing set elements, you may want to see if a particular item is in a set. Let's say you want to know whether the font is currently bold. You can determine if the fsBold style is in the set as follows:
if fsBold in Font.Style then Font.Style := Font.Style - [fsBold];The in keyword returns true if the particular value is in the set and false if it isn't in the set.
// the initial bitfield with two styles unsigned int flags = MB_OK | MB_ICONEXCLAMATION; // remove the icon style flags &= ~MB_ICONEXCLAMATION; // add a help button to the message box flags |= MB_HELP; // show the message box ::MessageBox(Handle, "Test Message", "Message", flags);This mechanism works fine, but it isn't very useful when you're dealing with VCL, because VCL uses Pascal sets. For this reason, Borland had to come up with a way to emulate sets in C++Builder. As an added benefit, the concept of sets is easier for beginning C++ programmers to understand than is the concept of bitfields. (C++Builder is all about rapid application development, and part of RAD is getting programmers up to speed as quickly as possible.)
Let's return to our earlier examples of how to add and remove elements from a set in Pascal:
{start with an empty set}
Font.Style := [];
{add the bold and italic styles}
Font.Style := [fsBold, fsItalic];
{remove the italic style}
Font.Style := Font.Style - [fsItalic];
{add the underline style}
Font.Style := Font.Style + [fsUnderline];
Now, let's see how the corresponding code looks in C++Builder.// start with an empty set Font-$gtStyle.Clear(); // add the bold and italic styles Font-$gtStyle << fsBold << fsItalic; // remove the italic style Font-$gtStyle $gt$gt fsItalic; // add the underline style Font-$gtStyle << fsUnderline;First, notice that you can use the Clear() function--a member of the Set template--to remove all elements from the set. Next, notice how you can add elements to the set using the insertion operator (<<). If you have C++ experience, then you've seen similar syntax in the C++ streaming classes. The insertion operator adds the item to the right of the operator to the set; you can chain insertion operators to add several elements to a set at one time.
Finally, the extraction operator ($gt$gt) removes elements from the set. You can also chain extraction operators to remove several elements from the set simultaneously.
if fsBold in Font.Style then Font.Style := Font.Style - [fsBold];The code checks to see if the bold style is set and, if so, removes it. However, C++ doesn't have the in keyword. Instead, the C++ Set template has a function called Contains(), which serves the same purpose. The C++ equivalent of the previous code is as follows:
if (Font-$gtStyle.Contains(fsBold)) Font-$gtStyle $gt$gt $gt$gt;
Once again, let's look first at how to create the set in Pascal:
MessageDlg("An error has occurred...",
mtError, [mbOK, mbCancel], 0);
Now, look at the C++ code for the same set:MessageDlg("An error has occurred...",
$lt$lt mbOK $lt$lt mbCancel, 0);
In this case, the Pascal code is a bit more elegant than the C++ implementation. You create the Pascal temporary
set simply by using the square brackets with the elements you wish to include in the set. In C++, you create a
temporary set, then add the elements using the insertion operator. That part of the C++ code is as follows:TMsgDlgButtons() << mbOK << <<e$gt$gt $gt$gtnuse this simple syntax any time you need a temporary set.
Kent Reisdorph is a editor of the C++Builder Developer's Journal as well as director of systems and services at TurboPower Software Company, and a member of TeamB, Borland's volunteer online support group. He's the author of Teach Yourself C++Builder in 21 Days and Teach Yourself C++Builder in 14 Days. You can contact Kent at editor@bridgespublishing.com.