Qml 文本换行(最大宽度)

发布于 2024-11-15 09:22:55 字数 1042 浏览 5 评论 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
        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"
    }
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

爱冒险 2024-11-22 09:22:55

几乎可以通过状态巧妙地做到这一点。问题在于,尝试通过将父级的宽度分配给文本框的 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
                }
            }
        ]
}

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
                }
            }
        ]
}
漫漫岁月 2024-11-22 09:22:55

这是另一种方法,它使用 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
        }
    }     
}

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
        }
    }     
}
戈亓 2024-11-22 09:22:55

聚会已经很晚了,但干净的解决方案是使用嵌入式 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
  }
}

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
  }
}
ぽ尐不点ル 2024-11-22 09:22:55

您还可以尝试类似的操作,使用上面提到的虚拟文本框:

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

这将使用文本的绘制大小,除非它大于您指定的像素宽度。

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.

夜深人未静 2024-11-22 09:22:55

试试这个:

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

Try this:

Text {
    property int MAX_WIDTH: 400
    width: MAX_WIDTH
    onTextChanged: width = Math.min(MAX_WIDTH, paintedWidth)
}
往事随风而去 2024-11-22 09:22:55

我没有使用状态,但我使用虚拟文本的想法来获得宽度。谢谢

我的代码:

                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
                  }

            }

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
                  }

            }
生生不灭 2024-11-22 09:22:55

显然晚了几年,但我刚刚遇到了类似的问题(虽然我使用的是 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。

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.

零度℉ 2024-11-22 09:22:55

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

每当某些东西具有最大宽度时,您就需要利用 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
        }

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

但现在,矩形的宽度和高度均为 0,这可以通过为文本设置 clip: true 来查看:

不包含任何内容的窗口。

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

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

        Text {
            id:messageBox

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

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

紫色矩形矩形是文本的大小。
现在,窗口比矩形窄,但矩形没有改变。

现在布局知道矩形应该有多大,但它并没有限制其宽度。

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 来防止其可见并影响布局。

没有任何改变.

等等,什么都没有改变。我真的不知道为什么,但是 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
            }
        }
    }
}

矩形现在限制为窗口的宽度。

Here's a modern solution for those who find this question years later.

Whenever something has a maximum width, you want to leverage Layout.maximumWidth, which requires using a layout. Since we only have one component, it doesn't matter whether we use RowLayout, ColumnLayout or 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
            }
        }
    }
}

This example is best evaluated inside out.

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

The Text component uses anchors.fill and anchors.margins to constrain itself within the bounds of its parent (the Rectangle). It now knows how big it needs to be and where it should be.

Right now, however, the Rectangle's width and height are 0, which can be seen by setting clip: true for the Text:

A window containing nothing.

The Rectangle is the direct child of a layout, which means its size and position is managed by the layout (unlike the Text, which manages its own size and position). While the layout knows where the Rectangle should be (Layout.alignment has a default value), it doesn't know how big it should be. Its size defaults to zero.

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

        Text {
            id:messageBox

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

We can inform the layout using implicitWidth and implicitHeight, which together make up the Rectangle's preferred size. If we didn't have access to implicitWidth and implicitHeight, we would use Layout.preferredWidth and 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.

Now the layout knows how big the Rectangle should be, but it doesn't limit its width as it should.

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 can be used to limit the width of a component within a layout. The Rectangle's width should be limited to the width that the Text would be when not wrapped. To determine this width, an identical Text with wrapMode: Text.NoWrap can be used for measurement. Since it's only used for measurement, visible: false is used to prevent it from being visible and affecting the layout.

Nothing changed.

Wait, nothing changed. I don't really know why, but Layout.maximumWidth only applies when Layout.fillWidth: true.

Layout.fillWidth: true behaves like anchors{left: parent.left;right:parent.right} in this situation, except that it respects 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文