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. QML TextArea performance with large data buffers
Forum Updated to NodeBB v4.3 + New Features

QML TextArea performance with large data buffers

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
6 Posts 3 Posters 716 Views 2 Watching
  • 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.
  • P Offline
    P Offline
    preiter
    wrote on last edited by
    #1

    I'm using Qt 6.6 with QML and a C++ backend.

    I have a TextArea in a Flickable. The text is bound to a string in my C++ backend. I'm finding that it's slow to update when the text buffer is large and the backend signals that the text has changed.

    It's taking 5s to redraw the TextArea when I have a 9MB buffer with about 21000 lines of text in it.

    I find that this time changes linearly with the size of the text buffer.

    In this blog post: https://www.qt.io/blog/text-editing-improvements-in-qt-quick
    it says that TextEdit has been updated to only render the text that's in the viewport. It seems like if that were the case, the render time would not be increasing linearly with the buffer size.

    Note: the blog post references TextEdit, not TextArea. I've tried both and found no difference in performance.

    Is there any way to check whether I'm getting that behavior?
    Any other advice for improving performance?

        Flickable {
            id: flickable
    
            property var textCursorPosition: 0
            property var yBuffer: 10
    
            anchors.fill: dataViewerTextContainer
            boundsMovement: Flickable.StopAtBounds
            clip: true
            focus: true
    
            ScrollBar.horizontal: ScrollBar {
                anchors.right: parent.right
                anchors.rightMargin: 15 // prevent scrollbars from overlapping
                policy: flickable.contentWidth > flickable.width ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
            }
            ScrollBar.vertical: ScrollBar {
                anchors.bottom: parent.bottom
                anchors.bottomMargin: 15 // prevent scrollbars from overlapping
                policy: flickable.contentHeight > flickable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
            }
            TextArea.flickable: TextArea {
                id: dataViewerText
    
                function positionViewAtBeginning() {
                    dataViewerText.cursorPosition = 0;
                }
                function positionViewAtEnd() {
                    dataViewerText.cursorPosition = dataViewerText.length - 1;
                }
                function updateCursorPosition() {
                    var bottomVisibleArea = flickable.visibleArea.yPosition + flickable.height - flickable.yBuffer;
                    var positionInRoot = flickable.mapToItem(dataViewerText, 0, bottomVisibleArea);
                    flickable.textCursorPosition = dataViewerText.positionAt(positionInRoot.x, positionInRoot.y);
                }
    
                font.family: "Courier New"
                font.pixelSize: root.themes.dataFontSize
                padding: 4
                readOnly: true
    
                onTextChanged: {
                    if (holdScroll.position === 0)
                        dataViewerText.positionViewAtEnd();
                    else
                        dataViewerText.cursorPosition = flickable.textCursorPosition;
                }
                Connections {
                    target: dataViewerTab
                    onDataViewerTextChanged: {
                        // This is here so that multiple calls to updateDataViewerText() 
                        // don't bog down the UI thread
                        console.log("DataViewerText changed");
                        var startTime = new Date().getTime()
                        Qt.callLater(function() {
                            console.log("Updating DataViewerText");
                            dataViewerText.text = dataViewerTab.dataViewerText;
                        });
                        Qt.callLater(function() {
                            console.log("dataviewer text update completed in: " + (new Date().getTime() - startTime) + "ms");
                        });
                    }
                }
            }
    
    1 Reply Last reply
    0
    • B Offline
      B Offline
      Bob64
      wrote on last edited by Bob64
      #2

      Unfortunately I cannot answer your question as I still use Qt 5, but this is an interesting topic for me as I had seen the post about improvements and it was something I was hoping to be able to take advantage of when we upgrade to Qt 6.

      In my application, I also need to display a large text buffer that is being continuously updated. It is showing a log that is written by a process launched by the application. This sometimes runs for a long time and the log can get very large.

      Like you, what I found when using TextArea was that, beyond a certain point, updates became intolerable and the application ground to a halt. From what I remember when I debugged it, the bottleneck was caused by an internal recalculation of the layout of the entire text buffer and this began to dominate once the buffer became large.

      In the end, the only way I found to have a log view in my application was to use a ListView with a model that consisted of the lines of text from the log. This has the advantage that ListView naturally only worries about the relatively small viewport that it is currently displaying. The downside is that I had to implement all of the multiline selection behaviour myself, which was relatively hard work and some aspects of the behaviour aren't quite right compared with a genuine text area component.

      1 Reply Last reply
      0
      • P Offline
        P Offline
        preiter
        wrote on last edited by
        #3

        Unfortunately, my users expect to be able to copy/paste freeform chunks of text out of my display and the behavior of that would be very strange if I converted to a ListView.

        1 Reply Last reply
        0
        • B Offline
          B Offline
          Bob64
          wrote on last edited by
          #4

          It is possible to do this - it's just that you have to code a lot of the selection logic yourself. I store selection information in my model, so that each item in the model comprises a "text" role as well as roles to capture "selected information" for that line. In the ListView delegate, where I use a read-only TextInput, I use the information to set selected the appropriate parts of each line. You then have all the mouse logic to identify an active selection, possibly spanning multiple lines, and update the model.

          In my case, I only implemented single selection - you can only select one block of text at a time - but in principle it could be extended to multi-selection.

          1 Reply Last reply
          0
          • A Offline
            A Offline
            afalsa
            wrote on last edited by
            #5

            Hello!

            Maybe you have already read this.

            • Handling a Lot of Text in QML
            • https://www.youtube.com/watch?v=37eAuM1Aqzc&ab_channel=KDAB
            B 1 Reply Last reply
            0
            • A afalsa

              Hello!

              Maybe you have already read this.

              • Handling a Lot of Text in QML
              • https://www.youtube.com/watch?v=37eAuM1Aqzc&ab_channel=KDAB
              B Offline
              B Offline
              Bob64
              wrote on last edited by
              #6

              @afalsa thanks for those links. I have only looked at the first one and skim read it, but it seems like they ended up with a very similar solution to mine. That is reassuring in the sense that there doesn't seem to be a much simpler approach that I missed. I don't recall finding that page when I had the issue, but I suspect I was grappling with it a year or two before that was written.

              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