Qml 文本换行(最大宽度)

问题描述 投票:0回答:8

我想将文本放入气泡内,并且我希望气泡等于文本宽度,但如果文本长度太长,我希望文本自动换行并等于父宽度。

此代码有效,但如果文本太长,文本不会换行:

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"
    }
}
qt qml qt-quick
8个回答
12
投票

你可以几乎通过状态巧妙地做到这一点。问题在于,尝试通过将父级的宽度分配给文本框的 PaintWidth 来设置父级的宽度意味着它随后会设置文本框的宽度,而 QML 检测到该宽度会影响 PaintWidth。它不会进一步递归,但 QML 仍然会发出警告。解决该问题的一种方法是执行以下操作,并有一个虚拟的不可见文本框,该文本框仅计算出文本的宽度/应该有多宽。虽然有点麻烦,但效果很好。

如果您希望对框的宽度进行像素限制,则可以将状态的“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
        }
    }     
}

5
投票

聚会已经很晚了,但干净的解决方案是使用嵌入式 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 而不是wrapper,但基础知识是相同的)。 我最终得到了一个看起来简单干净的解决方案,所以我想如果其他人遇到这个问题它可能会有所帮助。 以原代码为例:

        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 时,如果单词太长而无法容纳文本项的整个宽度,它将超出您设置的 maxWidth。


0
投票

对于那些多年后发现这个问题的人来说,这是一个现代的解决方案。

只要有最大宽度,您就想利用

Layout.maximumWidth
,这需要使用布局。由于我们只有一个组件,因此无论使用 RowLayout、ColumnLayout 还是 GridLayout 都没有关系。

import QtQuick
import QtQuick.Layouts

RowLayout {
    Rectangle {
        implicitWidth: messageBox.implicitWidth + 5
        implicitHeight: messageBox.implicitHeight + 5
        Layout.maximumWidth: messageBox.maxWidth + 5
        Layout.fillWidth: true

        color: modelData.myMessage ? "#aa84b2":"#380c47"
        radius: 10

        Text {
            property alias maxWidth: dummy.implicitWidth
            id:messageBox

            anchors.fill: parent
            anchors.margins: 2.5

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

这个例子最好从里到外进行评估。

        Text {
            anchors.fill: parent
            anchors.margins: 2.5
            clip: true
        }

文本组件使用

anchors.fill
anchors.margins
将自身限制在其父级(矩形)的边界内。它现在知道它需要有多大以及应该在哪里。

然而,现在矩形的宽度和高度都是0,这可以通过为文本设置

clip: true
来看到:

A window containing nothing.

矩形是布局的直接子级,这意味着它的大小和位置由布局管理(与文本不同,文本管理自己的大小和位置)。虽然布局知道矩形应该在哪里(Layout.alignment有默认值),但它不知道它应该有多大。它的大小默认为零。

    Rectangle {
        implicitWidth: messageBox.implicitWidth + 5
        implicitHeight: messageBox.implicitHeight + 5

        Text {
            id:messageBox

            anchors.fill: parent
            anchors.margins: 2.5
        }
    }

我们可以使用 
implicitWidth

implicitHeight
来通知布局,它们共同构成了矩形的
首选尺寸
。如果我们无法访问 implicitWidth
implicitHeight
,我们将使用
Layout.preferredWidth
Layout.preferredHeight

Purple Rectangle containing Text inside a wider window. The Rectangle is the size of the Text.Now, the window is narrower than the Rectangle, but the Rectangle didn't change. 现在布局知道矩形应该有多大,但它并没有限制其宽度。

RowLayout { Rectangle { implicitWidth: messageBox.implicitWidth + 5 implicitHeight: messageBox.implicitHeight + 5 Layout.maximumWidth: messageBox.maxWidth + 5 Text { property alias maxWidth: dummy.implicitWidth id:messageBox anchors.fill: parent anchors.margins: 2.5 Text { id: dummy text: parent.text visible: false } } } }

Layout.maximumWidth

可用于限制布局内组件的宽度。矩形的宽度应限制为文本未换行时的宽度。要确定此宽度,可以使用带有

wrapMode: Text.NoWrap
的相同文本进行测量。由于它只是用于测量,所以使用
visible: false
来防止它被看见并影响布局。

Nothing changed. 等等,什么都没有改变。我真的不知道为什么,但是

Layout.maximumWidth

仅适用于

Layout.fillWidth: true
在这种情况下,

Layout.fillWidth: true

的行为类似于

anchors{left: parent.left;right:parent.right}
,只不过它尊重
Layout.maximumWidth
RowLayout {
    Rectangle {
        implicitWidth: messageBox.implicitWidth + 5
        implicitHeight: messageBox.implicitHeight + 5
        Layout.maximumWidth: messageBox.maxWidth + 5
        Layout.fillWidth: true

        Text {
            property alias maxWidth: dummy.implicitWidth
            id:messageBox

            anchors.fill: parent
            anchors.margins: 2.5
            Text {
                id: dummy
                text: parent.text
                visible: false
            }
        }
    }
}

The Rectangle is now limited to the width of the window. The text wraps as expected.

© www.soinside.com 2019 - 2024. All rights reserved.