Qt Quick - Как правильно создать GridView с переменной высотой строки? - PullRequest
1 голос
/ 18 октября 2019

Я занимаюсь разработкой приложения с Qt 5.13.0 на профессиональном компьютере с Windows 10. Мне нужно создать вид сообщения в стиле 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
        }
    }
}

--- Отредактировано 18 октября 2019 г.

Следуя приведенному ниже предложению eyllanesc, вот 2 скриншота того, что я хочу и что я получаю:

что я хочу


enter image description here

что я получаю


enter image description here

ПРИМЕЧАНИЕ Я использую несколько языков для целей тестирования, потому что мое приложение должно иметь международную поддержку. Однако проблема, с которой я сталкиваюсь, не имеет к этому никакого отношения, то есть это не ошибка при вычислении текста, потому что 1. Размеры зеленого прямоугольника вокруг текста всегда правильные, и 2. Я сталкиваюсь с точно такой же проблемой с чисто английским текстом.

1 Ответ

1 голос
/ 19 октября 2019

Я предлагаю вам использовать 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
}
...