Reputation: 235
I have a TextArea
that will usually only contain about one line of text. I do, however, want the user to be able to add more than that and have the TextArea
expand up to a maximum of about 15 lines, at which point any additional text can be accessed via a scroll bar. I've been able to get the scrolling aspect working by having the TextArea
be contained in a Flickable
(which is ultimately contained in a 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 { }
}
}
At this point, how would I go about having the text box expand with the text until some pre-defined max number of pixels (say, 300)?
Edit
Alright, almost there, just having one problem with getting the text to center properly with Mitch's solution. My main.qml
file contains the following:
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
}
}
Any my HelloWorld.qml
file contains the following:
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 {}
}
}
This is very close to working, but for one reason or another, when I have this code outside of main.qml
, the text gets shifted lower and to the right until the user selects it:
After selecting the text, it looks like this (which is what I want it to start at):
Upvotes: 5
Views: 4091
Reputation: 24406
Set the height
of the Flickable
to be contentHeight
or 300
- whichever is smaller:
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 {}
}
}
If you don't want the Rectangle
to be where it is (a sibling of Flickable
), you can remove it, add
clip: true
to the Flickable
and
background: Rectangle {}
to the TextArea
.
Also, if you want to be a bit more precise, you can use FontMetrics
to calculate the line height:
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 {}
}
}
Upvotes: 10
Reputation: 235
Aha! After much searching, I finally found a handy property called paintedHeight
that's part of TextArea
. This will get the height of the text in your TextArea
, so I used this to find that the size of each line is 13 and simply update the height of the base Rectangle
whenever the text is edited, and simply capping it with an if
statement. Here's my wacky solution:
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 { }
}
}
In case anyone else finds themselves in a similar situation, just execute console.log(paintedHeight)
to get the height of the current text (and divide accordingly if you have more than one line) to get the height of your text, as it may be different than mine depending on the style and font you're using (I'm using the Fusion
style). Then just modify the paintedHeight
property in the Rectangle
with your size and the maxNumberOfLines
property in the TextArea
with the maximum number of lines you want the text to have.
Upvotes: 1