I have an application where I display the time on the screen. It works well except very rarely it sometimes does not render the time fully and skips rendering a number. For example if time is "11:07", it would render "11:0 " or "1 :07". I know it's a rendering problem because it fixes itself when the time changes and I can't recreate it by force setting the same time. Also I have the time in another screen in much smaller font, and I never see this issue there. I suspect it's something to do with rendering text in a large fontSize that causes this problem.
I tried creating the duplicate of my time text and using TextMetrics for both time text elements and compare their widths. If their widths are different, I assume that it did not render fully. I don't think this would actually work tho since it seems like the width of the elements would be the same, even if they don't render fully. I looked into SafeText but that does not work for my constraints. I am using NativeRendering since my font size is big (> 200px). Here is a MRE:
import QtQuick 2.15
import QtQuick.Window 2.2
import QtQuick.Controls 2.15
Window {
width: 1024
height: 600
visible: true
property string time: Qt.formatTime(new Date(),"hh:mm")
onTimeChanged: {
if(timeText.width !== timeTextDuplicate.width || timeMetric.width !== timeMetricDuplicate.width) {
console.log("They are not the same")
// redraw time
time = ""
time = Qt.formatTime(new Date(),"hh:mm")
}
}
Rectangle {
id: root
anchors.fill: parent
color: "black"
Text {
id: timeText
anchors.centerIn: parent
font.pixelSize: 200
color: "white"
text: time
}
TextMetrics {
id: timeMetric
text: timeText.text
font: timeText.font
}
Text {
id: timeTextDuplicate
font: timeText.font
text: timeText.text
visible: false
}
TextMetrics {
id: timeMetricDuplicate
text: timeTextDuplicate.text
font: timeTextDuplicate.font
}
Timer {
id: timer
interval: 60000
repeat: true
running: true
onTriggered: time = Qt.formatTime(new Date(),"hh:mm")
}
}
}
This is the output I get after setting QSG_RENDERER_DEBUG=render
Renderer::render() QSGAbstractRenderer(0x7f52702a63d0) "rebuild: full"
Rendering:
-> Opaque: 1 nodes in 1 batches...
-> Alpha: 6 nodes in 3 batches...
- 0x7f52702be8a0 [ upload] [noclip] [opaque] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0
- 0x7f52702be710 [ upload] [noclip] [ alpha] [ merged] Nodes: 4 Vertices: 56 Indices: 84 root: 0x0 opacity: 1
- 0x7f52702be240 [ upload] [noclip] [ alpha] [unmerged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0
- 0x7f52702bdd70 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 1
-> times: build: 0, prepare(opaque/alpha): 0/0, sorting: 0, upload(opaque/alpha): 0/0, render: 0
Renderer::render() QSGAbstractRenderer(0x7f5270006190) "rebuild: full"
Rendering:
-> Opaque: 2 nodes in 1 batches...
-> Alpha: 19 nodes in 17 batches...
- 0x7f52700d50a0 [ upload] [noclip] [opaque] [ merged] Nodes: 2 Vertices: 8 Indices: 12 root: 0x0
- 0x7f52700d18a0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 0.2
- 0x7f52702c5ad0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 152 Indices: 232 root: 0x0 opacity: 0.2
- 0x7f52702c59e0 [ upload] [noclip] [ alpha] [unmerged] Nodes: 2 Vertices: 184 Indices: 280 root: 0x0
- 0x7f52702c62c0 [ upload] [noclip] [ alpha] [unmerged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0
- 0x7f52702fdc90 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 32 Indices: 48 root: 0x0 opacity: 1
- 0x7f527030db10 [ upload] [noclip] [ alpha] [unmerged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0
- 0x7f52702c6040 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 96 Indices: 144 root: 0x0 opacity: 1
- 0x7f52702c5dc0 [ upload] [noclip] [ alpha] [unmerged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0
- 0x7f52700d5360 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 84 Indices: 126 root: 0x0 opacity: 1
- 0x7f52700c8150 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 1
- 0x7f52702f0730 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 1
- 0x7f52702c0ce0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 16 Indices: 24 root: 0x0 opacity: 1
- 0x7f52702c5f00 [ upload] [noclip] [ alpha] [ merged] Nodes: 2 Vertices: 184 Indices: 284 root: 0x0 opacity: 1
- 0x7f52702c5cb0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 1
- 0x7f52702c5bc0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 8 Indices: 12 root: 0x0 opacity: 1
- 0x7f52702c5800 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 4 Indices: 6 root: 0x0 opacity: 1
- 0x7f52702c58f0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 48 Indices: 72 root: 0x0 opacity: 1
-> times: build: 0, prepare(opaque/alpha): 0/0, sorting: 0, upload(opaque/alpha): 0/0, render: 0
I understand this could be a problem with the graphics card or QML itself, but is there anything I could do to detect that this has happened? Thanks
I use
TextMetricsslightly differently. I built aBigTextcomponent that chooses the largest value forfont.pixelSizeso that your text will fit but will not exceed the bounding rectangle. It does this by:widthandheightof the bounding rectangleTextMetricswidthandheightfor a "small" pixel sizeThe other point I would like to make is in your code, you set
TextMetricsfont as follows:I have found this can screw things up as you're no longer using the original
fontthat came withTextMetrics. I have found it safer to copy the font properties you need, e.g.To see these concepts in in action, I changed your application by (1) increasing the frequency of your timer from
1 minuteto1 second. Change the time format from "hh:mm" to "hh:mm:ss".Whilst running this app, try resizing the window and note the text font dynamically changes.
You can Try it Online!