Tengo un TextArea que normalmente solo contendrá una línea de texto. Sin embargo, quiero que el usuario pueda agregar más que eso y hacer que TextArea se expanda hasta un máximo de aproximadamente 15 líneas, momento en el cual se puede acceder a cualquier texto adicional a través de una barra de desplazamiento. He podido hacer funcionar el aspecto de desplazamiento haciendo que el TextArea esté contenido en un Flickable (que finalmente está contenido en un Rectangle).

Rectangle {
    id: rec
    width: 200
    height: 25

    Flickable {
        id: flickable
        anchors.fill: parent
        contentWidth: textArea.width
        contentHeight: textArea.height

        TextArea.flickable:
            TextArea {
            id: textArea
            text: qsTr("Hello, world!")
            wrapMode: Text.WordWrap
        }
        ScrollBar.vertical: ScrollBar { }
    }
}

En este punto, ¿cómo haría para que el cuadro de texto se expandiera con el texto hasta un número máximo predefinido de píxeles (digamos, 300)?

Editar

Muy bien, casi ahí, solo tengo un problema para que el texto se centre correctamente con la solución de Mitch. Mi archivo main.qml contiene lo siguiente:

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    HelloWorld{
        anchors.centerIn: parent
    }
}

Cualquier archivo de mi HelloWorld.qml contiene lo siguiente:

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
import QtQuick.Controls.Styles 1.4

ColumnLayout{

    width: 250

    FontMetrics {
        id: fontMetrics
        font: textArea.font
    }

    Flickable {
        id: flickable
        width: parent.width
        height: Math.min(contentHeight, fontMetrics.height * 15)
        contentWidth: width
        contentHeight: textArea.implicitHeight
        clip: true

        TextArea.flickable: TextArea {
            id: textArea
            text: "Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! "
                + "Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! "
            wrapMode: Text.WordWrap
            //padding: 0

            background: Rectangle {
                border.color: "blue"
            }
        }
        ScrollBar.vertical: ScrollBar {}
    }

}

Esto está muy cerca de funcionar, pero por una razón u otra, cuando tengo este código fuera de main.qml, el texto se desplaza hacia abajo y hacia la derecha hasta que el usuario lo selecciona:

enter image description here

Después de seleccionar el texto, se ve así (que es en lo que quiero que comience): ingrese la descripción de la imagen aquí

3
Kiwi 4 feb. 2019 a las 23:54

2 respuestas

La mejor respuesta

Configure el height del Flickable en contentHeight o 300, el que sea más pequeño:

import QtQuick 2.12
import QtQuick.Controls 2.12

ApplicationWindow {
    width: 400
    height: 400
    color: "#444"
    visible: true

    Rectangle {
        anchors.fill: flickable
    }

    Flickable {
        id: flickable
        width: parent.width
        height: Math.min(contentHeight, 300)
        contentWidth: width
        contentHeight: textArea.implicitHeight

        TextArea.flickable: TextArea {
            id: textArea
            text: qsTr("Hello, world! Hello, world! Hello, world! Hello, world! ")
            wrapMode: Text.WordWrap
        }
        ScrollBar.vertical: ScrollBar {}
    }
}

textarea

Si no desea que Rectangle esté donde está (un hermano de Flickable), puede eliminarlo, agregar

clip: true

A la Flickable y

background: Rectangle {}

Al TextArea.

Además, si desea ser un poco más preciso, puede usar FontMetrics para calcular la altura de la línea:

import QtQuick 2.12
import QtQuick.Controls 2.12

ApplicationWindow {
    width: 400
    height: 400
    color: "#444"
    visible: true

    FontMetrics {
        id: fontMetrics
        font: textArea.font
    }

    Flickable {
        id: flickable
        width: parent.width
        height: Math.min(contentHeight, fontMetrics.height * 15)
        contentWidth: width
        contentHeight: textArea.implicitHeight
        clip: true

        TextArea.flickable: TextArea {
            id: textArea
            text: "Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! "
                + "Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! "
            wrapMode: Text.WordWrap
            padding: 0

            background: Rectangle {}
        }
        ScrollBar.vertical: ScrollBar {}
    }
}
3
Mitch 4 feb. 2019 a las 22:38

¡Ajá! Después de mucho buscar, finalmente encontré una propiedad útil llamada paintedHeight que es parte de TextArea. Esto obtendrá la altura del texto en su TextArea, así que usé esto para encontrar que el tamaño de cada línea es 13 y simplemente actualizar la altura de la base Rectangle cada vez que se edita el texto, y simplemente tapándolo con una instrucción if. Aquí está mi solución loca:

Rectangle {
    property int paintedHeight: 13
    id: rec
    width: 200
    height: paintedHeight * 2

    Flickable {
        id: flickable
        anchors.fill: parent
        contentWidth: textArea.width
        contentHeight: textArea.height

        TextArea.flickable:
            TextArea {
            id: textArea
            wrapMode: Text.WordWrap

            property int maxNumberOfLines: 15
            onTextChanged: {
                rec.height = (lineCount * rec.paintedHeight) + rec.paintedHeight

                // cap the height so that the box stops expanding at maxNumberOfLines
                if(rec.height > rec.paintedHeight * (maxNumberOfLines + 1)){
                    rec.height = rec.paintedHeight * (maxNumberOfLines + 1)
                }
            }
        }
        ScrollBar.vertical: ScrollBar { }
    }
}

En caso de que alguien más se encuentre en una situación similar, simplemente ejecute console.log(paintedHeight) para obtener la altura del texto actual (y divida en consecuencia si tiene más de una línea) para obtener la altura de su texto, como puede ser diferente a la mía dependiendo del estilo y la fuente que estés usando (estoy usando el estilo Fusion). Luego, simplemente modifique la propiedad paintedHeight en Rectangle con su tamaño y la propiedad maxNumberOfLines en TextArea con el número máximo de líneas que desea que tenga el texto.

1
Kiwi 4 feb. 2019 a las 22:31