Controls provide the fundamental UI building blocks of Cascades applications. By learning how to use them effectively, you will be able to design shiny applications where information is presented to the user in a polished and clear manner. This chapter will review the most essential Cascades controls and show you how to use them in your own applications. Considering that you will build your UI in QML most of the time, I will use QML exclusively in this chapter (you can also build your UI using C++, but that should rarely be the case in practice). UI best practices are another important topic that I will cover throughout the topics presented here. After having read this chapter, you will
Control
Control is the base class for all UI controls and contains common properties that you can set in order to specify the control’s visual appearance on the screen:
The best way to understand the effects of these properties on the UI’s layout is to use the QML properties view under Momentics and play with the various parameters (see Figure 4-1, where a Container control has been selected).
Figure 4-1. QML properties view with a Container selected
A Container is a control for grouping other controls. A Container’s layout property governs how its child controls are displayed (note that a Cascades layout is equivalent to a layout manager in Java). Because containers can be nested, you can logically regroup a subset of your UI’s controls by adding them to a nested Container (there are actually no limits in the nesting depth, but for code readability reasons, it is a good idea to keep the nesting level to three at most). In practice, you can create extremely complex UIs by judiciously using the possibility to nest Containers with different layout properties.
You have three layouts to work with in Cascades: StackLayout, DockLayout, and AbsoluteLayout. The next section will review all three of them, with a particular emphasis on StackLayout, which should be preferred in most situations (a StackLayout is also used by default when no layout is specified for a Container).
StackLayout
StackLayout is by far the most common layout in Cascades. You should therefore invest some time in mastering it. You can use a StackLayout in order to stack controls horizontally or vertically in a Container. You specify the layout direction by setting the orientation property of a StackLayout, which can take one of the following values:
You can further customize a child control’s layout by optionally setting its layoutProperties, horizontalAlignment, and verticalAlignment properties. The layoutProperties property accepts an object, which matches the layout of the parent Container (for example, if the parent Container’s layout is an instance of AbsoluteLayout, a child control’s layoutProperties can only accept an instance of AbsolutLayoutProperties, and if the Container’s layout is an instance of StackLayout, the child control’s layoutProperties will take an instance of StackLayoutProperties).
Listing 4-1 and Listing 4-2 illustrate the correspondence between layout and layoutProperties.
Listing 4-1. AbsoluteLayout and Corresponding layoutProperties
import bb.cascades 1.2
Page {
Container {
layout: AbsoluteLayout {
}
Button {
layoutProperties: AbsoluteLayoutProperties {
positionX: 200
positionY: 500
}
}
}
}
Listing 4-2. StackLayout and Corresponding layoutProperties
import bb.cascades 1.2
Page {
Container {
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
Button {
layoutProperties: StackLayoutProperties {
spaceQuota: 1
}
text: "Button 1"
}
}
}
In the specific case of StackLayout, the StackLayoutProperties object defines a spaceQuota property, which specifies how space is divided amongst controls. For controls with a negative space quota, the preferredSize property is used to display the control (these “static” controls are given priority over dynamic controls with a space quota larger than 0). Controls with a space quota larger than 0 are dynamically displayed once the static controls have been positioned.
For example, Figure 4-2 illustrates a UI entirely designed using a StackLayout and space quotas.
Figure 4-2. UI created with StackLayout and space quotas (portrait)
If you change the device’s orientation, you will obtain the layout shown in Figure 4-3.
Figure 4-3. Same UI in landscape orientation
The UI controls are organized as follows (see also Figure 4-2 and Listing 4-1):
Listing 4-3 shows you the corresponding QML.
Listing 4-3. main.qml
Page {
Container {
id: root
topPadding: 20
bottomPadding: 20
leftPadding: 20
rightPadding: 20
Container {
id: child1
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
Button {
text: "button1"
layoutProperties: StackLayoutProperties {
spaceQuota: 1
}
}
Button {
text: "button2"
layoutProperties: StackLayoutProperties {
spaceQuota: 2
}
}
}
Button {
horizontalAlignment: HorizontalAlignment.Fill
text: "button3"
}
Container {
id: child2
layout: StackLayout {
orientation: LayoutOrientation.RightToLeft
}
Button {
text: "button4"
layoutProperties: StackLayoutProperties {
spaceQuota: 4
}
}
Button {
text: "b5"
layoutProperties: StackLayoutProperties {
spaceQuota: 1
}
}
Button {
text: "button6"
layoutProperties: StackLayoutProperties {
spaceQuota: 3
}
}
}
TextArea {
layoutProperties: StackLayoutProperties {
spaceQuota: 1
}
}
}
}
AbsoluteLayout
AbsoluteLayoutallows you to precisely set the X and Y coordinates of controls within a container. In practice, unless you are designing your UI for a very specific screen resolution and orientation, you should not use an absolute layout. As mentioned, the main advantage of the absolute layout is that you have complete control on positioning the UI elements. However, the major downside is that your UI will not gracefully handle different screen resolutions and orientations (there are cases, however, where using an absolute layout makes sense; for example, when you are designing a custom control and need to position the UI elements precisely). Listing 4-4 shows you how to use an absolute layout for positioning a button on the screen.
Listing 4-4. Absolute Layout
Container {
layout: AbsoluteLayout {}
Button {
text: "Button"
layoutProperties: AbsoluteLayoutProperties {
positionX: 100
positionY: 100
}
}
}
DockLayout
You can use a DockLayout in order to dock child controls to a specific area of the parent container. The child control’s docking area is specified by its horizontalAlignment and verticalAlignment properties, as illustrated in Listing 4-5 and Figure 4-4.
Listing 4-5. Dock layout
Page {
Container {
layout: DockLayout {}
Button {
text: "b1"
}
Button {
text: "b2"
verticalAlignment: VerticalAlignment.Center
}
Button {
text: "b3"
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Bottom
}
}
}
Figure 4-4. Dock layout
A DockLayout also has the following interesting characteristics:
Figure 4-5. Dock layout with overlapping controls
Figure 4-6. Dock layout with overlapping controls
Finally, Listing 4-6 shows the QML document corresponding to Figure 4-5 and Figure 4-6.
Listing 4-6. Dock layout with overlapping controls
import bb.cascades 1.2
Page{
Container {
leftPadding: 20
rightPadding:20
topPadding: 20
bottomPadding: 20
layout: DockLayout {}
ImageView {
horizontalAlignment: HorizontalAlignment.Right;
imageSource:"asset:///swissalpsnight.png"
preferredWidth: 600
}
ImageView {
horizontalAlignment: HorizontalAlignment.Center;
verticalAlignment: VerticalAlignment.Center;
imageSource:"asset:///swissalpsday.png"
preferredWidth: 600
rotationZ: 10
}
TextField {
verticalAlignment: VerticalAlignment.Bottom;
}
}
}
Text is probably the most ubiquitous control in any UI. Cascades therefore gives you lots of flexibility in handling text, as well as its appearance. You can customize the text styles by creating your own text style definitions. This section will review the three main text controls, which are Label, TextField, and TextArea, and show you how to customize their corresponding text style.
Text Styles
You can customize a text control’s appearance by setting its textStyle.base property, which is an instance of the TextStyle object. In practice, you will use a TextStyleDefinition attached object to create a new TextStyle instance (in other words, the TextStyleDefinition object is a factory for TextStyle objects).Using a TextStyleDefinition, you can customize visual attributes such as font weight (light, normal, and bold), color, size, and alignment. When specifying a TextStyleDefinition, you will always start with a system default base, TextStyle, which gives you an initial set of attributes to work from. The SystemDefaults.TextStyles class gives you the following default text styles:
Listing 4-7 shows you how you can use the default system text styles with a Label.
Listing 4-7. System Text Styles
import bb.cascades 1.2
Page {
Container {
Label {
text: "This is big text"
textStyle.base: SystemDefaults.TextStyles.BigText
}
Label {
text: "This is title text"
textStyle.base: SystemDefaults.TextStyles.TitleText
}
Label {
text: "This is subtitle text"
textStyle.base: SystemDefaults.TextStyles.SubtitleText
}
Label {
text: "This is body text"
textStyle.base: SystemDefaults.TextStyles.BodyText
}
Label{
text: "This is primary text"
textStyle.base: SystemDefaults.TextStyles.PrimaryText
}
Label{
text: "This is small text"
textStyle.base: SystemDefaults.TextStyles.SmallText
}
}
}
Listing 4-8 shows you how to customize a text style using a TextStyleDefintion.
Listing 4-8. Custom Text Style
import bb.cascades 1.2
Page {
Container {
attachedObjects: [
TextStyleDefinition {
id: myStyle
base: SystemDefaults.TextStyles.BigText
color: Color.DarkBlue
fontWeight: FontWeight.Bold
}
]
Label {
text: "Some bold text"
textStyle.base: myStyle.style
}
}
}
The advantage of specifying a TextStyleDefinition object is that you will be able to reuse it throughout your UI without redefining text styles for each control.
Inline HTML and CSS
Besides using TextStyleDefinition objects for customizing text appearance, you can also resort to inline HTML and CSS. The supported HTML tags are: <a>, <b>, <br/>, <i>, <span>, <p>, <div>, <em>, and <strong>. Listing 4-9 shows you how to apply inline HTML text styling to a label.
Listing 4-9. Custom Text Style
import bb.cascades 1.2
Page {
Label {
text: "<html><b>Cascades</b> is <i>awesome!</i></html>"
}
}
You can also embed a <style> tag inside <span> or <div> tags in order to apply CSS styling to your text, as shown in Listing 4-10.
Listing 4-10. CSS Styling
import bb.cascades 1.2
Page {
Label {
text: "<html><span style='text-decoration:underline'>Cascades</span> is"+
"<span style='font-size:xx-large;font-style:italic;color:green'>awesome!</span></html>"
}
}
Note that not all CSS attributes are supported in style definitions, but you can rely on the following ones (for additional details on how to use the attributes, refer to one of the numerous online CSS tutorials; a good starting point is www.w3schools.com/css/):
Label
You can use a label control to display a single or multiple lines of read-only text by setting its text property. You have already seen labels in action in the previous examples (see Listing 4-7 to Listing 4-9).
TextField
A TextField is a single-line control that accepts text input. A TextField has fixed height and variable width. Just like a label, you can control the text styling using a TextStyleDefinition object (in other words, all the techniques described in the previous sections apply to text fields). You can specify how the text field behaves in relation to its text input by specifying its inputMode property. The following are some common values:
In fact, a TextFieldInputMode corresponds to default values for input and content flags. Input flags determine how the text that users type is parsed and interpreted by the text field. Content flags determine how the text that users type is displayed. In practice, using one of the default TextFieldInputMode types to preset the flags is more than adequate, and you should rarely need to set the input and content flags directly. The inputMode property value also determines the kind of virtual keyboard displayed to the user when entering text. For example, TextFieldInputMode.Text is the most flexible and suitable for a wide variety of text. This mode also includes word suggestions to help users type faster. The other input modes are optimized for specific tasks such as writing e-mails or entering numeric values. For example, Figures 4-7 and 4-8 illustrate the TextFieldInputMode.EmailAddress and TextFieldInputMode.NumericPassword respectively.
Figure 4-7. A virtual keyboard corresponding to an e-mail address input (image source: BlackBerry)
Figure 4-8. A virtual keyboard corresponding to numeric password input (image source: BlackBerry)
You can capture a TextField’s input using its input grouped property, as illustrated in Listing 4-11.
Listing 4-11. Text Capture
import bb.cascades 1.2
Page {
Container {
TextField {
id: myField
inputMode: TextFieldInputMode.EmailAddress
hintText: "Enter email address"
input{
submitKey: SubmitKey.Go
onSubmitted: {
// handle input when submit key is pressed
// by extracting text from myField.text
}
}
}
}
}
The submitKey property controls the text that will appear on the virtual keyboard’s Submit key (the Submit key is always located on the lower-right side of the virtual keyboard). The property can take one of the following values: SubmitKey.Go, SubmitKey.Join, SubmitKey.Next, SubmitKey.Search, SubmitKey.Send, SubmitKey.Submit, SubmitKey.Done, SubmitKey.Connect, SubmitKey.EnterKey, and SubmitKey.Replace.
You can also use a TextField’s hintText property to suggest the purpose of the field to the user when there is no input (see Listing 4-11).
Validator
You can make sure that the user’s input conforms to a certain set of rules by specifying a Validator class for the TextField using its validator property. For example, for a password field you could ensure that it is of a certain length and that it contains at least a digit. You can use the validator’s mode property to specify when text validation should occur. For example, by setting the mode property to ValidationMode.Immediate, the user’s input will be validated as the user types along, and by setting the property to ValidationMode.FocusLost, the user’s input will be validated once the TextField has lost focus. During validation, you can update the validator’s state by setting its state property, which can take one of the following values:
You should implement the actual validation in JavaScript by handling the validator’s validate signal, as illustrated in Listing 4-12.
Listing 4-12. JavaScript Validation Using a Regular Expression
import bb.cascades 1.2
Page {
Container {
TextField {
id: myField
inputMode: TextFieldInputMode.NumbersAndPunctuation
input {
submitKey: SubmitKey.Go
onSubmitted: {
// handle input when submit key is pressed
// by extracting value text from myField.text
}
}
validator: Validator {
mode: ValidationMode.Immediate
errorMessage: "Invalid integer!"
onValidate: {
// regexp for valid integer including optional sign
var regexp = /^s*(+|-)?d+s*$/;
var isValidInteger = regexp.test(myField.text);
if (regexp.test(myField.text))
state = ValidationState.Valid;
else
state = ValidationState.Invalid;
}
}
}
}
}
The regexp variable defines a valid integer (for example, 10, -99, and 0 are valid expressions, but 10.0 would be considered as invalid). The important point is that I am using the regexp variable to toggle the validator’s validation state.
Finally, here a few best practices to consider:
TextArea
A TextArea is very similar to a TextField and shares many of its properties (which they both inherit from AbstractTextControl). The main difference comes from the fact that a TextArea can handle multiple lines of text, whereas a TextField provides a single line. You can set the TextArea’s inputMode using a TextAreaInputMode object (the possible values are TextAreaInputMode.Default, TextAreaInputMode.Text, TextAreaInputMode.Chat, TextAreaInputMode.Email, and TextAreaInputMode.Custom). Finally, you can also use the TextArea’s editor object to track the current cursor position or the current selected text (see Listing 4-13).
Listing 4-13. TextArea Signal Handling
import bb.cascades 1.2
Page {
Container {
layout: DockLayout {
}
leftPadding: 20
rightPadding: 20
TextArea {
id: myField
inputMode: TextAreaInputMode.Chat
hintText: "Enter some text"
verticalAlignment: VerticalAlignment.Center
preferredHeight: 500
scrollMode: TextAreaScrollMode.Elastic
onTextChanging: {
console.log("text changing: "+text)
}
editor.onSelectionStartChanged: {
console.log("selection start: "+selectionStart);
}
editor.onSelectionEndChanged: {
console.log("selection end: "+selectionEnd);
}
editor.onSelectedTextChanged: {
console.log("selectedTextChanged: " + selectedText)
}
editor.onCursorPositionChanged: {
console.log("cursorPositionChanged: " + cursorPosition)
}
}
}
}
Button
You can use buttons in order to capture touch events in your application. A Button can display some text, an image, or both. You can set the following properties on a Button:
As explained in the previous chapters, the button will emit the clicked signal that you can handle in QML using the onClicked signal handler (see Listing 4-14).
Listing 4-14. Button Clicked Signal
Button{
id: button
text: "mybutton"
onClicked: {
console.log("I was clicked!")
}
}
The following best practices apply to buttons:
Slider
A Slider is a control that allows the selection of a value from a range of values (see Figure 4-9). You can set the range using the fromValue and toValue properties. You can handle the value using the onImmediateValueChanged signal handler. In practice, you will have to round to the closest integer the immediateValue passed to the handler (see Listing 4-15).
Figure 4-9. Slider
Listing 4-15. Slider
import bb.cascades 1.0
Page {
Container {
TextField {
id: texfield
}
Slider{
id: slider
fromValue: 0
toValue: 100
onImmediateValueChanged: {
texfield.text = Math.round(immediateValue)
}
}
}
}
Use a slider when a user needs to quickly set a value from a predetermined range of values.
ImageView
An ImageView is a visual control for displaying images (you used ImageView controls in Listing 4-3 and in the HelloCascades app from Chapter 1). You can either set the imageSource property, which is a URL specifying the location of the image, or set the image property, which is a Image wrapped as a QVariant (note that when you specify the imageSource property as an absolute path on the filesystem, you must prepend the path with “file://”). You can also set the ImageView’s scalingMethod property, which specifies how the source image will be scaled within the control.
Selection Controls
You can use a selection control to specify a criteria for refining the information displayed to the user. In practice, selection controls will display a list of options to the user so that he can perform a selection from the list. It is therefore not surprising that Cascades provides a wealth of controls organized around option selection. The purpose of this section is to pass the controls in review and illustrate their usage by starting with the essential building block, which is the Option control.
Option
The Option control represents the basic building block of a list of selectable items. You will therefore use an Option control combined with controls such as DropDown, RadioGroup, and SegmentedControl to display a selectable item in a list of items. You can set the Option’s text, description, and imageSource properties to display the option on the screen and provide visual feedback. The Option’s selected property indicates its state.
DropDown
A DropDown is a control that allows users to select an option from a list of options. As illustrated in Figure 4-11, a DropDown consists of a title bar and an expandable list of options. The list expands and collapses when you tap on the title bar. When the DropDown is expanded, each option displays a title with an optional description and/or image. When the user selects an option, the drop-down is collapsed and the selected option’s title is displayed to the right on the title bar.
As illustrated in Listing 4-16, you can determine the user’s selection by handling the drop-down’s selectedIndexChanged signal and/or the option’s selectedChanged signal (if an option is selected, selected=true will be passed to the signal).
Listing 4-16. DropDown
Page {
DropDown {
title: "Actors"
enabled: true
onSelectedIndexChanged: {
console.log("SelectedIndex was changed to " + selectedIndex);
}
Option {
id: clint
text: "Clint Eastwood"
description: "The Good, The Bad, The Ugly"
value: "Blondie"
onSelectedChanged: {
if (selected == true) {
console.log(clint.value);
}
}
}
Option {
id: robert
text: "Robert De Niro"
description: "Taxi Driver"
value: "Travis Bickle"
selected: true
onSelectedChanged: {
if (selected == true) {
console.log(robert.value);
}
}
}
Option {
id: jack
text: "Jack Nicholson"
// description omitted
value: "J.J. Jake Gittes"
onSelectedChanged: {
if (selected == true) {
console.log(jack.value);
}
}
}
}
}
Figure 4-10 illustrates the corresponding UI.
Figure 4-10. DropDown
In practice, you should use a drop-down when you want your users to select a single option from a list of options. A drop-down also makes your UI more compact, thus saving you some screen real estate. You should not use drop-downs when you need to select multiple interconnected values (in this case, use a picker).
RadioGroup
A RadioGroup can be used to group a set of options together. However, only one option can be selected at a time. Options are displayed as radio buttons, with an optional text describing their purpose (see Figure 4-11).
Figure 4-11. RadioGroup
You can handle option selection by responding to the RadioGroup’s selectedOptionChanged signal (or alternatively, you could also directly handle the Option’s selectedChanged signal; see Listing 4-17).
Listing 4-17. RadioGroup
// Create a RadioGroup with three options
Page {
RadioGroup {
Option {
id: option1
text: "Easy"
onSelectedChanged: {
if (selected) {
console.log("Easy selected");
}
}
}
Option {
id: option2
text: "Hard"
selected: true
onSelectedChanged: {
if (selected) {
console.log("Hard selected");
}
}
}
Option {
id: option3
text: "Very Hard"
onSelectedChanged: {
if (selected) {
console.log("Very hard selected");
}
}
}
}
}
Use a RadioButton when users can choose between more than two mutually exclusive options.
SegmentedControl
A SegmentedControl displays a horizontal row of selectable options (in practice, you can display up to four visible options). A SegmentedControl is a great way of filtering content inside a view (for example, you will see in Chapter 5 how to use a SegmentedControl to dynamically switch QML components depending on the selected option). Listing 4-18 shows you how to create a SegmentedControl in QML.
Listing 4-18. SegmentedControl
Page {
Container {
SegmentedControl {
id: segmented1
Option {
id: option1
text: "Option 1"
value: "option1"
selected: true
}
Option {
id: option2
text: "Option 2"
value: "option2"
}
Option {
id: option3
text: "Option 3"
value: "option3"
}
onSelectedIndexChanged: {
var value = segmented1.selectedValue
console.debug("Selected value: " + value);
}
}
}
}
And Figure 4-12 shows the corresponding UI.
Figure 4-12. SegmentedControl
Pickers
A picker is a control for selecting items such as a picture, a file, or a date. I will describe in this section the FilePicker and the DataAndTimePicker, which come as standard controls with Cascades. (You can also create your own custom picker, but I won’t cover this here. Custom pickers are nevertheless explained in the online BlackBerry 10 developer documentation.)
FilePicker
A FilePicker allows the user to either select a file from the file system (in picker mode) or specify a name and location for saving a file (in saver mode). For example, you can use a FilePicker to load an image from the device’s photo folder in an ImageView (see Listing 4-19). (Note that in QML you must prefix the path returned by a FilePicker with “file://” before passing it to an ImageView.) You can also filter the file types by setting the FilePicker’s type property. Finally, you can use the fileSelected signal to handle selection (the signal is emitted both in picker and saver modes).
Listing 4-19. FilePicker
import bb.cascades 1.0
import bb.cascades.pickers 1.0
Page {
Container {
ImageView{
id: myImageView
}
Button {
text: "FilePicker from QML"
onClicked: {
filePicker.open()
}
}
attachedObjects: [
FilePicker {
id:filePicker
type : FileType.Picture
title : "Select Picture"
directories : ["/accounts/1000/shared/misc"]
onFileSelected : {
console.log("FileSelected signal received : " + selectedFiles);
myImageView.imageSource = "file://" + selectedFiles[0];
}
}
]
}
}
Also note that in the example provided in Listing 4-14, the FilePicker is an attached object property of the Container (this enables you to selectively display the FilePicker when the button is pressed).
DateTimePicker
A DateTimePicker is a control for selecting a date and/or time. You can set the DateTimePicker’s mode, which specifies how date and time are shown to the user (see Figure 4-13).
Figure 4-13. DateTimePiker (image source: BlackBerry web site)
Note that the internal representation of a date by the QDateTimePicker is a Qt QDateTime object, which is accessible with the QDateTimePicker.value property. In QML, there are several ways of setting this property: you can set the value property either by using a correctly formatted string or by using a JavaScript Date object. Finally, you can respond to the valueChanged signal to handle date changes.
CheckBox and ToggleButton
Check boxes and toggle buttons enable users to select options. Both controls inherit from AbstractToggleButton and share the following attributes:
CheckBox
A CheckBox control has two states: checked or unchecked. You can also optionally display some text beside the check box explaining its purpose. If you include some text, it will always be left-aligned, and the check box will be right-aligned (see Figure 4-14).
Figure 4-14. CheckBox
Listing 4-20 shows you how to handle check box states in QML.
Listing 4-20. CheckBox
CheckBox {
id: checkbox
checked: true
text: "Checkbox"
onCheckedChanged: {
console.log("checkbox state: " + checkbox.checked)
}
}
In practice, use check boxes when users can select multiple items or options, which are not mutually exclusive.
ToggleButton
A toggle button is a kind of switch control, which can, for example, represent On/Off states (see Figure 4-15). Signal handling is identical to a check box.
Figure 4-15. CheckBox
You should use a toggle button when users can switch between two mutually exclusive options, such as On and Off.
ScrollView
A ScrollView is a container allowing the scrolling and zooming of its content. A ScrollView provides a viewport, which displays an area of the entire content. You can use a ScrollView when the content will not fit the UI entirely (for example, that would be the case if a container included many controls). Note that a ScrollView’s content can also be an ImageView or a WebView (for example, you can use a ScrollView to zoom in or out of a picture). You can control the scrolling behavior by setting the ScrollView’s scrollViewProperties property. Listing 4-21 shows you how to include a WebView in a ScrollView.
Listing 4-21. ScrollView
Page {
ScrollView {
WebView {
url: "http://www.apress.com"
}
scrollViewProperties {
scrollMode: ScrollMode.Vertical
pinchToZoomEnabled: true
}
}
}
Use a ScrollView when
System Dialogs, Prompts, and Toasts
You can use the system dialog controls to pause your application flow and communicate important information to the user. System dialogs can be used to ask the user to confirm an action, notify the user of an event, or prompt the user for additional information.
SystemDialog
You can use a SystemDialog control to ask the user to confirm an action (see Listing 4-22). (Note that you need to import the bb.system 1.2 library.)
Listing 4-22. SystemDialog with User Confirmation
import bb.cascades 1.2
import bb.system 1.2
Page {
Container {
layout: DockLayout {
}
Button {
text: "Show Dialog!"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
onClicked: {
myDialog.show();
}
}
attachedObjects: [
SystemDialog {
title: "Save Changes"
id: myDialog
onFinished: {
switch (value) {
case (SystemUiResult.ConfirmButtonSelection):
console.log("save confirmed");
break;
case (SystemUiResult.CancelButtonSelection):
console.log("save canceled");
break;
default:
break;
}
}
}
]
}
}
To display the dialog, you need to call SystemDialog.show(). To determine the user’s selection, you need to handle the SystemDialog.finished() signal. The SystemDialog’s text property will be displayed on the dialog’s title bar (see Figure 4-16).
Figure 4-16. SystemDialog
SystemPrompt
You can use a SystemPromptto ask for some input from the user before continuing with your application flow. The SystemPrompt will display two default buttons for accepting or rejecting the dialog box and an input field for user input. You can retrieve the user’s input by calling SystemPrompt.inputFieldTextEntry() (see Listing 4-23).
Listing 4-23. SystemPrompt
import bb.cascades 1.2
import bb.system 1.2
Page {
Container {
layout: DockLayout {
}
Button {
text: "Show Dialog!"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
onClicked: {
myPrompt.show();
}
}
attachedObjects: [
SystemPrompt {
title: "Enter a new file name"
id: myPrompt
onFinished: {
switch (value) {
case (SystemUiResult.ConfirmButtonSelection):
console.log("new file name is: "+myPrompt.inputFieldTextEntry())
break;
case (SystemUiResult.CancelButtonSelection):
console.log("new file canceled");
break;
default:
break;
}
}
}
]
}
}
Figure 4-17 shows the SystemPrompt when displayed.
Figure 4-17. SystemPrompt
SystemToast
A toast is a simple pop-up message that is displayed for a predefined amount of time. The toast is for information purposes only and the user does not need to interact with it. Listing 4-24 shows you how to use a SystemToast to display a toast to the user.
Listing 4-24. SystemToast
import bb.cascades 1.2
import bb.system 1.2
Page {
Container {
layout: DockLayout {
}
Button {
text: "Show Dialog!"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
onClicked: {
myToast.show();
}
}
attachedObjects: [
SystemToast {
id: myToast
body: "Happy New Year!"
}
]
}
}
Summary
This chapter gave you a broad perspective of essential Cascades controls. You should now have a good understanding of the core controls and be able to use them in your own applications when designing single page UIs (the goal of the next chapter will be to show you how to add application navigation and structure using multiple pages).
Layout management is also an important topic covered in this chapter. The StackLayout was given a particular emphasis because it is the building block for creating device-independent and resizable UIs using space quotas. You also saw that in practice it is a good idea to use space quotas to define relative controls sizes instead of statically specifying a control’s preferred size. Finally, you discovered how Cascades gives lots of flexibility in styling UI text by either using text style definition objects or by using inline HTML and CSS.