User Interaction with QMLSo far, we have shown how to declare items and arrange them to create a user interface. If we play a QML file using the QML Viewer, we can resize the display window and see the items adapt to the change, but the items themselves do not respond to user input from the keyboard or mouse. Unlike standard Qt widgets, items do not include intrinsic support for user interaction. The features required for interactivity are added or applied to items. QML provides the MouseArea item to handle mouse input and Keys and KeyNavigation attached properties to handle keyboard input. These are used with other items to make them responsive to user input. Mouse AreasTo make items responsive to mouse clicks, we add MouseArea items to the user interface, typically as children of the items we want to make interactive. Since MouseArea is based on Item, it has a geometry, but no visual appearance. The following example defines a mouse area with an explicit position and size; the image shown indicates where the mouse area is in the user interface, but it will not be visible in the running example. [Missing image declarative-qmlintro-mousearea-annotated.png] The onPressed and onReleased definitions are signal handlers that contain JavaScript code that will be executed in response to a signal. In this case, when the mouse button is pressed or released, the code will change the color of the background. Other signal handlers can be defined to handle other user input, such as onClicked and onDoubleClicked. Some require additional configuration of the item before they will work as expected, as we shall see later. Note: It is more common to define mouse areas within items and position them with anchors, as shown by the rest of the examples in this chapter. Handling Mouse ButtonsThe following example uses an anchor to fill a Text item with a mouse area, and defines two signal handlers to response to mouse button input. [Missing image declarative-qmlintro-mouse-pressed1.png] The onPressed and onReleased signal handlers are defined for the mouse area. As a result, when the user presses a mouse button when the cursor is over the text, the color changes to green; when the button is released, the color changes to black. Note that the mouse area only responds to the left mouse button by default. This is because the default value of the acceptedButtons is Qt.LeftButton. To test for other buttons, set this property to be the combination of the buttons required (using the OR operator), as in the following example. [Missing image declarative-qmlintro-mouse-pressed-buttons.png] The mouse area covers the entire area of the user interface and accepts input from both left and right buttons. Each of the rectangles defines its color as an expression that depends on the mouse area's pressedButtons property, testing whether the relevant button is found in the value of this property. When a button is released, the value is Qt.NoButton. Note: The pressed property provides information about whether or not a button was pressed in the mouse area, but does not provide any more than a boolean value. This can be sufficient in many situations. Finding the Cursor PositionThe MouseArea item contains a number of properties and signal handlers that provide information about the mouse cursor. For example, the mouseX and mouseY properties contain the position of the cursor, as shown in the following example. [Missing image declarative-qmlintro-mouse-pressed-position.png] When the user presses the mouse button over the text item, the text changes to show the coordinates within the mouse area where the press occurred. If we need to find the mouse position outside the text item, we should make the mouse area a child of the text item's parent and use anchors to fill that item instead. Mouse HoverIn the previous examples, the text item and rectangles were updated only when the mouse button was pressed. Consider a situation where we would like to continuously update the text item with the mouse's position. In such a case, we could try the following: [Missing image declarative-qmlintro-mouse-pressed-position2.png] When we run this example, the text item shows the initial, default value of the mouse area's mouseX and mouseY properties. Moving the cursor over the text has no effect. It is only when the text item is clicked that the text is updated. The reason for this is that, by default, the mouse area only updates various properties when a button is pressed. To receive continuous updates about the mouse cursor, we need to enable mouse hover by setting its hoverEnabled property, as shown in the following example: [Missing image declarative-qmlintro-mouse-hover-enabled.png] With mouse hover enabled, other properties of the MouseArea can be monitored. For example, the containsMouse property can be used to determine whether the mouse cursor is over the mouse area. Previously, we only knew when this was the case because the user had to press a mouse button over the area. [Missing image declarative-qmlintro-mouse-hover-containsmouse1.png] The above example uses an expression to show the coordinates of the mouse cursor when it is in the mouse area, area. When area.containsMouse evaluates to false, the - character is shown instead. Certain signal handlers only become useful when mouse hover is enabled. For example, the onEntered, onExited and onPositionChanged signal handlers will be called when the cursor enters, exits or changes position in the area. Dragging ItemsAs well as handling the low level interaction details, the MouseArea item also handles drag operations if the relevant properties are set. The following example shows how dragging is enabled for an item. [Missing image declarative-qmlintro-mouse-drag.png] The item to be dragged is the Rectangle containing a MouseArea and Text items. All that is required is to set the value of the drag.target grouped property to the item we wish to enable dragging for; in this case, the parent of the mouse area. When run, the rectangle containing the text can be dragged around its parent's area. The other drag grouped properties allow the dragging behavior of the item to be restricted and fine-tuned. drag.axis can be set to only allow dragging to occur along the x or y axes, and the range of positions to which the target item can be dragged can be limited to a range specified by the drag.minimumX, drag.minimumY, drag.maximumX and drag.maximumY properties. Strategies for UseMouse areas are applied to a user interface by using anchors to fill the items that need to respond to user input. This makes them responsive to button presses by default, and to mouse movement when the hoverEnabled property is set to true. When a mouse area is not needed to provide input, its enabled property can be set to false, so that it ignores user input. When mouse buttons are pressed and released, the pressedButtons property is updated as expected. However, when multiple buttons are used, as in the example above, the most up-to-date values reported by this property are not necessarily propagated to the items that use it. For this reason, it can be better to consider using signal handlers to respond to mouse button presses and releases. Key HandlingAnother important method of user input is via the keyboard. In addition to the TextInput and TextEdit items, which accept keyboard input for display purposes, QML provides facilities to allow items to capture key presses, as well as higher level features for navigation using keys. Unlike mouse input, which uses the MouseArea item, key input uses two attached properties to handle keyboard input: Keys and KeyNavigation. These look like ordinary elements, but can be applied to any item in order to enable keyboard input support. Key NavigationIn desktop user interfaces, it is usually helpful to provide a way for the user to navigate between input fields or other interactive items by pressing navigation keys, typically the cursor keys or the Tab key. The KeyNavigation attached property is used to define the relationships between items to allow this kind of navigation. The following example shows two Rectangle items placed in a Row positioner. These are defined with identifiers, leftRect and rightRect. [Missing image declarative-qmlintro-key-navigation1.png] The leftRect rectangle attaches the KeyNavigation.right property, setting it to refer to the rightRect rectangle. The rightRect rectangle attaches the KeyNavigation.left property, referring to the leftRect rectangle. Initially, the leftRect rectangle has the keyboard focus, since its focus property is set to true. When the user presses the right cursor key, the focus is passed to the rightRect rectangle instead, as defined by the KeyNavigation attached property for that item. Pressing the left cursor key causes the focus to be passed back to leftRect because as defined by the KeyNavigation attached property for rightRect. |