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?

Better way to elide multiline text?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
12 Posts 3 Posters 4.5k 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