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.

DelegateChooser creates delegates in other context



  • Hi,
    I'm using model created and populated in C++. I'm using 3 additional roles (names provided in roleNames())

    import QtQuick 2.0
    import QtQuick.Controls 1.4
    import Qt.labs.qmlmodels 1.0
    
    TableView {
    	id: propertiesTableView
    	anchors.fill : parent
    	TableViewColumn{
    		title: "Name"
    		role: "display"
    		movable: false
    	}
    	TableViewColumn{
    		title: "Value"
    		role: "propertyValue"
    		movable: false
    		delegate: DelegateChooser {
    			role: "propertyType"
    			DelegateChoice { 
    				roleValue: "1"
    				delegate: Rectangle {
    					CheckBox {
    						checked: styleData.value
    					}
    				}
    			}
    		}
    	}
    	Component {
    		id: boolDelegate
    		CheckBox {
    			checked: styleData.value
    		}
    	}
    }
    

    When I run this code - I'm spammed with QQmlComponent: Must create component in context from the same QQmlEngine warning.
    Where's the problem? How to solve it?

    PS: I've debug a little and problem is with instantiation of DelegateChooser.
    *void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlContext forContext)
    and inside QQuickLoaderPrivate::_q_sourceLoaded
    creationContext()/itemContext() from stored/incubated component has engine property set inside, but component doesn't.



  • Minimal reproducing project
    main.cpp

    #include <QtQml/QQmlContext>
    #include <table_model.h>
    
    #include <QApplication>
    
    int main(int argc, char *argv[]) {
      QApplication a(argc, argv);
      TableModel model;
    
      QQmlApplicationEngine engine;
      engine.rootContext()->setContextProperty("externalModel", &model);
    
      engine.load(QUrl(QLatin1String("qrc:/main.qml")));
      QList<QObject *> rootObjects = engine.rootObjects();
      if (rootObjects.size() == 0)
        return -1;
      model.populateWithTestData(); 
      return a.exec();
    }
    

    table_model.h

    #ifndef TABLE_MODEL_H
    #define TABLE_MODEL_H
    
    #include <QStandardItemModel>
    #include <memory>
    
    enum TableModelTypes {
      kFloatValue = 1,
      kIntValue = 2,
      kBoolValue = 3,
      kColorValue = 4,
      kVector2Value = 5,
      kVector3Value = 6,
      kStringValue = 7,
      kResourceValue = 8,
      VALUE_NOT_SET = 0,
    };
    
    enum TableModelRoles {
      PropertyType = Qt::UserRole,
      PropertyValue = Qt::UserRole + 1,
    };
    
    class TableModel : public QStandardItemModel {
      Q_OBJECT
    public:
      TableModel() {
        QHash<int, QByteArray> roleNames = QStandardItemModel::roleNames();
        roleNames[Qt::DisplayRole] = "display";
        roleNames[TableModelRoles::PropertyType] = "propertyType";
        roleNames[TableModelRoles::PropertyValue] = "propertyValue";
        setItemRoleNames(roleNames);
      }
    
      ~TableModel() = default;
    
      Qt::ItemFlags flags(const QModelIndex &index) const override {
        if (index.isValid()) {
          if (index.column() == 0)
            return Qt::ItemIsEnabled;
        }
        return QStandardItemModel::flags(index);
      }
    
      QVariant data(const QModelIndex &index, int role) const {
        if (!index.isValid())
          return QVariant();
    
        switch (role) {
        case TableModelRoles::PropertyValue: {
          return QStandardItemModel::data(createIndex(index.row(), 1, index.internalId()));
        }
        }
    
        return QStandardItemModel::data(index, role);
      }
    
      void populateWithTestData() {
        auto row = 0;
        setRowCount(9);
        setColumnCount(2);
        addModelRow(row++, "Actual Width", 1232, TableModelTypes::kFloatValue);
        addModelRow(row++, "Actual Height", 1032, TableModelTypes::kFloatValue);
        addModelRow(row++, "Visible", true, TableModelTypes::kBoolValue);
        addModelRow(row++, "Enable Click", false, TableModelTypes::kBoolValue);
        addModelRow(row++, "Enabled", false, TableModelTypes::kBoolValue);
        addModelRow(row++, "Horizontal Alignment", 1, TableModelTypes::kIntValue);
        addModelRow(row++, "Vertical Alignment", 2, TableModelTypes::kIntValue);
        addModelRow(row++, "Locale", "", TableModelTypes::kStringValue);
        addModelRow(row++, "Name", "Node from Outer Space", TableModelTypes::kStringValue);
        emit modelAcquired(this);
      }
    signals:
      void modelAcquired(QAbstractItemModel *_model);
    
    protected:
      void addModelRow(int row, QString name, QVariant value, TableModelTypes type) {
        QModelIndex nameIndex = index(row, 0);
        QModelIndex valueIndex = index(row, 1);
        setData(nameIndex, name);
        setData(valueIndex, value);
        setData(nameIndex, type, TableModelRoles::PropertyType);
      }
    };
    
    #endif  // TABLE_MODEL_H
    

    main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 1.4
    import Qt.labs.qmlmodels 1.0
    
    Window {
    	visible: true
    	width: 600
    	height: 500
    
    	TableView {	
    		id: propertiesTableView
    		anchors.fill : parent
    		
    		TableViewColumn{
    			title: "Name"
    			role: "display"
    			movable: false
    		}
    		TableViewColumn{ title: "Type nr"; role: "propertyType";  movable: false; }
    	
    		DelegateChooser {
    			id: propertyValueDelegate
    			role: "propertyType"
    			DelegateChoice { 
    				roleValue: 3
    				delegate: Rectangle {
    					CheckBox {
    						checked: styleData.value
    					}
    				}
    			}
    			DelegateChoice {
    				delegate: Rectangle {
    					color: "blue"
    					Text {
    						text: "Default delegate"
    					}
    				}
    			}
    		}
    		
    		TableViewColumn{
    			title: "Value"
    			role: "propertyValue"
    			movable: false
    			delegate: propertyValueDelegate
    		}
    		
    		Connections {
    			target: externalModel
    			onModelAcquired : {
    				console.log("Setting model ("+_model.columnCount()+","+_model.rowCount()+")" )
    				propertiesTableView.model = _model
    				console.log("Setting model completed" )
    			}
    		}
    	
    	}
    
    	onClosing: {
    		console.log("Closing QML window ");
    		Qt.quit();
    	}
    }
    

  • Moderators

    @SebastianM
    Hi
    I haben’s used Tableview jet, so correct me if I am wrong
    But in the minimal example you do Not expose your model to the qml engine nor do you assign any model inside the qml file, I don‘t think this can work



  • Model is created:

      TableModel model;
    
      QQmlApplicationEngine engine;
      engine.rootContext()->setContextProperty("externalModel", &model);
    

    and attached to TableView

    		Connections {
    			target: externalModel
    			onModelAcquired : {
    				console.log("Setting model ("+_model.columnCount()+","+_model.rowCount()+")" )
    				propertiesTableView.model = _model
    				console.log("Setting model completed" )
    			}
    		}
    

    I've got logs like

    qml: Setting model (2,9)
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    QQmlComponent: Must create component in context from the same QQmlEngine
    qml: Setting model completed
    

    which shows that custom model change signal is received by TableView and assigned.

    However, I just made test with this ListModel assigned statically inside main.qml. The same set of warnings about incorrect context.
    So it's not a model problem.

    	ListModel {
    		id: listModel_1
    		ListElement { name: "Actual Width"; propertyValue: 1232; propertyType: 1; }
    		ListElement { name: "Actual Height"; propertyValue: 1032; propertyType: 1; }
    		ListElement { name: "Visible"; propertyValue: 1; propertyType: 3; }
    		ListElement { name: "Enable click"; propertyValue: 0; propertyType: 3; }
    		ListElement { name: "Enabled"; propertyValue: 0; propertyType: 3; }
    		ListElement { name: "Horizontal Alignment"; propertyValue: 1; propertyType: 2; }
    		ListElement { name: "Vertical Alignment"; propertyValue: 2; propertyType: 2; }
    		ListElement { name: "Locale"; propertyValue: 1; propertyType: 7; }
    		ListElement { name: "Name"; propertyValue: 12; propertyType: 7; }
    	}
    


  • Even simplier - all in one QML. No selection for delegate - always and for everything display one delegate.

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 1.4
    import Qt.labs.qmlmodels 1.0
    
    Rectangle {
    	visible: true
    	width: 600
    	height: 500
    	ListModel {
    		id: listModel_1
    		ListElement { display: "Actual Width"; propertyValue: 1232; propertyType: 1; }
    		ListElement { display: "Actual Height"; propertyValue: 1032; propertyType: 1; }
    		ListElement { display: "Visible"; propertyValue: 1; propertyType: 3; }
    		ListElement { display: "Enable click"; propertyValue: 0; propertyType: 3; }
    		ListElement { display: "Enabled"; propertyValue: 0; propertyType: 3; }
    		ListElement { display: "Horizontal Alignment"; propertyValue: 1; propertyType: 2; }
    		ListElement { display: "Vertical Alignment"; propertyValue: 2; propertyType: 2; }
    		ListElement { display: "Locale"; propertyValue: 1; propertyType: 7; }
    		ListElement { display: "Name"; propertyValue: 12; propertyType: 7; }
    	}
    	
    	DelegateChooser {
    		id: propertyValueDelegate
    		DelegateChoice {
    			delegate: Rectangle {
    				color: "blue"
    				Text {
    					text: "Default delegate"
    				}
    			}
    		}
    	}
    	
    	TableView {
    		id: propertiesTableView
    		anchors.fill : parent
    		model: listModel_1
    		
    		TableViewColumn{ title: "Name"; role: "display"; movable: false; }
    		TableViewColumn{ title: "Type nr"; role: "propertyType";  movable: false; }
    		
    		TableViewColumn{
    			title: "Value"
    			role: "propertyValue"
    			movable: false
    			delegate: propertyValueDelegate
    		}
    	}
    }
    


  • I used Import to QtQuick.Controls 1.4 which added TableView from Quick Controls 1.
    DelegateChooser works with TableView from Quick Controls 2 so only import QtQuick 2.12 should remain


  • Moderators

    @SebastianM
    great that you managed to figure it out.

    It's a bit difficult to read all this on a mobile screen so excuse my previous posts 🙈

    Never the less, thanks for charing the answer