Planned maintenance has been done but it did not solve the problem. So work will continue on this and a new time for trying updates will be announced asap.

A QML type showing rows and a scroll bar



  • Hi all,

    For part of my Qt Quick project, I need to expose data (including text and numbers in Persian) in rows with four or five columns, similar to a table. Each cell must be able to have a color, font for the text and emit the clicked signal when clicked/touched. The number of rows is various, because they can be added/removed. We should be able to scroll the rows. And we also should be able to search for a specific row using the text column, for example, in a separate row right after the first (title) row.

    Is there a built-in QML type that covers the features above all? If yes, what component please? And if not, from where should I start to reach what I want?

    Thanks.




  • Moderators

    @qcoderpro
    There's a couple of ways you can do that.

    QML has a TableView, there's also a ListView. For both you can specify the delegate (the item that is drawn), both have a Scrollbar component that you can override

    You can do a flickable, columns and repeaters. And a manually created and attached ScrollBar

    There are many ways to Rome.



  • Ow thanks. Which is easier to pick out and better for that non-western language please?


  • Moderators

    @qcoderpro the text format/Languag doesn't matter either way. QString is able to display them.

    Reading more carefully through your opening post.
    I think the best option for you would be to create a c++ model do your stuff there (including the search) and expose that to qml.

    Probably best to subclass QAbstractItemModel
    take a look here for further information:
    https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html



  • @j-hilk

    Sorry, I changed my mind. A table is too and unnecessarily sophisticated for the task which can be simply done using a ListView. The delegate can be a button with some data (text and numbers etc) and when clicked it shows the thorough version of data inside a dialog box. New lists can also be added and we can scroll up/down the list and remove any list element at will. But I'm not sure I can search for a element given a text, for instance.
    If I need to use C++ as the back-end (which is more preferable) instead of a ListView, probably a suitable abstract class is QAbstractListModel Class. Do you agree up to here? If yes, where can I find an example to start the primary part of the back-end section using that class? It's complicated and I don't know how to derive it in a class. :(


  • Moderators

    @qcoderpro

    yes there are a couple of way to do this.

    Take a look here:
    https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html

    It covers all usual methods, and gives an example for them



  • @j-hilk
    Thank you.
    I wrote this and get many errors and am sure it's awkward and must be changed to be a good program for the task. So please where it's need put some changes. I'm new in this case. :)

    dataModel.h:

    #ifndef DATAMODEL_H
    #define DATAMODEL_H
    
    #include <QAbstractListModel>
    #include <QPushButton>
    
    class DataModel: public QAbstractListModel
    {
        Q_OBJECT
        Q_PROPERTY(QVector mList READ showList WRITE addList NOTIFY mListChanged)
    
    public:
        explicit DataModel(QObject* parent = nullptr);
        void addList(const QString&, const char&, const int&);
        void showLsit();
    
    private:
        QVector<QPushButton> mList;
    };
    
    #endif // DATAMODEL_H
    

    dataModel.cpp:

    #include "datamodel.h"
    
    DataModel::DataModel(QObject* parent) : QAbstractListModel(parent)
    { }
    
    void DataModel::addList(const QString &name, const char& ch, const int& n)
    {
        mList.push_back(QPushButton(name + ch + n));
        emit mListChanged();
    }
    
    void DataModel::showLsit()
    {
    
    }
    

    main.cpp:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickStyle>
    
    #include "datamodel.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        QQuickStyle::setStyle("Material");
    
        qmlRegisterType<DataModel>("Model", 1, 0, "DataModel");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

    main.qml:

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Layouts 1.12
    import QtQuick.Controls.Material 2.12
    
    import Model 1.0
    
    ApplicationWindow {
        id: appWin
        visible: true
        width: 800; height: 600
        title: qsTr("Test")
    
        Material.background: "#E0E0E0"
    
       DataModel {
         id: firstList
         addList("test1", 'd', 12);
         showList();
        }
    }
    


  • @qcoderpro

    Hello here,

    I would do it like this :

    dataToDisplay.h:

    class DataToDisplay:  public QObject
    {
        Q_OBJECT
        Q_PROPERTY(string text1ToDisplay, READ getText1ToDisplay, NOTIFY text1ToDisplayChanged)
        Q_PROPERTY(string text2ToDisplay, READ getText2ToDisplay, NOTIFY text2ToDisplayChanged)
        Q_PROPERTY(int intToDisplay, READ getIntToDisplay, NOTIFY intToDisplayChanged)
        Q_PROPERTY(real realToDisplay, READ getRealToDisplay, NOTIFY realToDisplayChanged)
    
    public:
        DataToDisplay(string text1, string text2, int myInt, int myReal);
        ~DataToDisplay();
        string getText1ToDisplay();
        string getText2ToDisplay();
        string getIntToDisplay();
        string getRealToDisplay();
    
    signals:
        void text1ToDisplayChanged();
        void text2ToDisplayChanged();
         void intToDisplayChanged();
        void realToDisplayChanged();
    
    private:
        string m_text1;
        string m_text2;
        int m_int;
        real m_real;
    }
    

    dataToDisplay.cpp:

        DataToDisplay(string text1, string text2, int myInt, int myReal) : 
        m_text1(text1), m_text2(text2), m_int(myInt), m_real(myReal)
        {
             
        }
    
        ~DataToDisplay()
        {
            
        }
    
        string getText1ToDisplay()
        {
            return m_text1;
        }
        string getText2ToDisplay();
        {
            return m_text2;
        }
        string getIntToDisplay()
        {
            return m_int;
        }
        string getRealToDisplay();
        {
            return m_real;
        }
    

    DataManager.h:

    #include "DataToDisplay.h"
    
    class DataManager:  public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QList<QObject*> mList READ showList NOTIFY mListChanged)
    
    public:
    DataManager();
    ~DataManager();
    
    QList<Object*> showList() { return m_list }
    
    signals:
    void    mListChanged();
    
    private:
        QList<QObject*> m_list;
    }
    

    main.cpp:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickStyle>
    
    #include "DataManager.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        QQuickStyle::setStyle("Material");
    
       qmlRegisterType<DataToDisplay>("Model", 1, 0, "DataToDisplay");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

    main.qml:

        ListView
        {
            //anchor or layout the listview to the size of your page
            model: Model.showList()
    
            delegate: Rectangle
            {
                width = parent.widht
                height = parent.height * 0.2
    
                RowLayout
                {
                    anchor.fill: parent
                    
                    Rectangle
                    {
                        Layout.fillHeight = true
                        Layout.preferedWidth = parent.width * 0 . 2
                        color: playWithYourColorHere
    
                        Text { anchors.centenIn: parent; Text: modelData.text1ToDisplay }
                    }
    
                    Rectangle
                    {
                        Layout.fillHeight = true
                        Layout.preferedWidth = parent.width * 0 . 2
                        color: playWithYourColorHere
    
                        Text { Layout.fillHeight = true; Layout.preferedWidth = parent.width * 0 . 2; Text: modelData.text2ToDisplay}
                    }
    
                    Rectangle
                    {
                        Layout.fillHeight = true
                        Layout.preferedWidth = parent.width * 0 . 2
                        color: playWithYourColorHere
    
                        Text { anchors.centenIn: parent; Text: modelData.intToDisplay}
                    }
    
                    Rectangle
                    {
                        Layout.fillHeight = true
                        Layout.preferedWidth = parent.width * 0 . 2
                        color: playWithYourColorHere
    
                        Text { anchors.centenIn: parent;  Text: modelData.realToDisplay}
                    }
                }
            }
        }
    

    I didn't test it just write it for you at hand directly here so I would expect some few minor error to correct here and there.
    Then you just have to play with the list of QObject into DataManager and your ListView from main.qml will adjust itself.

    For the searching part you will have to implement it outside of the ListView but still make it work withe the same list.

    And last thing if you change any value for your dataToDisplay into the cpp it will be automaticaly readjusted into the listView but if you do it inside a QML you will have to call the mListChanged signal from DataManager.

    I Think that's it.



  • @darta
    Thank you. I removed all obvious errors and code is now this way:

    // dataManager.h
    #ifndef DATAMANAGER_H
    #define DATAMANAGER_H
    
    
    #include "DataToDisplay.h"
    
    class DataManager:  public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QList<QObject*> mList READ showList NOTIFY mListChanged)
    
    public:
    DataManager();
    ~DataManager();
    
    QList<QObject*> showList() { return m_list; }
    
    signals:
    void  mListChanged();
    
    private:
        QList<QObject*> m_list;
    };
    
    #endif // DATAMANAGER_H
    
    // dataDisplay.h
    #ifndef DATATODISPLAY_H
    #define DATATODISPLAY_H
    
    #include <QObject>
    
    class DataToDisplay:  public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString text1ToDisplay READ getText1ToDisplay NOTIFY text1ToDisplayChanged)
        Q_PROPERTY(QString text2ToDisplay READ getText2ToDisplay NOTIFY text2ToDisplayChanged)
        Q_PROPERTY(int intToDisplay READ getIntToDisplay NOTIFY intToDisplayChanged)
        Q_PROPERTY(double realToDisplay READ getRealToDisplay NOTIFY realToDisplayChanged)
    
    public:
        DataToDisplay(QString, QString, int, double);
        ~DataToDisplay();
        QString getText1ToDisplay();
        QString getText2ToDisplay();
        int getIntToDisplay();
        double getRealToDisplay();
    
    signals:
        void text1ToDisplayChanged();
        void text2ToDisplayChanged();
        void intToDisplayChanged();
        void realToDisplayChanged();
    
    private:
        QString m_text1;
        QString m_text2;
        int m_int;
        double m_real;
    };
    
    #endif // DATATODISPLAY_H
    
    // dataToDisplay.cpp
    #include "dataToDisplay.h"
    
    DataToDisplay::DataToDisplay(QString text1, QString text2, int myInt, double myReal) :
        m_text1(text1), m_text2(text2), m_int(myInt), m_real(myReal)
    {  }
    
    DataToDisplay::~DataToDisplay() { }
    
    QString DataToDisplay::getText1ToDisplay()
    {
        return m_text1;
    }
    
    QString DataToDisplay::getText2ToDisplay()
    {
        return m_text2;
    }
    
    int DataToDisplay::getIntToDisplay()
    {
        return m_int;
    }
    
    double DataToDisplay::getRealToDisplay()
    {
        return m_real;
    }
    
    // main.cpp 
    
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickStyle>
    
    #include "DataManager.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        QQuickStyle::setStyle("Material");
    
       qmlRegisterType<DataToDisplay>("Model", 1, 0, "DataToDisplay");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    
    // main.qml
    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Layouts 1.12
    import QtQuick.Controls.Material 2.12
    
    import Model 1.0
    
    ApplicationWindow {
        id: appWin
        visible: true
        width: 800; height: 600
        title: qsTr("Accounts Test")
    
        Material.background: "#E0E0E0"
    
     ListView
        {
            //anchor or layout the listview to the size of your page
            model: Model.showList()
    
            delegate: Rectangle
            {
                width: parent.widht
                height: parent.height * 0.2
    
                RowLayout
                {
                    anchors.fill: parent
    
                    Rectangle {
                        Layout.fillHeight: true
                        Layout.preferedWidth: parent.width * 0.2
                        color: "lightBlue"
    
                        Text { anchors.centerIn: parent; Text: modelData.text1ToDisplay }
                    }
    
                    Rectangle {
                        Layout.fillHeight: true
                        Layout.preferedWidth: parent.width * 0.2
                        color: "lightBlue"
    
                        Text { Layout.fillHeight: true;
                            Layout.preferedWidth: parent.width * 0.2;
                            Text: modelData.text2ToDisplay
                        }
                    }
    
                    Rectangle {
                        Layout.fillHeight: true
                        Layout.preferedWidth: parent.width * 0.2
                        color: playWithYourColorHere
    
                        Text { anchors.centerIn: parent; Text: modelData.intToDisplay }
                    }
    
                    Rectangle {
                        Layout.fillHeight: true
                        Layout.preferedWidth: parent.width * 0.2
                        color: "lightBlue"
    
                        Text { anchors.centerIn: parent;  Text: modelData.realToDisplay}
                    }
                }
            }
        }
    }
    

    But still there are two errors:
    ...mingw73_64\include\QtQml\qqmlprivate.h:119: error: use of deleted function 'QQmlPrivate::QQmlElement<DataToDisplay>::QQmlElement()'
    void createInto(void memory) { new (memory) QQmlElement<T>; }

    ...mingw73_64\include\QtQml\qqmlprivate.h:98: error: no matching function for call to 'DataToDisplay::DataToDisplay()'

    And where is the implementation of "dataManager.h" please?



  • I Forget that the C++ function that you will use from qml has to be in "public slots"

    into cpp files function should be notified DataToDisplay::DataToDisplay() for example

    And to implement your DataManager you can do it into the main.cpp
    and you will need function to implement your list of DataToDisplay


Log in to reply