Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.



  • @SeDi
    Can't you derive your class from QLabel as in the example? I wouldn't know how to reimplement the paintEvent using the private QQuickText class.



  • 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!

  • Qt Champions 2018

    Why don't you use a Text item for each line and wrap them in a Column ?



  • @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 
                            }
                        }
                    }
    

  • Qt Champions 2018

    If you are using height: parent.height / textRepeater.count, you might want to use ColumnLayout instead of Column, it will handle the height of its children automatically.



  • This post is deleted!


  • 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:
    0_1535146429339_löschen2.png

    it changes to this when sitting inside a ColumnLayout
    0_1535146439920_löschen.png

    I did get it better, eventually, by setting Layout.maximumWidth instead of width, but still the horizontal centering doesn't work:
    0_1535146449909_löschen3.png

    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 :-)


Log in to reply