Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Better way to elide multiline text?
Forum Updated to NodeBB v4.3 + New Features

Better way to elide multiline text?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
12 Posts 3 Posters 3.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SeDiS Offline
    SeDiS Offline
    SeDi
    wrote on last edited by
    #1

    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
                                }
                            }
                        }
                    }
    
    DiracsbracketD 1 Reply Last reply
    0
    • SeDiS SeDi

      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
                                  }
                              }
                          }
                      }
      
      DiracsbracketD Offline
      DiracsbracketD Offline
      Diracsbracket
      wrote on last edited by Diracsbracket
      #2

      @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

      SeDiS 1 Reply Last reply
      1
      • DiracsbracketD Diracsbracket

        @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

        SeDiS Offline
        SeDiS Offline
        SeDi
        wrote on last edited by
        #3

        Thank you, @Diracsbracket, you are absolutely right, that's a much more elegant way! I'll have a look into that!

        1 Reply Last reply
        0
        • SeDiS Offline
          SeDiS Offline
          SeDi
          wrote on last edited by
          #4

          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.

          DiracsbracketD 1 Reply Last reply
          0
          • SeDiS SeDi

            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.

            DiracsbracketD Offline
            DiracsbracketD Offline
            Diracsbracket
            wrote on last edited by
            #5

            @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.

            1 Reply Last reply
            1
            • SeDiS Offline
              SeDiS Offline
              SeDi
              wrote on last edited by SeDi
              #6

              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?

              DiracsbracketD 1 Reply Last reply
              1
              • SeDiS SeDi

                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?

                DiracsbracketD Offline
                DiracsbracketD Offline
                Diracsbracket
                wrote on last edited by Diracsbracket
                #7
                This post is deleted!
                1 Reply Last reply
                0
                • GrecKoG Offline
                  GrecKoG Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on last edited by
                  #8

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

                  SeDiS 1 Reply Last reply
                  3
                  • GrecKoG GrecKo

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

                    SeDiS Offline
                    SeDiS Offline
                    SeDi
                    wrote on last edited by
                    #9

                    @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 
                                            }
                                        }
                                    }
                    
                    1 Reply Last reply
                    1
                    • GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on last edited by
                      #10

                      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.

                      SeDiS 1 Reply Last reply
                      1
                      • GrecKoG GrecKo

                        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.

                        SeDiS Offline
                        SeDiS Offline
                        SeDi
                        wrote on last edited by
                        #11
                        This post is deleted!
                        1 Reply Last reply
                        0
                        • SeDiS Offline
                          SeDiS Offline
                          SeDi
                          wrote on last edited by SeDi
                          #12

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

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved