Qml文本换行(最大宽度)

20

我想在一个气泡中放置文本,希望气泡的宽度与文本宽度相等,但如果文本太长,则希望文本自动换行并与父元素的宽度相等。

该代码可以工作,但是如果文本太长,文本不会自动换行:

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"
    }
}
7个回答

12
您可以通过状态机实现这个功能,但是尝试将父容器的宽度设置为文本框的绘制宽度,会导致QML检测到影响绘制宽度,从而设置文本框的宽度。虽然这不会进一步递归,但QML仍会警告。解决问题的一种方法是创建一个虚拟的、不可见的文本框,只是计算出文本的宽度/应该有的宽度。这有点像“hack”,但工作得很好。
如果您更喜欢对框的宽度设置像素限制,那么可以将状态的“when”属性改为依赖于虚拟文本框的大小(而不是字符串的长度)。
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
                }
            }
        ]
}

5

以下是另一种方法,它使用Component.onCompleted脚本。相对于我的其他方法更加静态,所以我想这取决于你想要做什么。

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

我已经尝试过在文本被修改时触发更改的想法,因此在text_field项目中创建了一个onTextChanged,但似乎在更新paintedWidth之前就会调用onTextChanged。然而,这将允许一种替代方式来拥有动态文本框。这个评论只是为了完整性。 - Henry Gomersall
我更喜欢这种方法。我不需要使用 paintedWidth 进行比较,width 也可以。 - Akash Agarwal

4

虽然有些晚了,但一个干净的解决方案是使用嵌入式的TextMetrics对象。像这样:

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

3
您可以尝试像这样使用上述提到的虚拟文本框来实现此功能:
width: Math.min(dummy_text.paintedWidth, 250)

除非文字的尺寸大于您指定的像素宽度,否则将使用文字的绘制尺寸。


2

试试这个:

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

0

我没有使用状态,但是我使用了虚拟文本的想法来设置宽度。谢谢。

我的代码:

                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
                  }

            }

0

显然晚了几年,但我遇到了类似的问题(虽然我使用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项目的整个宽度,它将超出您设置的任何最大宽度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接