如何使 TextArea 具有最大尺寸和滚动条?

Posted

技术标签:

【中文标题】如何使 TextArea 具有最大尺寸和滚动条?【英文标题】:How to make a TextArea have a max size and a scroll bar? 【发布时间】:2019-02-04 20:54:27 【问题描述】:

我有一个TextArea,它通常只包含大约一行文本。但是,我确实希望用户能够添加更多内容并将TextArea 扩展到最多约 15 行,此时可以通过滚动条访问任何其他文本。通过将TextArea 包含在Flickable 中(最终包含在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  
    

此时,我将如何让文本框随着文本展开,直到某个预定义的最大像素数(例如,300)?

编辑

好的,差不多了,只是在使用 Mitch 的解决方案使文本正确居中时遇到了一个问题。我的main.qml 文件包含以下内容:

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
    

我的任何HelloWorld.qml 文件都包含以下内容:

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 
    


这非常接近工作,但出于某种原因,当我在main.qml 之外拥有此代码时,文本会向右下方移动,直到用户选择它:

选择文本后,它看起来像这样(这是我希望它开始的地方):

【问题讨论】:

【参考方案1】:

Flickableheight 设置为contentHeight300 - 以较小者为准:

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 
    

如果您不希望 Rectangle 出现在它所在的位置(Flickable 的同级),您可以删除它,添加

clip: true

Flickable

background: Rectangle 

TextArea

另外,如果你想更精确一点,你可以使用FontMetrics来计算行高:

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 
    

【讨论】:

很好的解决方案,只是一个后续问题:如果我尝试在与包含 ApplicationWindow 的文件不同的文件中使用您的代码,则文本开始移动到矩形之外,直到它被选中。我已经编辑了我的问题以包含我是如何编码的。知道是什么原因造成的吗? 嗯,我认为是填充。设置leftPadding: 0rightPadding: 0 等会有所帮助。在我的脑海中,我不确定它为什么会这样……顺便说一下,你可以用它来帮助可视化contentItemComponent.onCompleted: Qt.createQmlObject("import QtQuick 2.0; Rectangle width: parent.width; height: parent.height; color: '#aaff0000'; ", flickable.contentItem);(将它添加到@987654340 的正文中@)。 谢谢,将填充设置为零确实有帮助,但如果您想要非零填充,问题仍然存在。我注意到,如果我将Flickablewidth 设置为一个数字,而不是从ApplicationWindow 中获取它(即使用400 而不是parent.width),这似乎会引发问题。一旦我将Flickable 移到应用程序窗口之外,我就无法访问该字段。很奇怪。 另一个有趣的事情:如果我使用您的代码来可视化问题,似乎填充在 FlickableTextArea 之间单独发生(如果我将左侧的填充设置为10,TextAreaFlickable 边缘右侧 10 个像素处开始,然后在我开始编辑时重置)【参考方案2】:

啊哈!经过大量搜索,我终于找到了一个方便的属性,名为paintedHeight,它是TextArea 的一部分。这将获得TextArea 中文本的高度,所以我用它来发现每行的大小为 13,并在编辑文本时简单地更新基本Rectangle 的高度,并简单地用if 声明。这是我的古怪解决方案:

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  
    

如果其他人发现自己处于类似情况,只需执行console.log(paintedHeight) 即可获取当前文本的高度(如果您有超过一行,则相应地划分)以获取文本的高度,因为它可能根据您使用的样式和字体与我的不同(我使用的是Fusion 样式)。然后只需将Rectangle 中的paintedHeight 属性修改为您的大小,将TextArea 中的maxNumberOfLines 属性修改为您希望文本具有的最大行数。

【讨论】:

以上是关于如何使 TextArea 具有最大尺寸和滚动条?的主要内容,如果未能解决你的问题,请参考以下文章

在移动端中textarea如何显示滚动条?

textarea 如何设置滚动条

如何在网页的文本框中加滚动条

JavaFX - 如何从TextArea隐藏滚动条?

自动调整 textarea 最大 5 行限制,然后显示滚动条

具有不同滑块的 Spark textarea