Better way to elide multiline text?
-
For a TableView headerDelegate I need elided multiline text like this
no elide this time.....s needed not here
I have managed to get a somewhat hackish solution for this. But it feels like taking a sledgehammer to crack a nut. Does anybody know a more elegant way to do this? Here's what I do:
Text { id: textItem property string fullText: styleData.value function isMultiline(text) { return text.indexOf('\n') >= 0 } function recompose() { var s = ""; for (var i = 0; i<textMetricsRepeater.count;) { s += textMetricsRepeater.itemAt(i).line if (++i < textMetricsRepeater.count) { s += '\n'; } } return s; } width: parent.width anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter anchors.leftMargin: 5 text: isMultiline(fullText) ? recompose() : fullText color: textColor textFormat: Text.PlainText elide: Text.ElideMiddle // will *not* work with multiline (\n) or rich text (<b>) Repeater { id: textMetricsRepeater property var modelVar: textItem.fullText.split('\n') model: modelVar Item { property string line: headerDelegateTextMetrics.elidedText visible: false TextMetrics { id: headerDelegateTextMetrics property string str: textMetricsRepeater.modelVar[index] text: str.trim() elideWidth: textItem.width - 5 elide: Text.ElideMiddle } } } }
-
@SeDi
What about writing your own QML Text type, e.g. based on the following C++ example:
http://doc.qt.io/qt-5/qtwidgets-widgets-elidedlabel-example.html -
Thank you, @Diracsbracket, you are absolutely right, that's a much more elegant way! I'll have a look into that!
-
Uh. :-( Seems to me that the QML Text Type headers are private. Is that correct?
I am not sure if this is the correct header: qquicktext_p.h
It would be sad.
-
As QLabel belongs to the QWidget world, that wouldn't work in QML, or would it? I am not really sure here. At least I'd think it strange to include widgets in my project.
Looking around, I've found this thread that actually kind of discourages me a bit:
QML uses SceneGraph for painting, where QWidgets use a raster engine for painting. So they unfortunately dont play very well together. [...] You would need to render the widget as a texture on every paint event.
But, on the other hand: by now Qt is 3 years older. I am not sure what to do.
I have looked out for non-private headers in the folder QT\5.11.1\Src\qtdeclarative\src\quick\items and found these:
- qquickframebufferobject.h
- qquickitem.h
- qquickitemgrabresult.h
- qquickpainteditem.h
- qquickrendercontrol.h
- qquicktextdocument.h
- qquickview.h
- qquickwindow.h
I think I've seen the use of QQuickItem and QQuickPaintedItem before. QQuickTextDocument seems interesting, but I don't understand, if it is private or not, because of the use of Q_DECLARE_PRIVATE here:
public: QQuickTextDocument(QQuickItem *parent); QTextDocument *textDocument() const; private: Q_DISABLE_COPY(QQuickTextDocument) Q_DECLARE_PRIVATE(QQuickTextDocument)
Has anyone done a similar thing?
Any (perhaps different) ideas? -
This post is deleted!
-
Why don't you use a
Text
item for each line and wrap them in aColumn
? -
@GrecKo: Thank you! This is exactly that kind of idea I have been to stupid to come up with by myself. Now that you write it, it seems kind of obvious. Works like a charm and is shorter, faster, smarter and so much better readable . As a bonus: the TextMetric does not elide styledText correctly - Text does :-)).
For posterity, here's my code:
Column { anchors.fill: parent Repeater { id: textRepeater property var modelVar: styleData.value.includes('<br>') ? styleData.value.split('<br>') : styleData.value.split('\n') model: modelVar Text { id: textItem width: parent.width height: textRepeater.count > 0 ? parent.height / textRepeater.count : parent.height text: textRepeater.modelVar[index].trim() verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter anchors.leftMargin: 5 color: textColor textFormat: Text.StyledText elide: Text.ElideMiddle } } }
-
If you are using
height: parent.height / textRepeater.count
, you might want to useColumnLayout
instead ofColumn
, it will handle the height of its children automatically. -
Thank you, @GrecKo, for that additional idea!
I've checked it out, but I always have problems with the layouts, because QML types just behave so differently when inside a layout. From looking this way when living inside a Column:
it changes to this when sitting inside a ColumnLayout
I did get it better, eventually, by setting Layout.maximumWidth instead of width, but still the horizontal centering doesn't work:
Finally I could solve that by also setting Layout.preferredWidth, but then I returned to just take the Column approach.
Having had many problems in the past with obviously not correctly understanding how Layouts actually work in QML, I have lately started to avoid them quite generally.
Here, Column works just fine :-)