1

I have class with QSqlDatabase and with pointer to QSqlTableModel in one class. I use pointer to QSqlTableModel, because initialization of database is going on in constructor and after that I create QSqlTableModel using this database (also in constructor but in heap already).
This class is registered type in qml and so I create it in QML. How is it better to point out TableView to the QSqlTableModel pointer of this class? If it is possible.

alr
  • 1,332
  • 3
  • 13
  • 23

1 Answers1

3

It is not entirely clear what you're asking. I'm going to assume you want to share a pointer to your model with QML.

  1. Have a Q_PROPERTY for it. All Q_PROPERTYs are automatically visible to QML.

    • When returning QSqlTableModel* you need to register that type, too. E.g.

      qmlRegisterUncreatableType<QSqlTableModel>(
          "NameOfModuleInQML", 1, 0, "QSqlTableModel",
          "Cannot instanciate QSqlTableModel from QML");
      
    • Note that you cannot do this then:

      property QSqlTableModel mytabmodel
      

      do this instead if you need to:

      property QtObject mytabmodel
      
  2. Return it from a method of a class registered with QML (note that you must return QObject*). This is very likely what you want. E.g.

     class SomeClass : public QObject {
          // ...
     public:
         Q_INVOKABLE QObject *model() {
              return tableModel;
         }
         // ...
     };
    

    Then you can do this in QML:

    TableView {
        model: instanceOfYourclass.model()
        // other bindings
    
        TableViewColumn {
            title: qsTr("Name")
            role: "Name"
            width: 150
        }
    
        // and so on
    }
    
  3. You can create a singleton

    QObject *tableModelProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
        (void)engine;
        (void)scriptEngine;
    
        return new QSqlTableModel(...);
    }
    
    qmlRegisterSingletonType<QSqlTableModel>("NameOfModule", 1, 0, "NameInQML", tableModelProvider);
    

    This is a suitable approach if there is and ever will be only one instance of your model and if you don't need much to initialize it.

  4. Set your model as a context property

     QQmlEngine engine;
    
     // ..
     engine.rootContext()->setContextProperty("nameInQml", yourTableModelInstance);
    
dom0
  • 7,356
  • 3
  • 28
  • 50
  • If I use the first case you wrote (but without creating property QtObject in QML) I get the run-time error: "QMetaProperty::read: Unable to handle unregistered datatype 'QSqlTableModel' for property 'MyClass::tableModel'". If I use this with creating of property as you wrote I get "Unable to assign [undefined] to QObject*" error. The second method with Q_INVOKABLE works without errors but I cannot see data in TableView (I'll try to investigate it more deeply). – alr Oct 12 '14 at 14:14
  • The model is declared in class as a "QSqlTableModel *m_tableModel". I am not sure, is it actually right to return pointer to model to QML instead of object? – alr Oct 12 '14 at 14:36
  • When using option 1) and returning QSql... you *need* to register the type as pointed out above. Data being invisible is likely an issue of role names, check what's the output of `qDebug() << yourmodel->roleNames();` (include `` for this) is. – dom0 Oct 12 '14 at 17:06
  • You likely need to set up the model before passing it the first time to a QML view, I guess. – dom0 Oct 12 '14 at 17:06
  • Okay, it seems QSqlTableModel does not export role names (sadly). See http://qt-project.org/wiki/How_to_use_a_QSqlQueryModel_in_QML – dom0 Oct 12 '14 at 17:10
  • That is: you need to subclass QSqlTableModel and re-implement roleNames, returning a mapping column <-> role name. Then you use those role names in the TableViewColumn to access the data. – dom0 Oct 12 '14 at 17:12
  • Found example here (http://qt-project.org/forums/viewthread/41793), it works, but cells not editable and not updating when I insert something new. Anyway, the second proposed approach covers the question. – alr Oct 13 '14 at 13:15
  • @dom0 very detailed answer thank you. For (2) I'd like to point out that the returned pointer must explicitly be `QObject*`. If it is `QSqlTableModel*`, the behavior gets weird: Sometimes it is properly recognized by the qml engine and sometimes not (resulting in the pointer being `undefined`). – Ayberk Özgür Jun 27 '16 at 09:16
  • @AyberkÖzgür in C++ , returning an object of base type (`QObject`) is not recommended for derived class objects (`QSqlTableModel`) .. isn't that UB ? while it works for pointer objects only .. it could eventually also be UB .. dont know! – Mohammad Kanan Jun 22 '19 at 18:11