This tutorial is an update to the 2019 tutorial. If you have zero experience with the UI Theme feature, please first follow our Quick Start tutorial. If you are ready to gain a comprehensive understanding of this feature and dive deeper into UI Theme settings, then please proceed with this updated tutorial.
Starting from PowerBuilder 2019, Appeon added the UI theme feature to PowerBuilder so that developers can codelessly control how commonly-used controls and objects render during application runtime.
UI Theme configuration
You can configure the UI Theme to apply to an application in the Additional Properties > Themes settings of the application object.
- Theme Path -- This is the path to the directory that contains the UI Theme definition files. The default theme path is %Appeon%\Shared\PowerBuilder\theme190. When you install PowerBuilder, the installer will put all the system theme definition files in the default path. You can specify a different path (absolute or relative to the PBT file of the application) if the path contains the theme definition file you plan to use.
- Theme Options -- PowerBuilder will check in the given theme path to get all the folders that contain the master theme definition file "theme.json". The name of the folder that contains "theme.json" will be listed as a theme option.
The default theme path contains four system themes: Flat Design Blue, Flat Design Dark, Flat Design Grey, and Flat Design Silver. Table below shows you the major UI features of each system theme, and the differences between the themes and the “Do not use theme” options (the UI rendering option in previous PowerBuilder versions).
|
Do not use theme |
Flat Design Blue |
Flat Design Dark |
Flat Design Grey |
Flat Design Silver |
Window background color |
Set in the painter or script |
White |
Dark |
Grey |
White |
Font color |
Set in the painter or script |
Black |
White |
Black |
Silver Black |
Control background color |
Set in the painter or script |
White |
Black |
White |
White or Shallow Color Block |
Button |
System |
2D |
2D |
2D |
2D |
Border |
3D |
2D |
2D |
2D |
No Border |
Border thickness |
1 pixel |
1 pixel |
1 pixel |
1 pixel |
No Border |
Furthermore, please pay attention to the following configuration if you select to apply a UI Theme:
- Disable the "Windows classic style" option in the PowerBuilder Project painter
If "Windows classic style" is selected, the application UI will be always rendered in the Windows classic style. - (At runtime) Do not use "Windows Classic" theme in the Windows operating system
When the application is run in the Windows system with "Windows Classic" theme, the application UI will be rendered in the Windows Classic theme. - Disable the "Use Windows XP style DPI scaling" option in Windows 7, Windows Server 2012, or earlier.
If the scaling percentage is set to 125% or lower, the "Use Windows XP style DPI scaling" option will be automatically selected, which will prevent the selected theme working correctly. In such case (125% or lower), you should manually uncheck the "Use Windows XP style DPI scaling" option.
UI Theme functions
There are two UI Theme functions: ApplyTheme and GetTheme.
ApplyTheme
Instead of specifying the theme to use in the Additional Properties of the application object, you can set a theme dynamically in your source code using the ApplyTheme method.
For example, the following script applies the "Flat Design Blue" theme in the default theme path of the current application:
ApplyTheme ("Flat Design Blue")
The following script applies the "Flat Design Blue" theme in D:\App1SourceCode\themes\.
ApplyTheme("D:\App1SourceCode\themes\Flat Design Blue")
The following script applies the "Flat Design Blue" theme in themes\ folder in the directory that contains the PBT.
ApplyTheme("themes\Flat Design Blue")
Recommended practices:
- Avoid specifying the absolute theme path in the function, because the path must be true in both the development and runtime environment.
- Call the ApplyTheme method in the Application Open event when all of the child windows have not yet opened.
- Add an open dialog box for an application, in which you provide the theme options that you allow users to select by themselves.
GetTheme
You can get the theme that is currently applied to the application UI using this method.
For example, the following example gets the theme name that is currently applied to the application:
String ls_themename
ls_themename = GetTheme()
UI Theme definition
System themes
If you open the default theme path %Appeon%\Shared\PowerBuilder\theme190, you will see four folders in it: Flat Design Blue, Flat Design Dark, Flat Design Grey, and Flat Design Silver. Each folder contains the UI Theme definition files of the corresponding theme. There are only two types of files for the purpose:
- Theme.json file. This is the master theme definition file. It clearly sets the visual appearances of all possible elements of system objects and controls. The file is well structured so it should be easy to follow. Refer to Supported and unsupported theme settings for details on the theme settings required in the theme.json file.
Note: Compared with version 2019, the theme.json file in version 2019 R2 add more theme settings (JSON nodes):
"graph-control"->"hover-state"
"graph-control"->"focused-state"
"groupbox"->"background-transparent"
"groupbox"->"normal-state"->"background-color"
"singlelineedit"->"placeholder"
Therefore, if you have customized the theme.json file in version 2019, be careful not to directly copy it over to version 2019 R2. It would result in rendering failure of the UI theme.
- Numerous BMP, ICO and PNG files. These are the image files referenced in "theme.json". They are used to make up the visual elements in the theme.
Custom themes
You can add a new folder in the theme path to create a custom theme. In case it is too complicated to create a custom theme folder from scratch, you can duplicate an existing system theme folder and use that as the starting point for your custom theme. Yes, make sure to include the master "theme.json" file in the custom theme!
Custom theme definition files for selected objects or controls
The "theme.json" file applies globally to all the objects and controls in the application. For either a custom theme or system theme, you can define special visual override for selected objects or controls, such as:
- Configuring the theme settings of a window/user object;
- Configuring the theme settings of all controls of a specific type (such as CommandButton) in a window/user object;
- Configuring the theme settings of a specific control in a window/user object.
The way to do it is to add one or more custom theme definition files in the theme folder, following these rules:
- The new theme files shall follow this format: theme-[xxxx].json. The file prefix must be "theme-", [xxxx] can be any text, and the extension must be .json. For example:
theme-123.json
theme-abc.json
- The settings in the file can be a subset or all of the "theme.json" file. While the nodes that host theme settings are the system object or control name in "theme.json" (such as "checkbox", "commandbutton"), the nodes that host theme settings in the custom theme files shall be the name that points to the specific object(s) or control(s) that will apply the settings. For example:
{ "meta-info": { "version":"190" }, "w_main.uo_1.cb_1": { ... // Copy the settings from the "commandbutton" node of //the "theme.json" file and then modify } "w_main$commandbutton": { ... //Copy the settings from the "commandbutton" node of //the "theme.json" file and then modify } "w_main": { ... //Copy the settings from the "window" node of //the "theme.json" file and then modify } }
- Pay attention to the precedence on which settings would apply if multiple settings are defined for the same object/control:
- If there are multiple theme-[xxxx].json files, the settings in the last file in alphabetical order will be applied.
- From the highest to the lowest priority: settings configured for the specific control (in theme-[xxxx].json) > settings for controls of the same type (in theme-[xxxx].json) > generic settings for controls of the same type (in theme.json).
For more details about defining custom theme files and examples, you may further refer to:
UI Theme deployment
When you deploy the application, make sure to deploy the following two runtime files together with the application for the UI Theme support:
- Pbtheme190.dll
- Pbjson190.dll
Also, you must copy the theme definition folder (with the folder name being the same as the theme name) into the root directory of the application .exe file. The following explains the right way to do it:
- If you set the theme to use in the Additional Properties of the application object: Create a "theme190" folder in the root directory of the application .exe file, and then copy the theme definition folder into the "theme190" folder.
- If you use the ApplyTheme function to set the theme:
- In case only the theme name is specified in the function (the theme path is the default %Appeon%\Shared\PowerBuilder\theme190), create a "theme190" folder in the root directory of the application .exe file, and then copy the theme definition folder into the "theme190" folder;
- In case the absolute theme path is specified in the function, make sure the theme definition folder exists in the absolute theme path after the application deployment;
- In case the relative theme path is specified in the function, make sure the theme definition folder exists in the same relative path to the root directory of the application .exe file.
Supported and unsupported theme settings
If you have customized visual properties in the Properties, using expressions, or by PowerScript, you may find the UI Theme may clash with your customizations. Therefore, it is important to know the list of supported and unsupported theme settings and adjust accordingly.
General Settings
- “drawing”=true in each section means that the settings in the section will take effect. You can set the node to false if you want to use the “no-theme” style for all the settings in the section. Note that the value for "drawing" can only be true or false (all letters in lower case).
- “border” may be set to 0, 1, or 2. Unless otherwise explained in this tutorial, 0 means whether to draw borders relies on the Border setting in the PB IDE; 1 means that borders will always be drawn; 2 means no border.
- Border style is an unsupported setting because themes only support StyleBox! as the border style. If the previous border style is StyleLowered!/StyleRaised!/StyleShadowBox!, you may need to adjust the size of the relevant controls when you apply new UI theme.
- Except for font color, theme settings do not support font properties.
- The other node values will be either hex color value or specific image file to be assigned to the node.
Windows and user objects
What can be set by the theme
- Background color, title bar, border, and system buttons
- Menu, toolbar, and status bar
- Scrollbar on the OLE control, user object and window
What cannot be set by the theme
- Windows system dialog (such as Save As dialog, Open dialog), and PowerBuilder built-in dialog (such as Filter dialog, Sort dialog)
- Minimize/Maximize/Close buttons in the title bar
- Menu that calls to a third-party DLL
- Floating FrameBar
- Dockable windows (obsolete)
Controls
What can be set by the theme
- Font color and background color
- The border of the following control is always determined by the border property settings in the painter: InkEdit, InkPicture, SingleLineEdit, EditMask, MultiLineEdit, RichTextEdit, ListBox, PictureListBox, ListView, TreeView, Graph, and MonthCalendar.
- The border of DatePicker, DropDownListBox, and DropDownPictureListBox is always rendered, regardless of the border property setting in the painter.
- By default, StaticText has no border ("border"=0 in theme.json). If "border" is modified to 1 in theme.json, the border property setting in the painter takes effect.
- By default, StaticHyperLink has no border ("border"=0 in theme.json), except when 1) its border is set to StyleShadowBox in the painter; or 2) its background is not transparent and its border is set to StyleBox in the painter. If "border" is modified to 1 in theme.json, its border property in the painter takes effect.
What cannot be set by the theme
- Line, Oval, Rectangle, RoundRectangle, Picture, PictureHyperLink, and Animation.
- OLE control or ActiveX control.
- RichTextEdit control (except that the border of this control can be set in the theme.json file.
- The background color of these controls: CheckBox, RadioButton, GroupBox, StaticText, and StaticHyperLink. The background color is always transparent, unless when the control is placed on top of an unsupported control (such as Picture), the background color gets the settings in the painter.
- The lines that connect the tree items in the TreeView control will not display, even though the HasLines property is enabled.
DataWindows
What can be set by the theme
- The border and resizable settings in the painter have higher priorities than the theme settings; the settings of other properties by expression or the Modify function has higher priorities than the theme settings. Note that dynamically setting the resizable or border property at runtime in the script will not take effect.
- The settings of the background color and font color of Column, Text, Computed Field, and GroupBox controls by expression or the modify function has higher priorities than the theme settings (settings in the painter have no effect).
- For Grid and CrossTab DataWindows, the “grid-style” and “cross-style” subsections have higher priorities than the settings outside the two subsections.
- The DataWindow selected row is determined by the theme.json file, which are configured under the "cross-style" for the Crosstab DataWindow, or configured under the "grid-style" for DataWindows of other presentation styles.
- In the Header of Grid and CrossTab DataWindows, the background of the Text control is transparent and the background color of the Header band is determined by theme settings.
What cannot be set by the theme
- Label, Composite, OLE 2.0, and RichText DataWindows
- DataWindow title bar
- Color of the DataWindow band (except for the Header of Grid and Crosstab DataWindows)
- DataWindow Button control if the button displays a picture (system picture or custom picture).
- If a DataWindow control is dynamically created, it will be first rendered by the theme.json file (rather than the definition in the Create statement), or changed later by the property expression in the PowerBuilder IDE or the Modify method in the script.
- When printing or saving the DataWindow as PDF file, the theme will not take effect, except for the Graph DataWindow.
- The CheckBox and RadioButton control on a DataWindow Column will have no border.
- If DataWindow HSplitScroll is set to true, the height of HScrollBar groove and the width of VScrollBar groove cannot be set by the theme.json file; they will have no effect and will use the default values.
Additional theme settings
By upgrading to PowerBuilder 2019 R2, the new UI theme allows you to configure much more visual elements of the controls than before.
Grid line:
- Configure the line and color for the grid line of CrossTab and Grid DataWindow (JSON node: "datawindow"->"cross-style" and "datawindow"->"grid-style").
Toolbar
- Configure the background color of toolbar (JSON node: “toolbara”-> "bitmap-background-color").
Graph
- Configure the color for a graph (JSON node: "graph-colors").
User object
- Control whether the “border-color" shall be effective (JSON node: “userobject”->"default-style"). If “default-steyle” is true, "border-color" has no effect.
DataWindow
- Configure whether the background color shall be effective (JSON node: “datawindow”->"background-color-enabled").
StaticText, StaticHyperLink and GroupBox
- Configure whether the background color shall be transparent (JSON node: “groupbox”->"background-transparent"; “statictext”->” background-transparent”, “statichyperlink”->”background-transparent”).
Select row:
- Configure the text color and background color for the selected row in the DropDown edit-style column in DataWindow (JSON node: "datawindow"->"dwo-column"->"dropdown-type").
- Configure the text color and background color for the detail band of CrossTab and Grid DataWindow (JSON node: "datawindow"->"cross-style" and "datawindow"->"grid-style").
Images:
- Configure the box for the CheckBox control and the CheckBox edit-style column in DataWindow (JSON node: "checkbox" and "datawindow"->"dwo-column"->"checkbox-type").
- Configure the radio for the RadioButton control and the RadioButton edit-style column in DataWindow (JSON node: "radiobutton" and "datawindow"->"dwo-column"->"radiobuttons-type").
- Configure the arrow for the DropDown edit-style column in DataWindow (JSON node: "datawindow"->"dwo-column"->"dropdown-type").
- Configure the arrow for the DatePicker, DropDownListBox, and DropDownPictureListBox controls (JSON node: "datepicker", "dropdownlistbox", and "dropdownpicturelistbox").
- Configure the arrow (up, down, and dropdown) for the EditMask control and the EditMask edit-style column in DataWindow (JSON node: "editmask" and "datawindow" -> "dwo-column" -> "editmask-type").
- Configure the left and right buttons for the HScrollBar control (JSON node: "hscrollbar").
- Configure the top and bottom buttons for the VScrollBar control (JSON node: "vscrollbar").
- Configure the left, right, top, and bottom buttons for the Tab control (JSON node: "tab").
- Configure the foreground and background color for the slider and the image for thumb in the HTrackBar and VTrackBar control (JSON node: "htrackbar" and "vtrackbar").
- Configure the image for the check box and the expanded and collapsed buttons in TreeView (JSON node: "treeview").
Several useful techniques to further adjust your user interface
How to turn off UI Theme at runtime
Use this workaround if you want to dynamically turn off the theme at runtime: create a custom theme that has {“drawing”:false} for every control type, and use this theme in the ApplyTheme method.
Note: Before switching between themes or turning off the theme thru the ApplyTheme method, it is the best practice to prompt end users to reopen the current window, in order to refresh the UI correctly.
How to make it easier to resize windows in new theme
Windows in new UI theme have modern-looking 2D borders. The lines of the borders are quite thin, sometimes causing difficulty to change the cursor to the resizing cursor. If you want to make it easier for your app users to resize windows, you can consider to slightly enlarge the width of the border lines, for globally window (in theme.json) or for a specific window (in theme_123.json, for example).
The JSON node "Window"->"border"->"margin" determines the width of the border lines. By default, the value is [1,30,1,1], respectively for the left border, upper border, right border and lower border. You can change the settings for the left border, right border, and lower border to 2 or 3. For example, [3,30,3,3]. The border will be bolder, and when you hover mouse over, the cursor will change to the resizing cursor more easily.
How to update the icons used in your application
You may find that the old-fashioned icons used in the application clashes with the modern appearance of UI Themes. Therefore, it may be necessary to update the icons to a modern style.
There are two options for updating the icons:
Option A: You can replace each icon manually. A set of Windows 10 style icons are provided for selection under the "icons" list and the "small pictures" list in the Property tab for controls. The icons can be easily distinguished by their names: "_icon_2" is appended to the name of each new icon, and "_2" is appended to the name of each new small picture.
Option B: Appeon has developed a free icon-replacement tool to help you with completing the task. For more information about the tool, see https://community.appeon.com/index.php/codeexchange/powerbuilder/177-icon-replace-tool.
How to disable the new UI theme for a control
Taking StaticText as an example. If a theme is applied, the font color, background color, and border of StaticText can only be set in the theme.json file, and cannot be dynamically changed by the expression or the Modify method. If you want to set different font color or background color for multiple StaticText controls, you will have to disable the UI theme for this control first.
To disable the UI theme for the StaticText control, change the value of “drawing” to false under “statictext” in the theme.json file.
statictext":
{
"drawing":false,
"border":0,
"background-transparent":true,
"normal-state":
{
"text-font":{"color":"#000000"}
},
"disabled-state":
{
"text-font":{"color":"#999999"}
}
},
How to set the font color of text control in the DataWindow
Before applying a theme (take New Customer window as an example): the asterisk for a few columns (such as Customer ID, Last Name, First Name) is set to blue.
After applying a theme:
All text controls in DataWindow have the same font color (black) in the theme.json file.
Solution:
If you want to set it to a different color, you can set it by specifying an expression in the properties dialog.
Add an expression for Text Color in the Font Properties dialog to set the asterisk to blue.
Specify the color in the expression box.
How to set the background color of text control in the DataWindow
Before applying a theme (take New Order window as an example):
The background of the text field for Order ID and Amount is set to grey in the properties dialog.
After applying a theme:
The background color set in the properties dialog does not take effect; instead, all text fields have the same background color which is set in theme.json.
Solution:
To set the background of the text field for Order ID and Amount to a different color, you can set it by using an expression in the properties dialog.
How to set the background color of DataWindow
Before applying a theme (take Customer Report window as an example):
The background color of DataWindow is set by the following script:
dw_1.modify("datawindow.color="+string(il_BackColor))
After applying a theme:
The script that modifies the DataWindow background.color does not take effect.