Components
The QML, what we’ve just written, is functional enough, but it's already becoming difficult to maintain. Our MasterView is getting a little long and difficult to read. When we come to change how our command buttons look, for example, aligning the icon and text, we will have to change it in four places. If we want to add a fifth button, we have to copy, paste, and edit a whole bunch of QML to do so. This is where reusable components come into play.
Components are exactly the same as the views we have already created—just snippets of QML. The difference is purely semantic. Throughout this book, views represent screens that lay out content while components are the content.
The easiest way to create a new component is when you have already written the QML that you want to form the basis for your component, which we have done. Right-click on any of the Row elements we added for our commands and select Refactoring > Move Component into Separate File.
Name the new component NavigationButton and save it to a new folder—cm/cm-ui/components:
The Row element will be moved to our new file and in MasterView, you will be left with an empty NavigationButton component:
NavigationButton {
}
Unfortunately, it comes with a big red squiggly, and our app will no longer run. While the refactoring step has happily created a new NavigationButton.qml file for us, it's not actually included in our project anywhere, so Qt doesn't know where it is. It’s easy enough to resolve though, and we just need to set up our resources bundle as we did with our views and assets:
- Create a new Qt Resource File called components.qrc in the cm/cm-ui folder
- Create an empty qmldir file in cm/cm-ui/components as we did for our assets
- Edit components.qrc to include both of our new files within a /components prefix:
<RCC> <qresource prefix="/components"> <file alias="qmldir">components/qmldir</file> <file
alias="NavigationButton.qml">components/NavigationButton.qml</file> </qresource> </RCC>
- Edit qmldir to set up our module and add our NavigationButton component to it:
module components
NavigationButton 1.0 NavigationButton.qml
- Ensure that components.qrc has been added to the RESOURCES variable in cm-ui.pro
- In MasterView, include our new components module to get access to our new component:
import components 1.0
We now have a reusable component that hides away the implementation details, reduces code duplication, and makes it much easier to add new commands and maintain the old ones. However, there are a few changes we need to make to it before we can leverage it for our other commands.
Currently, our NavigationButton has hard-coded icon and description text values that will be the same whenever we use the component. We need to expose both the text properties so that we can set them to be different for each of our commands. As we saw, we can achieve this using property aliases, but we need to add unique identifiers to our Text elements for that to work. Let’s set the default values to be something generic and also implement advice from earlier in the book to have an Item component as the root element:
import QtQuick 2.9 import assets 1.0
Item { property alias iconCharacter: textIcon.text property alias description: textDescription.text
Row { Text { id: textIcon font { family: Style.fontAwesome pixelSize: 42 } color: "#ffffff" text: "uf11a" } Text { id: textDescription color: "#ffffff" text: "SET ME!!" } } }
Now that our component is configurable with properties, we can replace our commands in MasterView:
Column { NavigationButton { iconCharacter: "uf0c9" description: "" } NavigationButton { iconCharacter: "uf015" description: "Dashboard" } NavigationButton { iconCharacter: "uf234" description: "New Client" } NavigationButton { iconCharacter: "uf002" description: "Find Client" } }
This is much more concise and manageable than all of the duplicated QML we had earlier. Now, if you run the application, you’ll see that while we’ve taken a couple of steps forward, and that we’ve also taken one step back:
As you can see, all of our components are drawn on top of each other. The root cause of this is the issue we’ve touched on previously regarding sizing. We have a visual component with a root Item element, and we haven’t explicitly defined its size. Another thing we are neglecting is our custom style. Let’s fix those next.