Reputation: 199
I am developing a Qt Quick application. My goal is to create a keyboard with pressed and released buttons on a qml page. This keyboard has 78 keys.
I wanted to represent a pressed key with the InnerShadow effect and a released key with the DropShadow effect :
Here is the qml code for the key button component :
Button {
id: root
text: "A"
property color textColor: "#397f92"
property color backgroundColor: "#f6f7fa"
property color borderColor: "#397f92"
property real fontSize: 14
property int offset : 2;
font.family: "Helvetica"
font.pointSize: fontSize
font.capitalization: Font.MixedCase
contentItem: Text {
anchors.centerIn: parent
text: root.text
color: textColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font: root.font
}
background: Rectangle {
implicitWidth: 55
implicitHeight: 55
color: backgroundColor
border.color: borderColor
radius: 10
border.width: 2
}
DropShadow {
visible: !root.down
anchors.fill: parent
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 17
color: "#80000000"
source: root.background
cached: false
}
InnerShadow {
visible: root.down
anchors.fill: parent
radius: 8.0
samples: 16
horizontalOffset: 6
verticalOffset: 6
color: "#b0000000"
source: root.background
}
The problem is that loading these 78 components takes time (more than 1sec). So I was looking for a better solution with a similar visual.
When using simple Rectangle components, the loading takes very little time (fast enough so that the user don't notice it).
When using two images (for pressed and released states), the loading also takes time (more than 1sec).
I've been looking for a solution on the documentation and on some forums but maybe I haven't looked for the correct thing. One of the hints I had was to find a way to load the components on the application once and for all when starting it instead of every time I load the page where this buttons are declared, but I haven't found how to do that.
Any help would be welcome to improve the performance of this design...
Here is the code for the use of images:
KeyButton.qml
Button {
id: root
text: "A"
property color textColor: "#397f92"
property color backgroundColor: "#f6f7fa"
property color borderColor: "#397f92"
property real fontSize: 14
property int offset : 2;
font.family: "Helvetica"
font.pointSize: fontSize
font.capitalization: Font.MixedCase
contentItem: Text {
anchors.centerIn: parent
text: root.text
color: textColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font: root.font
}
background:Image {
id: bkg_img
source: root.down ? "qrc:/pressed.png" : "qrc:/release.png"
}
Keypad.qml
Item {
id: keypad_keys
anchors.horizontalCenter: parent.horizontalCenter
width: 57 * 14
anchors.horizontalCenterOffset: - width / 20
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -150
RowLayout {
id: row_layout_0
KeyButton {
id: esc_key
fontSize: 9
text: "esc"
Layout.preferredHeight: 30
Layout.preferredWidth: 57
}
KeyButton {
id: key_f1
fontSize: 9
text: "f1"
Layout.preferredHeight: 30
Layout.preferredWidth: 57
}
KeyButton {
id: key_f2
fontSize: 9
text: "f2"
Layout.preferredHeight: 30
Layout.preferredWidth: 57
}
...
}
}
Upvotes: 0
Views: 843
Reputation: 104494
While dtech is steering you in a good direciton, here are a handful of basic things you can do to improve application startup performance.
Measure loading performance with a retail production build, not a debug build.
Pre-compile your QML files. This can give a pretty significant speed-up in some cases.
If your keyboard isn't expected to appear right when the app starts up, pre-load the QML into a QQuickView when the app starts up. Then call "show" when it's actually needed. This of course just trades off the 1 second of loading time to make the application take longer to load. YMMV.
Use a Loader in your main qml file to load the actual contents. You can actually have the main qml file just have a Loader that hosts your actual QML content file along with a simple animated "spinner" control to show that the UX is loading up. This won't make your keyboard appear any faster, but your application won't seem stuck or hung.
Upvotes: 0
Reputation: 49289
Your buttons have high drawing complexity. The multisampling shadows are especially taxing.
You could bake the shadows as images, at least for the repeating key sizes, that would significantly improve performance.
Or you could use BorderImage
to implement the all keys as composite flat raster graphics.
What you say about using images being slow as well doesn't really add up. Images should be fast, you are probably doing something wrong, but absent your actual code, it is not possible to tell what.
Additionally, you could bake the states of repeating key sizes as an image source and use a trivial shader to draw that cached result very efficiently, and only have the key caption dynamic.
Last but not least, you can scrap the shadows altogether, and use a combination of outline and fill color changes, scaling or linear gradients to achieve a depth effect that is not faked by shadows but by bevels. I mean after all, that inner shadow is not all that realistic in representing a pressed key, keys don't really sink like that.
The shadowy stuff has fallen out of trend many years ago. There are much more efficient ways to achieve a depth effect, here's a couple of basic examples:
Row {
spacing: 6
Rectangle {
width: 100
height: 100
radius: 10
color: "lightgrey"
border.color: "#666666"
border.width: 2
Rectangle {
width: 90
height: 90
x: ma.pressed ? 3 : 6
y: x
radius: 10
color: "darkgrey"
}
MouseArea {
anchors.fill: parent
id: ma
}
}
Rectangle {
width: 100
height: 100
radius: 10
color: ma2.pressed ? "darkgrey" : "lightgrey"
gradient: Gradient {
GradientStop { position: ma2.pressed ? 0 : 1; color: "#666666" }
GradientStop { position: ma2.pressed ? 1 : 0; color: ma2.pressed ? "#777777" : "#efefef" }
}
border.color: "#666666"
border.width: 2
Rectangle {
width: 90
height: 90
anchors.centerIn: parent
radius: 10
scale: ma2.pressed ? .98 : 1
color: "lightgrey"
}
MouseArea {
anchors.fill: parent
id: ma2
}
}
}
Upvotes: 1