Обтекание текста Qml (максимальная ширина)

Я хотел бы поместить текст внутри пузыря, и я хочу, чтобы мой пузырь был равен ширине текста, но если длина текста слишком длинная, я бы хотел, чтобы текст автоматически обертывался и был равен ширине родительского элемента.

Этот код работает, но текст не обертывается, если текст слишком длинный:

Rectangle {
    id:messageBoxCadre
    width: (modelData.messageLength>25)? (wrapper.width - 20): messageBox.width+10
    height: messageBox.height+5
    color: modelData.myMessage ? "#aa84b2":"#380c47"
    radius: 10

    Text {
        id:messageBox
        text: '<b><font color=purple>'+modelData.message+'</font></b> '
        wrapMode: "WordWrap"
    }
}

и я попробовал это, обертывание текста, но если текст слишком мал, ширина пузыря не равна размеру текста:

Rectangle {
    id:messageBoxCadre
    width: (modelData.messageLength>25)? (wrapper.width - 20): messageBox.width+10
    height: messageBox.height+5
    color: modelData.myMessage ? "#aa84b2":"#380c47"
    radius: 10

    Text {
        id:messageBox
        width: (modelData.messageLength>25)? (wrapper.width - 20): messageBox.width
        text: '<b><font color=purple>'+modelData.message+'</font></b> '
        wrapMode: "WordWrap"
    }
}

Ответ 1

Вы можете почти сделать это с помощью состояний. Проблема заключается в том, что попытка установить ширину родительского объекта, назначив его раскрашенному шрифту текстового поля, означает, что он устанавливает ширину текстового поля, которое QML обнаруживает как влияющее на paintWidth. Это не реже, чем это, но QML все еще выдает предупреждения. Один из способов решения этой проблемы состоит в том, чтобы сделать следующее и иметь фиктивное невидимое текстовое поле, которое просто показывает, насколько широким будет текст. Его немного взломать, но он работает хорошо.

Вы можете изменить свойство "когда" для состояния, зависящего от размера текстового поля (а не длины строки), если вы предпочитаете ограничение на пиксель по ширине поля.

import QtQuick 1.0

Rectangle {
    id: containing_rect
    property string text

    text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
    //text: "a short string"

    Text {
        id: text_field
        anchors.top: parent.top
        anchors.left: parent.left

        height: parent.height
        width: parent.width
        text: parent.text
        wrapMode: Text.WordWrap

    }

    Text {
        id: dummy_text
        text: parent.text
        visible: false
    }

    states: [
            State {
                name: "wide text"
                when: containing_rect.text.length > 20
                PropertyChanges {
                    target: containing_rect
                    width: 200
                    height: text_field.paintedHeight
                }
            },
            State {
                name: "not wide text"
                when: containing_rect.text.length <= 20
                PropertyChanges {
                    target: containing_rect
                    width: dummy_text.paintedWidth
                    height: text_field.paintedHeight
                }
            }
        ]
}

Ответ 2

Здесь другой способ, который использует Component.onCompleted script. Это более статично, чем мой другой метод, поэтому я думаю, это зависит от того, что вы хотите с ним сделать.

import QtQuick 1.0

Rectangle {
    id: containing_rect
    property string text

    height: text_field.paintedHeight

    text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
    //text: "a short string"

    Text {
        id: text_field
        anchors.top: parent.top
        anchors.left: parent.left

        height: parent.height
        width: parent.width

        text: parent.text
        wrapMode: Text.WordWrap
    }

    Component.onCompleted: {
        if (text_field.paintedWidth > 200) {
            width = 200
        } else {
            width = text_field.paintedWidth
        }
    }     
}

Ответ 3

Вы также можете попробовать что-то вроде этого, используя указанное текстовое поле:

width: Math.min(dummy_text.paintedWidth, 250)

Это будет использовать окрашенный размер текста, если он не будет больше указанной ширины пикселя.

Ответ 4

Я не использовал состояние, но я использую идею фиктивного текста, чтобы иметь ширину. спасибо

мой код:

                Rectangle{
                id:messageBoxCadre
                width: (modelData.messageLength>25)? (wrapper.width - 20): messageBox.width+10
                height: messageBox.height+5
                color: modelData.myMessage ? "#aa84b2":"#380c47"
                radius: 10

                Text {
                    id:messageBox
                    width: (modelData.messageLength>25)? (wrapper.width - 20): dummy_text.dummy_text
                    text: '<b><font color=purple>'+modelData.message+'</font></b> '
                    wrapMode: "WordWrap"
                }

                Text {
                      id: dummy_text
                      text: '<b><font color=purple>'+modelData.message+'</font></b> '
                      visible: false
                  }

            }

Ответ 5

Попробуйте следующее:

Text {
    property int MAX_WIDTH: 400
    width: MAX_WIDTH
    onTextChanged: width = Math.min(MAX_WIDTH, paintedWidth)
}

Ответ 6

Очевидно, пару лет поздно, но я столкнулся с подобной проблемой (хотя я использую elide вместо wrap, но основы те же). Я закончил тем, что походило на простое и чистое решение, поэтому я решил, что если кто-нибудь еще столкнется с этой проблемой, это может помочь. Использование исходного кода в качестве примера:

        property int maxWidth: 100  // however you want to define the max width

        Rectangle{
            id:messageBoxCadre
            width: messageBox.paintedWidth+10  // width of the actual text, so your bubble will change to match the text width
            height: messageBox.height+5
            color: modelData.myMessage ? "#aa84b2":"#380c47"
            radius: 10

            Text {
                id:messageBox
                text: '<b><font color=purple>'+modelData.message+'</font></b> '
                width: maxWidth  // max width that your text can reach before wrapping
                wrapMode: "WordWrap"
            }
        }

Единственная проблема для этого примера заключается в том, что с WordWrap, если слово слишком длинное, чтобы соответствовать всей ширине элемента Text, оно будет превышать любую максимальную ширину, которую вы установили.