This tutorial will show you how to create a dialog, add widgets to it, connect signals and execute it within the Harmony Script Editor.
It will also introduce the UiLoader and cover how to add predefined Qt forms to your scripts.
While dialog boxes are highly customizable, message boxes are simple to use and can just as effectively convey an important message or alert to the user. There are three kinds of message boxes: information, warning and critical.
Information boxes display your message and have one button; OK.
Warning boxes display your message and have two buttons; Abort and Retry.
Critical boxes display your message and have on button; Retry.
The Retry and OK buttons function the same, sending the accept signal, and the Abort button sends the reject signal. If the accept signal is sent, the MessageBox will return true, if the reject signal is sent, false will be returned.
There are 4 simple dialog boxes that you can use that do not require any formatting to get basic input from the user such as an item from a list, a number, or a text string.
Here are some code snippets showing how to implement these preset dialogs.
getText
LABEL is the prompt you want to show next to the text field to get input from the user. TEXT is the default text that appears in the dialog box’s text field. TITLE is the title that will appear on the dialog box. This line will return a String.
getNumber
LABEL is the prompt you want to show next to the number field to get input from the user. VALUE is the default value that appears in the dialog box’s number field. DECIMALS is the number of decimals to allow in the input. MIN is the minimum value allowed for the input. MAX is the maximum value allowed for the input. TITLE is the title that will appear on the dialog box. This line will return a double.
getItem [1/2]
LABEL is the prompt you want to show next to the item list. LIST is an array of items for the user to choose from. CURRENT is the currently selected item from the list. EDITABLE is a boolean flag whether or not to allow the user to enter their own item. TITLE is the title that will appear on the dialog box. This line will return a value matching the type from the LIST array.
getItem [2/2]
LIST is an array of items for the user to choose from. CURRENT is the currently selected item from the list. EDITABLE is a boolean flag whether or not to allow the user to enter their own item. This line will return a value matching the type from the LIST array.
When you create a custom dialog you can create complex boxes that give the user a variety of input options.
For starters, we will start by showing you how to create a very basic dialog:
The variable myDialog is a dialog object. You can change the title of your dialog box by using dialog.title, or dialog.caption, followed by the string you want to display as the title. dialog.exec is how to execute and display your dialog box, and must be after any customizations of your dialog that you want to display.
Now we can check out some more simple customizations.
By default, a dialog box has 2 buttons; OK and Cancel. Clicking OK sends the accepted signal, causing dialog.exec to return true, and clicking Cancel sends the rejected signal, causing dialog.exec to return false. We can change the text of these buttons using dialog.okButtonText and dialog.cancelButtonText. Here is what that would look like for myDialog from earlier:
So far our dialog box is looking pretty bare. We can add some text to the body of the dialog box by using a Label widget:
This text will appear in a single line in the dialog box, and as is the case for all widgets, the box will be resized to fit it. To add multiple lines of text, you can create and add new Label widgets, or add line breaks in your string.
DIALOG BOX LAYOUT Your dialog box is automatically sized to be the smallest possible while still fitting all the widgets. You can edit your box’s width to make it larger than necessary, but it will not shrink the box smaller than it would be by default.
There are a few other ways to improve the formatting of your dialog box. dialog.addSpace() inserts a block of blank space in your dialog. It can be used to space out widgets, or to change the height of your dialog box before it executes.
You can also separate your widgets into columns by adding a new column:
Any widgets added to your dialog before adding a new column will show up in the previous column. Your dialog can be split into as many columns as you’d like.
Similar to columns, you can create tabs that appear at the bottom of your dialog box. Any widgets added after a tab will appear in that tab. The widgets that appear in your tabs can be formatted the same way as those in the main body, even with columns. The contents of only one tab can be seen by the user at any given time, and adding additional tabs will increase the number of tabs the user can open, and not create any nested tabs.
Finally, you can create a group box within you dialog to keep all related widgets together and independently formatted under a specific title.
Within a group box you can add widgets with GroupBox.add, and have the formatting options of GroupBox.addSpace and GroupBox.newColumn. GroupBox.clear removes all widgets within the group box.
Here is a sample dialog box showcasing all of the formatting options:
Now that you have learned how to create and format a dialog box, we can move on to using them to get input from a user. There are ten widgets you can use to get user input and here we will show you how to use each of them. These widgets are contained in a wrapper to allow them to be used within the scripting environment, and as a result are missing some of the functionality and properties they would normally have within Qt. This functionality can be regained by using the UiLoader, which is covered at the end of this tutorial.
LineEdit The line edit widget allows you to prompt the user for a line of text and then save their input as a string. The user’s input will be saved into the widget’s LineEdit.text attribute, where it can be accessed. You also can set the value of LineEdit.text before executing your dialog to preload your text edit field with a message or prompt for the user. It is important to note that if you set the value of LineEdit.text and then the user clicks the Cancel button, it will be as if the user entered the preset text.
TextEdit The text edit widget creates a multi-line text box for the user to write text to. You can save what is written in the text box in a string, and preserve all of the formatting such as line breaks and spacing originally in the text box. The user’s input will be saved into the widget’s text attribute, where it can be accessed. You can set the value of TextEdit.text before executing your dialog to preload your text edit field with a message or prompt for the user. It is important to note that if you set the value of TextEdit.text and then the user hits the Cancel button, it will be as if the user entered the preset text.
Line edit and text edit are very flexible for getting user input, but that input is unpredictable, as the user can type anything into the text field. The following input widgets only accept specific input.
NumberEdit The number edit widget creates a field where the user can input only numbers (0-9) and modifiers for those numbers ( + , - , . ). The ‘+’ and ‘-‘ symbols can only be the first character in the field. Using NumberEdit.minimum, NumberEdit.maximum, and NumberEdit.decimals you can restrict what the user can input further, setting limits for the lowest number possible, the largest number possible, and the number of decimals allowed in the input. You can also edit the label (NumberEdit.label) on a number edit widget to prompt the user properly.
DateEdit The date edit widget allows the user to input a date. By default, the date is ordered in the format Day/Month/Year, but the order can be changed using DateEdit.order and the DateEditEnum object. You can also set the minimum and maximum dates allowed by using DateEdit.maximum and DateEdit.minimum. These both require arguments that are Date objects. The default date shown is January 01, 2000, but that can be changed by presenting the DateEdit.date value to a Date object. You can also use DateEdit.label to set a prompt for the user next to the input field.
TimeEdit The time edit widget allows the user to input a time. This widget uses QTime objects, which use 24H clock formatting. By default, the time edit widget allows the user to edit the hour, minute and whether it is the AM or PM. To allow the user to edit the seconds, you can use TimeEdit.showSeconds, and to hide the AM : PM display you can use TimeEdit.showAMPM. You can set minimum and maximum times that the user can enter, with TimeEdit.minimum, and TimeEdit.maximum, either of which must be set to QTime objects. You can set the initial time displayed when the dialog box opens by presetting the TimeEdit.time value, again with a QTime object. You can also use TimeEdit.label to give a prompt to the user next to the input field.
SpinBox The spin box widget allows the user to choose a number from an ascending and descending list. The user can also type their choice into the spin box, but only if it is within the minimum and maximum values. It will return an integer value only. You can set the maximum value of the spin box using SpinBox.maximum, and set the minimum value with SpinBox.minimum. You can set the default (starting) value shown in the spin box with SpinBox.value. By default, the spin box goes from 0-99, with an initial value of 0. You can also use SpinBox.label to give a prompt to the user next to the input field.
ComboBox The combo box widget allows the user to select an item from a dropdown list. The values for the dropdown list can be added using ComboBox.itemList, with an array of items. If ComboBox.editable is set to true, the user can either select an item from the list, or type in their own value. By default, the editable attribute is set to false. You can get the zero indexed position of the user’s input from your array of items with ComboBox.currentItemPos. You can retrieve their actual selection or input with ComboBox.currentItem. You can also use ComboBox.label to give a prompt to the user next to the dropdown list.
Slider The slider widget allows the user to select the value from scrollable slider. The default range for the slider is from 0 to 99. The minimum and maximum values of the slider can be set with Slider.minimum and Slider.maximum. The initial value along the slider can be set by presetting the Slider.value. The orientation of the slider in the dialog box can be set with Slider.orientation, and changed to "Horizontal" or "Vertical". By default, the slider will be horizontal. The slider widget also has a built-in signal. Signals can make function calls, such as in this case where there is a valueChanged signal. You can use Slider.callback to call a function whenever the valueChanged signal is sent, meaning whenever the user moves the slider. Slider.valueChanged( int ) will send the valueChanged signal without altering the value of the slider. You can also use Slider.label to give the user context about the slider.
CheckBox The check box widget allows the user to choose a boolean value for a given prompt, the box being checked for true, and unchecked for false. The status of the box can be retrieved or preset with CheckBox.checked, which will also return the associated boolean value. CheckBox.text can be used to give a prompt or label to the check box.
RadioButton The radio button widget allows the user to choose a one of multiple radio buttons, which must each be instantiated separately. The status of the button can be checked or set with RadioButton.checked, which will return a boolean value. RadioButton.text can be used to give a prompt or label to the check box. By default, a radio button will be unchecked, but once it is checked it cannot be unchecked except by checking a different box in the same container, meaning radio buttons inside a tab or group box will not interact with radio buttons outside of that tab or group box, and vice versa.
Button The button widget allows you to add your own custom button to the dialog box. You can change the label of the button using Button.label. The button also has a clicked() signal, meaning you can use it to call other functions in the middle of executing your dialog box. You can call a function with this signal using Button.callback.
So far we’ve covered signals when it comes to creating your own button and when using a slider, but the default Cancel and OK buttons also send signals. In a script, these buttons will close the dialog box, but we can use the signals they send as they do to our advantage afterwards. When a dialog box is closed using the Cancel button, the line dialog.exec() will return false, when closed with OK, dialog.exec() will return true. While we can’t change the actual signals sent, we can use the return values generated by these signals locally. The signal emitted by clicking the cancel button is a rejected() signal, that goes to the reject() slot of the dialog box. The signal emitted by clicking the OK button is an accepted() signal, that goes to the accept() slot of the dialog box.
This can be seen in the example above, in the following lines:
If the user clicks ‘Undo’ (The cancel button) after testing out a few colours for their colour card, the script will call colourResetter and set the colour card to the colour it was when the function was originally called. If you are going to be using any of the user input after the dialog box is closed then you should contain your dialog.exec(), and the operations involving that input, in an if statement.
UiLoader allows you to load predefined Qt forms that define Qt Widgets. These pre-defined Qt forms are typically built using Qt Designer.
Using the Qt Designer allows you to create more complex widgets than possible solely within the scripting environment, as you can use all of the pre-defined widgets supported by Qt4.8. These Qt Designer files use the extension *.ui, and are loaded by using the UiLoader.load() function where the parameter is the path to your *.ui file.
All widgets created in the ui file can be edited further inside your script by using the nested name of the attribute you wish to edit. For example, a checkbox inside of a tab inside of a dialog may have the full name dialog.tab.checkbox, and editing its value (whether it’s checked or not when the dialog opens) would look like this:
When using the UiLoader, not only can you edit all of the properties of a widget, you also have access to all of its signals and slots, as well as its inherited properties, signals, and slots. The Qt documentation has all the info on all of the supported widgets as well as their accessible properties: http://doc.qt.io/archives/qt-4.8/. Some of these properties, signals and slots are not usable within the Harmony widget wrapper, so the UiLoader can be a very powerful tool for your script.
The following script and associated predefined form are included in the installation of Harmony, so it can be run inside the Harmony Script Editor to see what it does. The script (TB_LightTableSliderUsingFormLoader.js) can be found in your Harmony folder in /resources/scripts/, or in the Script Editor, and the predefined form (lighttable.ui) can be found in your Harmony folder in /resources/forms/.