How DataFlex Handles Fonts
Font Sizes in DataFlex
DataFlex supports three ways to set a font size:
Physical_FontSize
This is approximately the size of a font in physical pixels. This allows you to set height and width, but you would always want to set the width to 0, allowing Windows to set the width. This varies from computer to computer and is not scalable. This is a legacy interface.
FontSize
This corresponds to the Windows LogicalFont (actually, it’s the positive number style of LogicalFont). This allows you to set height and width, but you would always want to set the width to 0, allowing Windows to set the width. As noted, LogicalFont varies from computer to computer and is not scalable. This is a legacy interface.
FontPointHeight
This corresponds to point height and it scales. FontPointHeight is a new addition to revision 17.0. This is the property you want to use. It renders FontSize and Physical_FontSize obsolete.
Font Size and Dialog Units
In DataFlex, object sizes and locations are set with dialog units. The GUI or pixel size of a dialog unit is determined by your font size. The average height and average width of characters is used to determine the number of pixels for both a vertical and horizontal dialog unit. The larger the physical font size, the larger the dialog unit will be.
While it should be obvious that changing the font height will change the physical size of a font, it should be noted that changing any font attribute might change the physical size of a font. Whenever the size changes, the dialog unit size changes. In other words, the dialog unit’s size is determined by more than just the font size. If you hold the size constant and change the typeface or font weight, the dialog unit size may change.
How Dialog Units are Used
The dialog unit is used by an object’s Size and Location properties as follows:
- The size of an object is determined by that object’s font size.
- The location of an object is determined by the parent object’s font size.
Restated, an object is located based on its parent’s font metrics, but is sized based on its own font metrics.
The Form_Font Properties
Some objects, such as Form, Combo, and Button, contain forms. This is a legacy concept. Since these objects are all single item objects, each object will only contain one form. These form objects contain an interface that duplicates the object’s interface. This is the case with font properties, where you have Form_Typeface, Form_FontPointHeight, Form_FontWeight, Form_FontItalics, and Form_FontUnderline.
Because forms are a legacy feature, we would normally advise that you not use these properties. With fonts, it turns out that these form properties have an unintended benefit. When you set the form_font properties, the size of the control does not change. This has the advantage that the control may line up better with its sibling objects and the disadvantage that the size may not be a good fit for the font.
Therefore, if you want the size of your control to not change based on your font, use the form_font properties. If you want the size of your control to change, use the regular font properties. Don’t use both in the same object.
Use this lightly. Be aware that this is an unintended behavior and that we may provide a better way of handling this in the future.
Global Typeface and Font Height
When an application is run, it needs to acquire a default typeface and font height. Prior to DataFlex 17.0, this was set to a Typeface of “MS Sans Serif” and a Physical_FontSize of 12. Because this uses the Physical_FontSize property, this setting would not scale with different DPIs.
As of DataFlex 17.0, you now simply specify that your default typeface and font height should be the Windows system default. Rather than using Physical_FontSize, the scalable FontPointHeight is used. In Windows Vista and 7, the default is Segoe UI/9pt; in XP, it is Tahoma/8pt.
This default typeface and height is applied to DataFlex objects. COM objects will have their own mechanism for font assignment, although the norm will be to use the same Windows default typeface and point height. Therefore, the appearance of DataFlex and COM fonts will be consistent.
How Fonts are Assigned to Objects
Rule 1: When a container object is created, it uses the global font.
Rule 2: When a control object is created, it uses its parent container’s font.
These two rules will explain most of the behaviors you see in an application. They are a simplification of the actual process, which will be described in detail. For now, this may be all you need to know and may wish to skip this section and revisit it later.
Font assignment is somewhat complicated. It is probably best to look at this from two perspectives. The first is an application that assigns no explicit fonts at all. Anytime you set one of the font messages (e.g., Typeface, FontPointHeight, FontWeight), an explicit font is created for that object. Defining custom font characteristics is the second perspective, and this makes things more complicated. We will start with the simpler case where there are no custom fonts at all.
Using the Default Font Settings
Font assignment differs with Containers and Controls.
-
Containers: A Container gets its font based on the global typeface and font height; it creates a new font and assigns it to itself. Therefore, each container creates and owns its own font. The font is created when the object is created. (To be fully accurate, the container creates a copy of its parent’s font, but then sets the typeface and font height as described above. So in the unlikely case that you’ve set a custom font weight, italics, or underline in the parent, it is acquired by the child container, while the custom typeface and font height are not.)
-
Controls: A Control uses its parent font (i.e., it uses its parent container font). It uses this font directly and does not make a copy of that font. In addition, many of our controls have a “form” interface where there is an additional form (or forms) inside the control object. Once again that form delegates to its parent (the control), which delegates to its parent (a container). Since the container has a font, that font is shared by the form.
Therefore, in a default setup, an explicit font is created for every container. That font is shared by all child controls but not child containers. There are some exceptions here with some objects such as cTextEdit and TreeViews and COM objects.
Assigning Your Own Font Settings
You create a custom font by setting one of the font properties (e.g., Set FontItalics to True). Once you do that, the object will now create its own explicit font, and it will not delegate to share a parent font.
-
Containers: When you create a font in a container, the existing container font is replaced with the new font.
-
Controls: If you create a font in a control, a new font is created and explicitly assigned to the control. If a font already exists for the control, it is replaced with the new setting. Note that a form font will now use this as its shared font. However, if you create a form font, a new font is created for that form. If a form font already exists, it is replaced.
When you create a custom font, the size of a dialog unit may change, which means that the size of the object and the location of its child objects will change based on the font’s dialog unit. This creates the issue where you might have two forms with the same dialog size (e.g., set Size to 14 100) with different fonts (typeface, weight, or height), which will appear as different sizes on your screen. Sometimes this is desired and sometimes not. There is an important and useful exception with form fonts. If you create a custom form font, the size of its control does not change.
The Complexity of Mixing Default and Custom Fonts
There are a number of challenges when you start working with custom fonts.
-
Containers do not obtain all of their default behavior from their parent. Containers always create their own font using the global typeface and font height. If you had two nested containers A and B, you set a font in A, its child (B) would not acquire this font and would use the global font instead. To make this even more confusing, any child controls in A would use the new font, while child controls in B would use the global font.
-
Containers and controls behave differently. If you place a control and a container inside of a parent container and assign the parent container a custom font, the control will use that font while the container will not. This means that the sizing of the container and control siblings will be different. To make this work, the developer would have to apply a custom font to either the child container or child control object.
-
The existence of fonts and form fonts is confusing. For the most part, these two types of fonts do the same thing and they exist for legacy reasons. Normally, we’d tell developers to just use the font interface, but the fact that form fonts do not resize the control can, in certain cases, be useful.
-
With controls, it is not really clear where the font is coming from. It can be shared from its parent container, it can be defined in the control, or defined in the control’s form.
-
When custom fonts are applied after a control is paged, there is a bit of an inconsistency. The control is redisplayed using the new dialog units, but child controls are not relocated using that new metric.
While all of this may seem confusing, this can be simplified by following a few simple guidelines. These will be discussed later, but the important point here is to avoid setting fonts in containers. If you need to set a font, set it in the control. This way, containers always use the same metrics for sizing themselves and locating child objects.