End to End GUI Development with Qt5
上QQ阅读APP看书,第一时间看更新

Command bar

Let’s begin by adding some more properties to Style for our command components:

readonly property color colourCommandBarBackground: "#cecece"
readonly property color colourCommandBarFont: "#131313"
readonly property color colourCommandBarFontDisabled: "#636363"
readonly property real heightCommandBar: heightCommandButton
readonly property int pixelSizeCommandBarIcon: 32
readonly property int pixelSizeCommandBarText: 12
readonly property real widthCommandButton: 80 readonly property real heightCommandButton: widthCommandButton

Next, create two new QML components in our UI project: CommandBar.qml and CommandButton.qml in cm-ui/components. Update components.qrc and move the new components into the /components prefix with aliases. Edit qmldir and append the new components:

CommandBar 1.0 CommandBar.qml
CommandButton 1.0 CommandButton.qml

For our button design, we want to lay out the description below the icon. The icon should be positioned slightly above centre. The component should be square, as follows:

CommandButton.qml:

import QtQuick 2.9
import CM 1.0
import assets 1.0
Item { property Command command width: Style.widthCommandButton height: Style.heightCommandButton
Rectangle { id: background anchors.fill: parent color: Style.colourCommandBarBackground
Text { id: textIcon anchors { centerIn: parent verticalCenterOffset: -10 } font { family: Style.fontAwesome pixelSize: Style.pixelSizeCommandBarIcon } color: command.ui_canExecute ? Style.colourCommandBarFont :
colourCommandBarFontDisabled
text: command.ui_iconCharacter horizontalAlignment: Text.AlignHCenter } Text { id: textDescription anchors { top: textIcon.bottom bottom: parent.bottom left: parent.left right: parent.right } font.pixelSize: Style.pixelSizeNavigationBarText color: command.ui_canExecute ? Style.colourCommandBarFont :
colourCommandBarFontDisabled
text: command.ui_description horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter }
MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true onEntered: background.state = "hover" onExited: background.state = "" onClicked: if(command.ui_canExecute) { command.executed(); } }
states: [ State { name: "hover" PropertyChanges { target: background color: Qt.darker(Style.colourCommandBarBackground) } } ] } }

This is largely similar to our NavigationButton component. We pass in a Command object, which is where we will obtain the icon character and description to display in the Text elements as well as the signal to emit when the button is pressed, so long as the command can execute.

We use an alternative to the Row/Column based layout and use anchors to position our icon and description instead. We center the icon in the parent Rectangle and then apply a vertical offset to move it up and allow space for the description. We anchor the top of the description to the bottom of the icon.

Rather than propagating a signal when the button is pressed, we emit the executed() signal of the Command object, first verifying that the command can execute. We also use this flag to selectively color our text elements, using a paler grey font if the command is disabled.

We implement some more hover functionality with our MouseArea, but rather than exposing a property to pass in the hover color, we simply take the default and darken it a few shades using the built-in Qt.darker() method. We also only apply the state change in the onEntered() slot of the MouseArea if the command can be executed.

CommandBar.qml:

import QtQuick 2.9
import assets 1.0
Item { property alias commandList: commandRepeater.model
anchors { left: parent.left bottom: parent.bottom right: parent.right } height: Style.heightCommandBar
Rectangle { anchors.fill: parent color: Style.colourCommandBarBackground
Row { anchors { top: parent.top bottom: parent.bottom right: parent.right }
Repeater { id: commandRepeater delegate: CommandButton { command: modelData } } } } }

Again, this is largely the same as NavigationBar, but with a dynamic list of commands rather than hard-coded QML buttons. We introduce another new component—the Repeater. Given a list of objects via the model property, Repeater will instantiate a QML component defined in the delegate property for each item in the list. The object from the list is made available via the built-in modelData variable. Using this mechanism, we can automatically generate a CommandButton element for each command we have in a given list. We use another property alias so that the caller can set the command list.

Let’s put this to use in CreateClientView. First, import components 1.0, and then add the following inside the root Item and after the Rectangle:

CommandBar {
    commandList: masterController.ui_commandController.ui_createClientViewContextCommands
}

We drill down through our property hierarchy to get the command list for the create client view and pass that list to the command bar which takes care of the rest. Don’t worry if the CommandBar has red squiggles, Qt Creator just needs to catch up with our blistering pace.

Run the app and navigate to Create Client View:

Click on the button, and you will see the message output to the console. Adding new commands is as simple as appending a new Command object to the QList inside CommandController—no UI changes needed! The command bar will automatically create a new button for every command it finds in the list. Also note that this command bar is only present on the CreateClientView, so it is context sensitive. We can easily add command bars to other views by simply adding extra lists and properties to the CommandController, as we will later.