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. ComboBox together with QStringListModel
QtWS25 Last Chance

ComboBox together with QStringListModel

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qml c++qml combobox
4 Posts 2 Posters 2.4k 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.
  • K Offline
    K Offline
    koahnig
    wrote on 18 Nov 2020, 11:00 last edited by
    #1

    Struggeling while trying to an editable ComboBox for QML. See also https://forum.qt.io/topic/120952/using-editable-combobox

    The purpose is described in the other post.

    I came across QStringListModel which seem to fulfill my purposes also in view of being able to store and set the actual entries in combination with QSettings. Also I am more comfortable with Qt for C++

    However, the combination is not as easy to implement as initially thought.

    I have used a Qt Quick template to create a minimal application.

    The .pro file from template

    QT += quick
    
    CONFIG += c++11
    
    # You can make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
            main.cpp
    
    RESOURCES += qml.qrc
    
    # Additional import path used to resolve QML modules in Qt Creator's code model
    QML_IMPORT_PATH =
    
    # Additional import path used to resolve QML modules just for Qt Quick Designer
    QML_DESIGNER_IMPORT_PATH =
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    

    The main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include <QStringListModel>
    
    #include <QDebug>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        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);
    
        qmlRegisterType <QStringListModel> ( "StringListModel", 1, 0, "QStringListModel" );
        QStringListModel lstModel;
        lstModel.setStringList( QStringList() << "Test1" << "Test2");
    
        qDebug() << lstModel.stringList();
    
        engine.rootContext()->setContextProperty ("myLstModel", &lstModel );
    
        engine.load(url);
    
        return app.exec();
    }
    

    The main.qml

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import StringListModel 1.0
    
    ApplicationWindow {
        width: 640
        height: 480
        visible: true
        title: qsTr("Scroll")
    
        ComboBox {
            id: firstComboBox
            model: StringListModel
        }
        ComboBox {
            id: secondComboBox
            anchors.top: firstComboBox.bottom
            model: myLstModel
        }
        ComboBox {
            id: thirdComboBox
            anchors.top: secondComboBox.bottom
            model: myLstModel.stringList
        }
    }
    

    There already some remains of my struggle to get the initial entries from QStringListModel into the ComboBox in QML. None of these attempts worked. The ComboBox in the middle has at least the right number of entries, but they are all empty.

    Has anyone an idea what I am missing?

    Vote the answer(s) that helped you to solve your issue(s)

    1 Reply Last reply
    0
    • B Offline
      B Offline
      Bob64
      wrote on 19 Nov 2020, 15:58 last edited by Bob64
      #2

      @koahnig The middle approach is as you say closest to working.

      If you wanted to use your first approach, based on StringListModel as exposure of QStringListModel to QML, you would have to instantiate it somewhere. You are assigning the type StringListModel to your model property rather than an instance of it.

      However, assuming you go for the context property approach I think you are at least missing setting the textRole in secondComboBox. Try setting:

         ...
         model: myLstModel
         textRole: "display"
      }
      
      K 1 Reply Last reply 19 Nov 2020, 17:40
      1
      • B Bob64
        19 Nov 2020, 15:58

        @koahnig The middle approach is as you say closest to working.

        If you wanted to use your first approach, based on StringListModel as exposure of QStringListModel to QML, you would have to instantiate it somewhere. You are assigning the type StringListModel to your model property rather than an instance of it.

        However, assuming you go for the context property approach I think you are at least missing setting the textRole in secondComboBox. Try setting:

           ...
           model: myLstModel
           textRole: "display"
        }
        
        K Offline
        K Offline
        koahnig
        wrote on 19 Nov 2020, 17:40 last edited by
        #3

        @Bob64 said in ComboBox together with QStringListModel:

        @koahnig The middle approach is as you say closest to working.

           ...
           model: myLstModel
           textRole: "display"
        }
        

        This helps getting closer. Adding textRole displays all entries in the ComboBox.

        Vote the answer(s) that helped you to solve your issue(s)

        1 Reply Last reply
        0
        • K Offline
          K Offline
          koahnig
          wrote on 20 Nov 2020, 17:18 last edited by
          #4

          The only solution I found is with inheriting from QStringListModel.

          main.cpp

          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          #include <QQmlContext>
          #include <QSettings>
          
          #include "MyStringListModel.h"
          
          #include <QDebug>
          
          int main(int argc, char *argv[])
          {
              QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
          
              QGuiApplication app(argc, argv);
          
              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);
          
              qmlRegisterType <MyStringListModel> ( "StringListModel", 1, 0, "MyStringListModel" );
              MyStringListModel lstModel;
              QSettings settings ( "TestQml.ini", QSettings::IniFormat );
              lstModel.readSettings(&settings, "Components");
          
              if ( lstModel.stringList().size() < 1 )
              {
                  lstModel.setStringList( QStringList() << "Test 1" << "Test 2");
                  lstModel.setCurrentIndex(0);
              }
          
              qDebug() << lstModel.stringList();
          
              engine.rootContext()->setContextProperty ("myLstModel", &lstModel );
          
              engine.load(url);
          
              return app.exec();
          }
          

          MyStringListModel.h

          #ifndef MYSTRINGLISTMODEL_H
          #define MYSTRINGLISTMODEL_H
          
          #include <QObject>
          #include <QStringListModel>
          class QSettings;
          
          class MyStringListModel : public QStringListModel
          {
              Q_OBJECT
          
              Q_PROPERTY (int CurrentIndex READ getCurrentIndex WRITE setCurrentIndex NOTIFY sigCurrentIndex )
          
              int CurrentIndex;
          
          public:
              MyStringListModel();
          
              int getCurrentIndex () const;
              void setCurrentIndex ( int indx );
          
              void readSettings ( QSettings *settings, const QString & category );
              void writeSettings ( QSettings *settings, const QString & category ) const;
          
          public slots:
              void addNewText ( QString editText );
              void sltEditText ( QString editText );
          
          signals:
              void sigCurrentIndex();
          
          };
          
          #endif // MYSTRINGLISTMODEL_H
          

          MyStringListModel.cpp

          #include "MyStringListModel.h"
          
          #include <QSettings>
          
          MyStringListModel::MyStringListModel()
              : CurrentIndex ( 0 )
          {
          
          }
          
          int MyStringListModel::getCurrentIndex() const
          {
              return CurrentIndex;
          }
          
          void MyStringListModel::setCurrentIndex(int indx)
          {
              CurrentIndex = indx;
          }
          
          void MyStringListModel::addNewText(QString editText)
          {
              const QStringList &lst = stringList();
              for ( int i = 0; i < lst.size(); ++i )
              {
                  if ( editText == lst[i] )
                      return;
              }
              setStringList ( stringList() << editText );
              setCurrentIndex ( rowCount() - 1 );
          }
          
          void MyStringListModel::readSettings(QSettings *settings, const QString &category)
          {
              settings->beginGroup(category);
              QStringList lst = settings->value("Entries", QStringList()).toStringList();
              setStringList ( lst );
              int currentIndex = settings->value("CurrentPosition", 0 ).toInt();
              setCurrentIndex(currentIndex);
              settings->endGroup();
          }
          
          void MyStringListModel::writeSettings(QSettings *settings, const QString &category) const
          {
              settings->beginGroup(category);
              settings->setValue("Entries", stringList());
              settings->setValue("CurrentPosition", CurrentIndex );
              settings->endGroup();
          }
          
          void MyStringListModel::sltEditText(QString editText)
          {
              addNewText ( editText );
              QSettings settings ( "TestQml.ini", QSettings::IniFormat );
              writeSettings(&settings, "Components");
          }
          

          main.qml

          import QtQuick 2.15
          import QtQuick.Controls 2.15
          import StringListModel 1.0
          
          ApplicationWindow {
              width: 640
              height: 480
              visible: true
              title: qsTr("Scroll")
          
              Frame {
                  ComboBox {
                      id: secondComboBox
                      editable: true
                      model: myLstModel
                      currentIndex: model.CurrentIndex
                      textRole: "display"
                      onAccepted: {
                          if (find(editText) === -1)
                              model.addNewText ( editText )
                      }
                  }
              }
          }
          

          Vote the answer(s) that helped you to solve your issue(s)

          1 Reply Last reply
          0

          2/4

          19 Nov 2020, 15:58

          • Login

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