[SOLVED]How to update the TableView in QML or C++?
-
I am coding a program combining QML and C++. The TableView shows a column of a table. I can add or delete the record correctly, but I can not update the TableView, which always shows the content before adding or deleting.
How to update the TableView?
PS: I do not know whether it is good choice to code with QML and C++ instead of QWidget directly. At least by now, it keeps frustrating me.
-
I am coding a program combining QML and C++. The TableView shows a column of a table. I can add or delete the record correctly, but I can not update the TableView, which always shows the content before adding or deleting.
How to update the TableView?
PS: I do not know whether it is good choice to code with QML and C++ instead of QWidget directly. At least by now, it keeps frustrating me.
Hi @CoderJeff,
Assuming you are usingQAbstractTableModel
orQAbstractItemModel
as C++ model with QML, to update the view, use setData to update the model and then fire the dataChanged signal with appropriate index to notify the view about the changes.
It would be helpful if you post some code.I do not know whether it is good choice to code with QML and C++ instead of QWidget directly. At least by now, it keeps frustrating me.
It totally depends upon your requirements.
-
Hi @CoderJeff,
Assuming you are usingQAbstractTableModel
orQAbstractItemModel
as C++ model with QML, to update the view, use setData to update the model and then fire the dataChanged signal with appropriate index to notify the view about the changes.
It would be helpful if you post some code.I do not know whether it is good choice to code with QML and C++ instead of QWidget directly. At least by now, it keeps frustrating me.
It totally depends upon your requirements.
Actually, I am using QSqlTableModel.
class MySqlModel : public QSqlTableModel
{
......
void addRecord(field1,field2, ..., fieldN);
void deleteRecord();
void updateRecord(field1, field2, ..., fieldN);
......
}The TableView in QML has only one column.
After running addRecord() and deleteRecord(), I want to update the content of TableView. But I do not know how to do it. The following is a part of my code.
main() {
//other code
......MySqlModel *model = new MySqlModel;
model->QSqlQueryModel::setQuery("SELECT FieldName1 FROM Table");QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty ("SQQL", model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));//other code
......
}In the qml:
TableView{
//other code
......model: SQQL
//other code
......
}How to use setData and dataChanged to connect MySqlModel in C++ and TableView in QML?
-
Actually, I am using QSqlTableModel.
class MySqlModel : public QSqlTableModel
{
......
void addRecord(field1,field2, ..., fieldN);
void deleteRecord();
void updateRecord(field1, field2, ..., fieldN);
......
}The TableView in QML has only one column.
After running addRecord() and deleteRecord(), I want to update the content of TableView. But I do not know how to do it. The following is a part of my code.
main() {
//other code
......MySqlModel *model = new MySqlModel;
model->QSqlQueryModel::setQuery("SELECT FieldName1 FROM Table");QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty ("SQQL", model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));//other code
......
}In the qml:
TableView{
//other code
......model: SQQL
//other code
......
}How to use setData and dataChanged to connect MySqlModel in C++ and TableView in QML?
@CoderJeff Are
addRecord
,updateRecord
accessible from QML ?
Once you have called say addRecord(int field1) you need to callsetData()
after it to update the model and dataChanged() with proper index.
An example from one of my code:void PicModel::updateTitle(int row, int col, QString title) { QModelIndex modelIndex = this->index(row,col); setData(modelIndex, title, TitleRole); return; } bool PicModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == TitleRole) { m_data[index.row()].m_title = value.toString(); //Just a list which holds 'struct' of pics info } emit dataChanged(index, index); return true; }
So from QML
updateTitle
is invoked with parameters (row and title) and the rest code updates the QList (data holder) and then updates the view. -
@CoderJeff Are
addRecord
,updateRecord
accessible from QML ?
Once you have called say addRecord(int field1) you need to callsetData()
after it to update the model and dataChanged() with proper index.
An example from one of my code:void PicModel::updateTitle(int row, int col, QString title) { QModelIndex modelIndex = this->index(row,col); setData(modelIndex, title, TitleRole); return; } bool PicModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == TitleRole) { m_data[index.row()].m_title = value.toString(); //Just a list which holds 'struct' of pics info } emit dataChanged(index, index); return true; }
So from QML
updateTitle
is invoked with parameters (row and title) and the rest code updates the QList (data holder) and then updates the view.@p3c0 said:
Are addRecord, updateRecord accessible from QML ?
Yes.
I tried, but it does not work.
void MySqlModel::addRecord(const QString &str1)
{
//add a record
......//update the model
QSqlQueryModel::setQuery("SELECT FieldName1 FROM Table");
int ct = this->rowCount();
QModelIndex modelIndex = this->index(ct-1,0);
this->setData(modelIndex, str1, PortName);
......
}I did not overload the setData since I have no class member m_data like yours. I only update the instance of MySqlModel.
-
@p3c0 said:
Are addRecord, updateRecord accessible from QML ?
Yes.
I tried, but it does not work.
void MySqlModel::addRecord(const QString &str1)
{
//add a record
......//update the model
QSqlQueryModel::setQuery("SELECT FieldName1 FROM Table");
int ct = this->rowCount();
QModelIndex modelIndex = this->index(ct-1,0);
this->setData(modelIndex, str1, PortName);
......
}I did not overload the setData since I have no class member m_data like yours. I only update the instance of MySqlModel.
@CoderJeff Well then in case of add, use beginInsertRows and endInsertRows. This too will update the model and thus the view. Can you post the complete code ? Its harder to guess how you are trying to implement it.
-
@CoderJeff Well then in case of add, use beginInsertRows and endInsertRows. This too will update the model and thus the view. Can you post the complete code ? Its harder to guess how you are trying to implement it.
C++ code:
class MySqlModel : public QSqlTableModel
{
Q_OBJECTpublic:
MySqlModel(QObject *parent = 0);
~MySqlModel();enum Roles { Field1 = Qt::UserRole + 1, Field2 }; QHash<int, QByteArray> roleNames() const; QVariant data(const QModelIndex &index, int role) const; Q_INVOKABLE void addRecord(const QString &str1, const QString &str2, const QString &str3);
private:
static void createConnection();
static void closeConnection();static QSqlDatabase m_db;
};
QHash<int, QByteArray> MySqlModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Field1] = "field1";
roles[Field2] = "field2";
return roles;
}QVariant MySqlModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();QString fieldName; switch (role) { case Field1: fieldName = QStringLiteral("FieldName1"); break; case Field2: fieldName = QStringLiteral("FieldName2"); break; } if (!this->record().isGenerated(fieldName)) return QVariant(); else { QModelIndex item = indexInQuery(index); if ( !this->query().seek(item.row()) ) return QVariant(); return this->query().value(fieldName); } return QVariant();
}
void MySqlModel::addRecord(const QString &str1, const QString &str2, const QString &str3)
{
QSqlQuery query;
bool bPrepare = query.prepare("INSERT INTO Portfolio (fieldName1, "
"fieldName2,"
"fieldName3)"
"VALUES (?,?,?)");query.addBindValue(str1); query.addBindValue(str2); query.addBindValue(str3); query.exec();
QSqlQueryModel::setQuery("SELECT FieldName1 FROM Portfolio")
int ct = this->rowCount();QModelIndex modelIndex = this->index(ct-1,0); this->setData(modelIndex, str1, Field1); return;
}
Qml code:
TableView{
id: myTableView
objectName: "myTableViewObj"
anchors.top: rowRadio.bottom
anchors.left: rowRadio.left
anchors.right: rowRadio.right
anchors.bottom: parent.bottom
anchors.topMargin: 8
TableViewColumn{ role: "field1"; title: "FieldName1"}
headerVisible: false
model: SQQL
} -
I changed my code. It works finally.
Add a Q_INVOKABLE function:
Q_INVOKABLE QObject* model()
{
QSqlQueryModel::setQuery("SELECT FieldName1 FROM Portfolio")
return mySqlModelInstance;
}In QML, after calling addRecord or deleteRecord, call the above function and update the TableView's model.
{
......
myModel.addRecord();
tableView.model = myModel.model();
......
}{
......
myModel.deleteRecord();
tableView.model = myModel.model();
......
}I did not use setData or dataChanged.
-
I changed my code. It works finally.
Add a Q_INVOKABLE function:
Q_INVOKABLE QObject* model()
{
QSqlQueryModel::setQuery("SELECT FieldName1 FROM Portfolio")
return mySqlModelInstance;
}In QML, after calling addRecord or deleteRecord, call the above function and update the TableView's model.
{
......
myModel.addRecord();
tableView.model = myModel.model();
......
}{
......
myModel.deleteRecord();
tableView.model = myModel.model();
......
}I did not use setData or dataChanged.
@CoderJeff But then you are assigning model and again and again when something is added or removed. Instead try to use beginResetModel and beginInsertRows.
-
@CoderJeff But then you are assigning model and again and again when something is added or removed. Instead try to use beginResetModel and beginInsertRows.
I will try it.
QML almost drives me crazy.
I am making a desktop program. I find it is very inconvenient to integrate QML and C++ while it is much more convenient using QWidget. I check the difference between QML and QWidget. QML is encapsulated and all its elements are private. It is not easy to access the elements of QML. On the contrary, QWidget on GUI are public. User can access them freely.
Do you agree with me?
-
I will try it.
QML almost drives me crazy.
I am making a desktop program. I find it is very inconvenient to integrate QML and C++ while it is much more convenient using QWidget. I check the difference between QML and QWidget. QML is encapsulated and all its elements are private. It is not easy to access the elements of QML. On the contrary, QWidget on GUI are public. User can access them freely.
Do you agree with me?
@CoderJeff Well new QtQuick Controls are still evolving. Many of the important properties are still under development and hence they are private.
I find it is very inconvenient to integrate QML and C++ while it is much more convenient using QWidget
Depends upon the requirement. I have been using components like
Item
,ListView
etc.. with C++ with no problem. Finding Items, connecting to QML signals too work.QML is encapsulated and all its elements are private.
Yes they are (assuming creating from C++). But you can create Items from C++ using QQuickItem. May there are troubles in making them public. Or may be in future they could be made public. Or may be they are not meant to be made.