6
votes

We are building a graphical user interface with QtQuick/QML. We have some dynamic, multi-line text coming from a database, which should be displayed in the application. Currently, we are using the Text element to display the text. However, we need some QML components inline embedded into the text. For this, the text coming from the database contains placeholders such as ::checkbox|1:: which should then be replaced and displayed by the program.

In HTML, this is easy, you can simply mix inline elements with text to produce a result like this:

enter image description here

but in QML, this seems to be more difficult, as Text elements cannot be word-wrapped into two halves if there is not enough space (both the text and the container size should be dynamic).

The best solution we could come up with, is creating a Flow layout with one Text element for each word, but this seems too hacky. Using RichText with HTML is not enogh, since we really need our custom QML elements in the text. Also, we want to avoid using a WebView due to performance reasons.

Is there a sophisticated way to implement this with QML/C++ only?

2
I guess the easiest way is to split the string by spaces and so wrap all token to Text or Button or whatever ant put that into Flow. Yes, in this case you lose all text alignments, space rules etc.folibis

2 Answers

1
votes

You can create custom widgets and embed them into QML: Writing QML Extensions with C++

0
votes

I haven't tried placing something in the middle, but I did try adding a tag to the beginning (and I might try adding a tag at the end).

QML's Text has a lineLaidOut signal that let's you indent the first line of text.

http://doc.qt.io/qt-5/qml-qtquick-text.html#lineLaidOut-signal

Here's what I did:

enter image description here

Text {      
    text: issue.summary

    onLineLaidOut: {
        if (line.number == 0) {
            var indent = tagRect.width + tagRect.rightMargin
            line.x += indent
            line.width -= indent
        }
    }

    Rectangle {
        id: tagRect
        implicitWidth: padding + tagText.implicitWidth + padding
        implicitHeight: padding + tagText.implicitHeight + padding
        color: "#400"
        property int padding: 2
        property int rightMargin: 8
        radius: 3

        Text {
            id: tagText
            anchors.centerIn: parent
            text: issue.product
            color: "#fff"
        }
    }
}