Qt Quick-创建具有可变行高的GridView的正确方法是什么?

时间:2019-10-17 22:39:58

标签: qt gridview qml qt5

我正在Windows 10专业计算机上使用Qt 5.13.0开发应用程序。我需要创建一个类似于消息视图的Whatsapp,为实现这一点,我使用了GridView组件作为基础。但是,为了正确绘制消息,我需要根据消息文本创建具有不同高度的每个GridView行。

但是令我惊讶的是,尽管我认为这是一个简单的手续,但我在互联网上找不到任何解决方案。我自己尝试了一个解决方案,下面附上了它,但是它不起作用。问题在于,所有行都采用最后一个调整大小的行的高度。

我毫不怀疑Qt可以做到这一点,不幸的是,我已经寻找了好几天,而我找不到解决该问题的方法。我根本不知道如何实现这一目标。因此,有人可以向我解释如何创建具有可变高度的行的GridView,或者如果GridWiew不是执行此操作的适当组件,我应该使用它代替吗?

这是我的qss文件:

import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.12
import QtQuick.Layouts 1.11

Window
{
    visible: true
    width: 640
    height: 480
    title: qsTr("Grid view")
    color: "#ffffff"

    ColumnLayout
    {
        transformOrigin: Item.Center
        spacing: 0
        x: 0
        y: 0
        width: parent.width
        height: parent.height

        /**
        * Grid view item
        */
        Component
        {
            id: itGridItem

            Item
            {
                Column
                {
                    Rectangle
                    {
                        property int messageWidth: (gvMessageGrid.cellWidth / 2) - 50

                        id: itemRect
                        x: senderIsMyself ? 25 : gvMessageGrid.cellWidth - (25 + messageWidth)
                        y: 5
                        width: messageWidth
                        height: itemTextID.height + 20
                        color: senderIsMyself ? "#d5d5d5" : "#800b940e"
                        radius: 5
                        clip: true

                        Text
                        {
                            id: itemTextID
                            width: parent.width - 20
                            text: itemText
                            renderType: Text.NativeRendering
                            textFormat: TextEdit.RichText
                            wrapMode: Text.WordWrap
                            font.family: "Segoe UI Emoji"
                            font.pixelSize: 18
                            anchors.margins: 10
                            anchors.left: parent.left
                            anchors.top: parent.top
                            color: "#101010"
                        }

                        onHeightChanged: gvMessageGrid.cellHeight = height + 10
                    }
                }
            }
        }

        /**
        * Messages grid view
        */
        GridView
        {
            id: gvMessageGrid
            y: 0
            Layout.fillHeight: true
            flickableDirection: Flickable.VerticalFlick
            Layout.fillWidth: true
            Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
            clip: true
            contentWidth: 700
            contentHeight: 300
            cellWidth: contentWidth
            cellHeight: 150
            model: lmGridModel
            delegate: itGridItem

            ScrollBar.vertical: ScrollBar
            {
                visible: true
            }

            onWidthChanged: cellWidth = width
        }
    }
}

---于2019年10月18日编辑

在下面的eyllanesc建议之后,以下是我想要和得到的两个屏幕截图:

我想要的


enter image description here

我会得到什么


enter image description here

注意,出于测试目的,我正在使用多种语言,因为我的应用程序必须具有国际支持。但是,我遇到的问题与此无关,即,它不是文本计算错误,因为1.文本周围的绿色矩形大小始终正确,并且2.我遇到的是纯英文文本。 / p>

1 个答案:

答案 0 :(得分:1)

我建议您使用ListView而不是GridView。您可以轻松查看全角列表项中的所有内容。让我与您分享旧项目中的ListDelegate类。注意在锚定绑定中使用isIncoming属性,例如:

anchors {
    left: isIncoming? undefined : parent.left
    right: isIncoming? parent.right : undefined
}

完整列表:

import QtQuick 2.5

import "units.js" as Units

Rectangle {
    id: chatMsgDelegRoot

    property bool isIncoming: !model.out
    property bool isSelected: model.isSelected

    signal clicked(int index)

    width: parent.width
    height: dlgColumn.height + Units.gu(2.5)
    color: "#edf1f5"

    Column {
        id: dlgColumn
        spacing: Units.gu(4)
        width: parent.width
        anchors.verticalCenter: parent.verticalCenter

        BorderImage {
            id: borderImage

            source: isIncoming?
                        (isSelected ? "/images/img/MsgOut_Selected_2.png" : "/images/img/MsgOut_2.png") :
                        (isSelected ? "/images/img/MsgIn_Selected_2.png" : "/images/img/MsgIn_2.png")

            // Texture-dependent.
            border {
                left: isIncoming? 20 : 30
                top: 20
                right: isIncoming? 30 : 20
                bottom: 35
            }

            anchors {
                left: isIncoming? undefined : parent.left
                right: isIncoming? parent.right : undefined
            }
            width: Math.max(content.width + Units.gu(15), Units.gu(21))
            height: content.height + Units.gu(9)

            MouseArea {
                id: msgDelegateMa
                anchors.fill: parent
                onClicked: chatMsgDelegRoot.clicked(model.index)
            }

            Loader {
                id: content
                sourceComponent: model.type === "Text" ? textComponent : controlComponent
                anchors {
                    left: isIncoming? undefined : parent.left
                    right: isIncoming? parent.right : undefined
                    leftMargin: Units.gu(10)
                    rightMargin: Units.gu(10)
                    top: parent.top
                    topMargin: Units.gu(4)
                }
            }

            Text {
                text: model.date.toTimeString()
                font.pointSize: 8
                font.italic: true;
                color: "lightgrey"
                anchors {
                    left: isIncoming? undefined : parent.left
                    right: isIncoming? parent.right : undefined
                    rightMargin: Units.gu(7.5)
                    leftMargin: Units.gu(7.5)
                    bottom: parent.bottom
                    bottomMargin: Units.gu(1)
                }
            }
        } // BorderImage
    } // Column

    // TODO To separate files.
    Component {
        id: textComponent

        Rectangle {
            id: textComponentRoot

            color: "#00000000"
            width: msgText.paintedWidth
            height: msgText.height

            Text {
                id: msgText
                font.pointSize: 10
                textFormat: Text.RichText
                wrapMode: Text.WrapAtWordBoundaryOrAnywhere
                width: chatMsgDelegRoot.width * 0.7
                text: model.body
                color: isSelected? "white" : "black"
            }
        }
    } // Component

    Component {
        id: controlComponent

        Rectangle {
            id: textComponentRoot

            color: "#00000000"
            width: innerColumn.width
            height: innerColumn.height

            Column {
                id: innerColumn
                spacing: Units.gu(1)

                Text {
                    id: fileNameText
                    font.pointSize: 10
                    wrapMode: Text.WrapAtWordBoundaryOrAnywhere
                    width: chatMsgDelegRoot.width * 0.7
                    elide: Text.ElideRight
                    text: "File transfer: " + model.body
                    color: isSelected? "white" : "black"
                }

                Row {
                    id: innerRow
                    anchors.right: parent.right
                    spacing: Units.gu(1)

                    SimpleButton {
                        id: allowBtn
                        width: Units.gu(15)
                        height: Units.gu(8)
                        text: "Allow"
                    }

                    SimpleButton {
                        id: denyBtn
                        width: Units.gu(15)
                        height: Units.gu(8)
                        text: "Deny"
                    }
                }
            } // Column
        }
    } // Component
}