开发者

Qml text wrap (max width)

开发者 https://www.devze.com 2023-03-13 08:47 出处:网络
I would like to put text inside a bubble, and I want that my bubble be equal to the text width, but if the text length is too long, I would like the text to wrap automati开发者_JAVA百科cally and be eq

I would like to put text inside a bubble, and I want that my bubble be equal to the text width, but if the text length is too long, I would like the text to wrap automati开发者_JAVA百科cally and be equal to the parent width.

This code works but the text is not wrapping if text is too long:

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"
    }
}

and I tried this, text wrap, but if the text is too small the bubble width is not equal to the text size:

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"
    }
}


You can almost do this neatly with states. The problem is that attempting to set the width of the parent by assigning it to the paintedWidth of the text box means it then sets the width of the text box, which QML detects as influencing paintedWidth. It wouldn't recurse further than this, but QML still kicks out warnings. One way around the problem is to do as follows, and have a dummy invisible text box that just works out how wide the text is/should be. Its a bit of a hack, but it works nicely.

You could change the "when" property of the state to be dependent on the size of the dummy text box (rather than the length of the string) if you preferred a pixel limit on the width of the box.

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
                }
            }
        ]
}


Here's another way, which uses the Component.onCompleted script. It's more static than my other method, so I guess it depends on what you want to do with it.

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
        }
    }     
}


Very late to the party but the clean solution is to use an embedded TextMetrics object. Like this:

...
Text {
  id: textObj
  width: Math.min(textWidth, myThreshold)

  // access to binding-loop-free width and height:
  readonly property alias textWidth: textMetrics.boundingRect.width
  readonly property alias textHeight: textMetrics.boundingRect.height

  TextMetrics {
    id: textMetrics
    font: textObj.font
    text: textObj.text
    elide: textObj.elide
  }
}


You can also try something like this, using the dummy text box mentioned above:

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

This will use the painted size of the text unless it is greater than your specified pixel width.


Try this:

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


i did not use state, but i use the idea of dummy text to have width. thanks

my code :

                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
                  }

            }


Obviously a couple years late, but I just ran into a similar issue (though I am using elide instead of wrap but the basics are the same). I ended up with what seems like a simple and clean solution so I figured if anyone else runs into this problem it can maybe help. Using the original code as an example:

        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"
            }
        }

The only problem for this example is that with WordWrap, if a word is too long to fit the entire width of the Text item it will exceed whatever maxWidth you have set.

0

精彩评论

暂无评论...
验证码 换一张
取 消