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

QML: Horizontal ScrollBar on ListView



  • I want to display a ListView containing strings (e.g. using Labels) that are usually of a reasonable length but can occasionally be longer than the maximum width I want to make the ListView. When this happens, the text is clipped to the right and the user has no way to see the missing characters.

    A horizontal scrollbar seems like the obvious solution here but I cannot get it to work. I have tried attaching a horizontal scrollbar to ListView, I have tried wrapping ListView in a ScrollView, setting all sorts of combinations of widths, implicit widths, content widths ...

    Is it possible to use a horizontal scrollbar for the situation I have described?

    Let's say we start with something like this:

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        function getItems() {
            var items = [];
            for (var i = 0; i !== 20; ++i) {
                items[i] = "This string is too long to fit in my ListView!";
            }
            return items;
        }
    
        Rectangle {
            anchors.centerIn: parent
            height: 200
            width: 100
            border.color: "black"
    
            ListView {
                anchors.fill: parent
                model: getItems()
                clip: true
    
                delegate: Label {
                    text: modelData
                }
            }
        }
    }
    
    

  • Qt Champions 2017

    ScrollBar may not be right option. Use elide feature for the labels in the delegate. Use tooltip feature/scrolling text feature when particular delegate is selected.



  • @dheerendra Thanks. Can you please explain what you mean about "scrolling text feature"?


  • Qt Champions 2017

    @Bob64

    Scrolling Text - Adding animation to move the text from left to right.



  • @dheerendra is there a straighforward way to control the positioning of long text within a shorter label? I suppose I could take substrings but is there a better way?



  • I will attempt to launch and tweak your QML code later today (presuming i get a moment). I'm curious why a horizontal bar would not work (although the gymnastics might not be worth it in the end).

    Just to put forth more options:

    fontSizeMode: Text.Fit
    

    https://doc.qt.io/qt-5/qml-qtquick-text.html#fontSizeMode-prop

    In addition to the elision options, I have (on occasion) used fontSizeMode: Text.Fit, which will shrink the text only when necessary to make it fit. However, this will result in the sometimes jarring visual discrepancy of the short strings being in a larger font, and the long strings being in a smaller font.



  • Here is a "partial solution" that gives you scrollability (but not a visible scrollbar) by adding two lines of code inside your ListView.

    I am testing all this with Qt 5.15.0 on Linux.

    The key thing to realize up front is that ListView "is a" Flickable (which is similar to a ScrollView).

    Therefore the ListView supports properties such as flickableDirection which are inherited from Flickable. (Go to https://doc.qt.io/qt-5/qml-qtquick-listview.html and search "Inherits".)

    To make the whole ListView "scrollable" (aka "flickable"), you can add the lines shown below.

    On a touch screen, you will then be able to swipe/drag to "scroll" the content horizontally. On a desktop computer (without a touchscreen), you can click-and-drag the content.

    IMPORTANT:

    • For HorizontalFlick, the content will not scroll/flick unless you ensure that contentWidth is wider than what fits in the ListView's actual width.
    • For VerticalFlick, the content will not scroll/flick unless you ensure that contentHeight is taller than what fits in the ListView's actual height.
        ListView {
          anchors.fill: parent
          model: getItems()
          clip: true
    
          contentWidth: 500  // 1 of 2 newly inserted lines of code
          flickableDirection: Flickable.HorizontalFlick // 2 of 2 newly inserted lines of code
    
          delegate: Label {
            text: modelData
          }
        }
    

    You can see that in the interest of time and simplicity, I hardcoded contentWidth: 500 in the above sample code. It would be nicer to compute the necessary width for the longest piece of text instead of hardcoding 500, but that is a separate exercise in QML computation.



  • @KH-219Design Thank you very much for this. It's certainly another option to consider.

    BTW regarding the contentWidth I am already doing work in my real application to attempt to calculate the longest label length. I am using TextMetrics but it has to be said that I am getting rather unreliable values from it. But that might be another question...


Log in to reply