Tech News Back Issues Issue: 032008
Button, Button - Which Kind Of Button?
Well, it had to happen sooner or later. We now have a choice to make when we want to place a set of radio buttons onto the face of a Window class. Omnis Studio version 4.3 now supplies both traditional Radio Button fields and a new field type called a Radio Group. We have seen this "new" control on remote forms for quite some time, but this is a new field type for a window class.
There are some definite advantages to using a Radio Group rather than a cluster of our traditional Radio Button fields. The most obvious advantage is that we don't have to worry about keeping all those radio buttons in data entry order or about making sure that they all reference the same variable in their dataname property values. All the buttons are in one field control, so there is only one dataname property to concern us. They can be copied, pasted and dragged around as though they were grouped together (or were contained in a borderless group or scroll box field) since they are, in fact, the same field. We also don't have to worry about aligning them with one another - if we, indeed, want to line them up. And we can even manage events that happen to them in one place - like the technique I have long demonstrated in classes of enclosing a collection of Radio Button fields inside a Group Box field and using the $control method of the Group Box to handle events for those buttons. So a number of setup and operational processes would appear to be made simpler with the addition of this new field type.
But is the Radio Group a replacement for a group of Radio Button fields? Far from it! While a Radio Group field is a great substitute for a simple set of basic radio buttons clustered together in the same area on a window, it lacks the flexibility of a "complete" radio button field. So we will also review some of those features in this article while answering the question "When would we want to use which kind of radio button on a window class?".
Radio Group Basics
Perhaps this is too basic, but let's begin with the purpose of a radio button control in general. Such a control object is used to make a mutually exclusive choice among a number of options. There are usually more than two options when we use this control type, since a simple binary choice (on or off, for example) is generally better performed using a Checkbox field. (A single Checkbox takes up less space than two Radio Buttons...)
In desktop applications (and increasingly even on web pages where the developer has done some additional coding), a click on either the radio button or its associated label (or even on some of the empty space after the label text) is recognized as making the corresponding choice. This gives the user a larger target than just the little button icon itself, making the control easier to use.
Although the buttons are labeled, such a field generates (and the database then stores in the variable associated with the buttons) an integer number to indicate the choice made by the user rather than the label string chosen. A Short integer value stores more compactly that the indicated Character string value and can be more easily manipulated or compared in other operations. Such numeric values might also be mapped to ENUM columns (enumerated string value lists - which are also stored as integers) in a SQL database, although such data types usually begin counting options with the value of 1 while Omnis Studio button controls of this nature (and those of most other programming languages) begin generating values with 0. So an offset of 1 (adding 1 to the button field output) is required to keep the two in synch when using Radio Buttons with ENUM values.
Setting up a Radio Group field is quite simple. There are relatively few options compared to those we are given for individual Radio Button fields. Many of the options are used, in fact, to simplify the grouping of the buttons. But there are very few options for modifying their appearance, layout or availability - and none of those can be applied to individual buttons within the group. Here are the basics:
First, we determine the number of buttons for a Radio Group field by simply specifying an integer quantity for the buttoncnt property (too easy!). These buttons are then layed out in an orderly rectangular grid by combining the values of the columncnt and horizontal properties. (These three properties are all found under the Appearance tab in the Property Manager - and if we switch off the "Sort by Property Name" option for the Property Manager, they are grouped together at the bottom of the list of Appearance properties.)
There are only a few configuration options available for our buttons. We could have a single column of buttons (columncnt = 1, horizontal = kFalse), a single row of buttons (columncnt = buttoncnt, horizontal = kTrue) or a grid with multiple columns and rows (with button numbers increasing down the columns or across the columns depending on the value of horizontal). Our biggest problem would appear to be making sure that the field itself is high enough and wide enough to accomodate all the buttons we have specified and their labels - otherwise some of the content of the field will be hidden.
Oh yes, the labels! We set the labels for the buttons by placing a comma-separated list of label strings in the text property (found on the General tab of the Property Manager). If we provide too few labels, some of the buttons will simply remain unlabeled. If we supply too many, the extras will simply not appear (but the extra label strings do remain in the property value, so they can be exposed by dynamically increasing the value of buttoncnt at runtime).
If necessary, we can dynamically change labels at runtime by reassigning the entire text property string value. But there are other things we can do with this property as well...
Label Text Options
By the way, the text property of a Radio Group, just like that of a Radio Button, supports Square Bracket Notation. That is, we can dynamically assign label text for the buttons in a Radio Group using variables rather than reassigning the entire text property value. This can be handy for multi-lingual applications, but it can also be used for changing button labels as we move from row to row in the database.
Just make sure that the value of each variable used in this way is populated before redrawing the Radio Button field. If a variable is NULL or empty, the buttons can really get messed up!
But although we can use Square Bracket Notation here, we want to keep it as simple as possible - preferably limiting ourselves to using only (short - or appropriately long) variable names rather than lengthy and complex expressions. This is because the length of our square bracket expression is used to determine the spacing for our labels - not the length of the resulting label string. There are two possible problems with this:
If the value generated by our square bracket expression is significantly shorter than the expression string itself, there could be an embarrassing gap:
If the value generated by our square bracket expression is significantly longer than the expression string, it will spill over into the next column:
But if we are careful, by doing this only with an "orphan" button, we can take advantage of this "feature":
Although a Radio Group field can evaluate expressions placed within square brackets, it does not support styled text. If we were to place the style() function in square brackets within the text property value, we would see the 11 character escape string the function generates (remember, some of the characters may not be printable) rather than a style effect on our window instance:
And we might also see some stranger behavior on the window design class associated with this (due to the comma character in the parameter list of the style() function - which could apply to any expression that uses functions, really):
We have little control over the spacing of the buttons in a Radio Group field. There are no properties for row height or column width and we can't inject a tab to a specific position using the style() function. Omnis Studio looks at the label strings we have chosen to use (the strings in the text property value - including any square bracket expressions) and adjusts the button widths accordingly. Our choice of font - especially the font size - determines the row height. On Mac OS X, it appears that using a "theme" font yields a nice spacing automatically - especially the ThemeApplication font. Using too small a font would cause a vertical group of buttons to touch. So using a fieldstyle becomes even more important.
We can make the labels a bit wider by adding trailing space characters to each entry, but spaces are usually narrow in most fonts so it may take quite a few to make a difference. Here I added eight spaces to make the label space a little wider:
The first button (the one that generates a value of 0) is always in the upper left corner of this control. We cannot change this anchor point for a Radio Group. The buttons will always be in a logical order - and again, the order of the buttons is determined by the combination of the columncnt and horizontal property values. This is mainly of concern if there are multiple rows and columns (columncnt is non-zero). In that case, if horizontal is kFalse, the buttons are numbered down the leftmost column and then down each subsequent column. But if horizontal is kTrue, the buttons are numbered across the top row from left to right and then across each subsequent row. The label text is assigned based on this order.
As with Radio Button fields, a Radio Group field contains an iconid property. This is used to change the icon used to display the state of a given button in the group. But the icon used by a Radio Group does not appear to change on Mac OS X (10.4.11 is all I have tested so far), although changes to the iconid property on Windows (XP) display the selected icon just fine. Radio Button field icons change as expected when the iconid value is changed, though. But a number of issues on the various versions of Mac OS X have been reported (since Apple continues to change the rules that software developers must follow - often without warning!) and an update to Omnis Studio 4.3 is promised soon specifically to deal with Mac OS X issues (and maybe a few new options...).
A couple of friendly notes of warning on changing the icon, though:
First, make certain that you have chosen the id number of a multi-state icon. This will assure that a similar, but changed, icon will appear when the button is in different states. Second, try to use an icon that is reasonable for a radio button. Some of the multi-state icons are designed for other things and may not give an intuitive signal to the user. For example, icon number 613 (the plus/minus box for Windows tree lists found on the Multistate 2 page of the Omnispic icon datafile) shows a minus when selected and a plus when not selected. Then again, it was designed for indicating actions on exposing or hiding tree list node contents, not for use with radio buttons.
Of course, we can always create our own icons if the ones provided do not suit our particular needs. (See the Omnis Tech News article on "Icons and the Icon Editor" published 3 April 2002 - yet another ancient Tech News article that could use updating - including adding some illustrations! The current Omnis Studio icon technology offers us alpha channels and the ability to have multiple icon datafiles of our own creation, among other improvements since 2002.) If we want to make custom icons for use with Radio Group or Radio Button fields, we must make certain that we create them on a multi-state icon page - and then create the appropriate look for each of the states specified on that page.
What's Missing From A Radio Group?
Did I say "missing"? Perhaps "different from a Radio Button" would be a better turn of phrase. There are a number of appearance options that we have had for Radio Button fields for a long time that are not available currently for the Radio Group field type. In addition, the freedom the Radio Button field type offers us (along with a little more work) allows us to create much more flexible interfaces involving choice buttons than a static block of them. So the new Radio Group is great for setting up and maintaining a simple set of buttons that we want to be all on a block, but there are a number of layout scenarios where we need more freedom of expression.
So the biggest thing "missing" (there's that word again) from the Radio Group field type is the ability to apply certain features to individual buttons. But that is why we continue to have the Radio Button field type as well. For example, the visible, active and enabled properties (as well as tooltip and disablefocus) also are applied to all buttons at once for a Radio Group field. Of course, this makes perfect sense from one point of view, but this can be a disadvantage occasionally (as is discussed below). Also, if the value of the associated variable is changed, we only have to redraw the one Radio Group field rather than remembering to draw a number of separate Radio Button fields - so that is a feature "missing" from the Radio Button field type in some sense.The advantages of a Radio Group field are the even spacing and automatic layout attributes, as well as unified event handling and the unified dataname property. The disadvantages are that those advantageous features limit us in a number of ways.
In addition, there are some options the Radio Group field type just hasn't been given...
Radio Button Style Options
Just like with Pushbutton fields, we have a number of appearance options for Radio Button fields with the buttonstyle property. This is only a property of a Radio Button field, not of a Radio Group field. Here is a brief description of each option for this property:
kNoBorderButton is the built-in default buttonstyle property value for a Radio Button field. This is the only style option we have for a Radio Group, though, since there is no property for changing this aspect of the fields appearance. If we switch off the background pattern for such a field (or for a Radio Group field), the field becomes transparent (except for the text it displays - and the button icon, of course). This means that we can see the background of the container through the field. We can even see background skins if that feature is being utilized. (More about that some other time!) Radio Button fields with this buttonstyle value will generally not have a colored background. In fact, the forecolor, backcolor and bordercolor properties are all greyed out in the Property Manager. However, if we change this property to one of the other options and then change it back, we will notice that the Radio Button field now has a solid color background - even though the color properties are disabled. This issue can be remedied by removing and then reapplying the fieldstyle property value. (I have tested this on both Mac OS X and Windows XP with the same results.)
But there are many other options for the style of a Radio Button field. For the sake of completeness, let's briefly examine those style options - options of which some Omnis developers may not be aware...
kSystemButton is the first option past the default presented in the dropdown list offered by the buttonstyle property in the Property Manager. If we select that, our Radio Button field looks like a standard pushbutton - complete with any "3D-ness" applied by the operating system. Again, a button of this style cannot be colored or patterned. When such a button is selected at runtime, it displays appropriately for the given platform. On Windows, the button is rectangular. When selected, it looks indented and shows a dotted rectangle around the label text. On Mac OS X, the button is lozenge-shaped with a 3D appearance. The selected button takes on the standard aqua color while an unselected button remains greyish. On either platform, this has a look reminiscent of the buttons on an old car radio (if those buttons weren't round) with the text of the label on top of the button. We cannot assign foreground or background colors to this style of button.
We can include a multi-state icon on this button and it will further indicate the state of the button. Or we could use a static icon along with or as a substitute for the label text. The field alignment for the button determines where the icon is located relative to the label text.
The "center" option would normally place the icon above the text, but there is not enough vertical room on a system button on Mac OS X to do so. This is because the height of a system button is fixed at 22 pixels on this platform. On Windows XP, this style of button can be given a greater height - and the icon is centered above the text when the align property value (found under the Text tab in the Property Manager) is set to kCenterJst.
We can also make any of the text-bearing button styles contain multiple lines of label text - except for the default kNoBorderButton option mentioned above. To do this, we indicate a line break using a double forward-slash character string (//). (The text will not automatically wrap onto multiple lines, so we have to help it a little.) This usually looks best if the field is center-aligned. If you were not aware, we can also use this technique for causing line breaks in the text of dialog boxes. While we can perform this feat on all platforms, the height limitation of a system button style on Mac OS X makes this look a bit odd. On Windows, where we can make the field taller, this works perfectly fine. The other styles that display text labels work fine for this feature on Mac OS X as well.
kHeadingButton is the next option. The Radio Button field with this buttonstyle property value looks like the column heading of a Headed List field. This button style displays a rectangular button on all platforms with the label text again displayed within the button. On Windows XP, the button is basically white, but displays as "indented" when selected. On Mac OS X, the button has a 3D quality and is darkened when selected. We cannot assign color to this type of button either.
Oh yes, and we can make buttons of this style, or of the "user button" style detailed below, any size we wish on all platforms.
A Radio Button field with the kComboButton option displays as a pushbutton with a downward-pointing arrow on it. On Windows XP, this button is the width of the field (we can adjust both the height and width on that platform), has a slight 3D-ness to it and a chevron-shaped arrow. The selected button of the set is a darker grey. On Mac OS X, the button is 21 pixels square (no matter how large the field is made), had a 3D aqua look and a solid triangular arrow. The selected button in the set is a slightly darker aqua color. And we still cannot assign color to this type of button. I have added a checkbox icon into each of the Radio Button fields shown here to help indicate which one is selected from the group. this button style does not display label text, but does display an icon (to the side) if we assign one.
The kUserButton option yields a rectangular button with a 3D look on all platforms - and one that can be colored if we wish. The forecolor, backcolor and bordercolor properties for the field become enabled when this option is selected. The selected button becomes a dark grey no matter what color or pattern of colors is applied to the field. The text retains whatever color it had, so it might be wise to detect the change of which button is selected and lighten the color of the selected button so that it can be read more easily. (Or use a dark color with white textcolor for all the buttons, allowing the dark grey to indicate which is selected.) Any color selected while this option is in force will be retained by the field and appear in the Property Manager when another buttonstyle option is selected - even though that color will not be realized on the field itself. This is the only one we can make truly ugly on any platform!
The kRoundButton and kLargeRoundButton options are primarily for the Mac OS X platform. (The large round button style first appeared in Omnis Studio version 4.2) In fact, these button types are not at all round on any other platform! On Windows XP, they take on the same look as kSystemButton provided - but without the label text. They can also be made any size and the vertical gradient used to provide the 3D look is spread across the entire height - although it is less convincing at larger sizes. But on Mac OS X these appear as translucent round buttons with a diameter of 19 or 27 pixels respectively. Making the fields area any larger is pointless, but making it smaller clips the button image. These buttons do not display text (on either platform). Rather, they are used to display only an icon - but here we use a normal, static icon for these instead of a multi-state icon. In fact, the multi-state icons only statically display their default, unselected image even when this kind of button is in its selected state. For reasons of pure arithmetic, the k16x16 size is most appropriate for this control - and even that can be a bit cramped on the smaller of these buttons! Possible specialized use: Changing states of the window (or some part of it, such as a page pane) where a tab strip does not provide the proper look. In fact, even without an icon, these button types (especially the smaller one) can be quite effective when coupled with paragraph-sized multiline label text blocks (on Mac OS X, at least).
The Power of the Individual
With a Radio Group, all buttons in the group are enabled or disabled, hidden or shown together. It is not possible to disable or hide individual buttons within the group at this time. Yet there can be occasions where one or more choices may not be appropriate given other aspects of the current data or choices made on previous "screens" (in a "wizard" scanario). Sets of Radio Button fields do not have this limitation. An individual Radio Button can be disabled or hidden without affecting the other buttons in the set. We do not (yet) have a property or method for a Radio Group field that allows us to change these aspects of individual buttons within a Radio Group field (similar to our ability to change the alignment of individual columns in a Headed List field at runtime using the $setcolumnalign() method) - but perhaps we never will.
Another property not shared between Radio Group and Radio Button fields is the local property. A Radio Group cannot be made local to another field as can a Radio Button field. A properly created set of Radio Button fields (where they are in contiguous field number order and they address the same variable) are already "internally local" amongst themselves when their local property value is at its default setting of kFalse, but this property allows us to make the first of these buttons (and, therefore, the entire set) local to a field outside the group.
Advanced Radio Button Techniques
Then there is some design territory that is simply out of reach for the Radio Group field type. So individual Radio Button fields still have their place in the toolkit! Here are some additional techniques to consider (by no means an exhaustive list!):
Sometimes we might have entire paragraphs of text that we must use as the "labels" for a set of Radio Button fields. Those fields cannot display multiline labels, so we must use separate objects for that text. Since we also need to react to a click on the label text to select a button, our best choice for the label text object is probably a Shape field. this is a special field that can take on the aspect of any background object, while having the event handling features of a foreground object (like click detection in a $event method). All we have to do is make sure that the Radio Button fields themselves are in proper field number order (the field numbers of the Shape fields can be anything) and then queue a click on the corresponding Radio Button field when a click is detected on one of the Shape fields. That code would look like this:
The "coverage" for a given button-label combination would be as shown here (pass your mouse over the illustration):
Fig. 21 - Coverage Area When Using Shape Fields For Multi-Line Labels With Radio Buttons
We can also do this if the choice description is a picture or some combination of picture and text fields. Again, Shape fields are good choices for large labels of any background object type.
Since each Radio Button field can be independently placed, we can arrange them in such a way as to provide secondary choices with Checkbox or additional sets of Radio Buttons (or Radio Groups). This requires some fancier coding, but it may well come up in practice. We could even make the main Radio Button fields move to expose the sub-choices for the selected button:
Each situation will be different, but the advantage of having a separate $event method for each button will be immediately apparent if you find yourself needing to go down this road.
There will be times when something about the current row in one table dictates that one or more button choices for a row in another table should be disallowed. In such cases, we need the ability to either disable (grey out) one or more buttons from a set of Radio Buttons or simply make the temporarily inappropriate choices invisible. Changing the enabled or visible property value to kFalse for one of a set of Radio Button fields has no affect on the operation of the group - beyond disallowing that one button, of course. This was illustrated in Figure 20 above.
In addition, we might find ourselves in the position to spread a set of Radio Buttons onto various locations on a window. No problem if we are using Radio Buttons since we must place them individually anyway. We just have to take extra precautions to make sure that we do not accidentally interfere with their field order when manipulating other objects in design mode. We can help prevent such problems by first grouping those fields and then locking them once we feel they are in the proper positions.
As we can see, even something as overtly simple as a set of radio buttons can offer a great deal of variety when we start poking around and exploring its secrets. The new Radio Group field type is a welcome addition to our toolkit fo the simple cases because it makes our work even simpler. But the Radio Button field type is still there for those special needs.
In The Next Issue
I hope you find what I have presented here to be useful. In the next issue of Omnis Tech News I will revisit the Graph2 component and highlight the new features that have been exposed in it with Omnis Studio version 4.3. this component becomes more impressive with each release!
Copyright of the text and images herein remains with the respective
author. No part of this newsletter may be reproduced, transmitted,
stored in a retrieval system or translated into any language in any
form by any means without the written permission of the author or
Omnis® and Omnis Studio® are registered trademarks, and Omnis 7 is a trademark of Raining Data UK Ltd. Other products mentioned are trademarks or registered trademarks of their corporations. All rights reserved.