QSqlQueryModel - How to add and delete rows? - qt

I am making my model which inherits from QSqlQueryModel
#include <QSqlQueryModel>
class SqlQueryModelBorrowingUsers : public QSqlQueryModel
{
Q_OBJECT
//some class members
};
I also have a view that I set in BorrowingUsersWindow class and pass my model to that view.
in this view, i have two QPushButtons add record and delete record
class BorrowingUsersWindow : public QDialog
{
Q_OBJECT
//some class members
private:
SqlQueryModelBorrowingUsers *myModel; //my model
QTableView *tblViewUserData; //my view
QPushButton *bttAddRecord, *bttRemoveRecord; //I have a two buttons add and remove
};
Looking at the classes that QSqlQueryModel inherits from, I found
two functions in the QAbstractItemModel class
insertRow(int row, const QModelIndex &parent = QModelIndex())
removeRow(int row, const QModelIndex &parent = QModelIndex())
So the question is this. How can I implement adding and deleting rows with these two functions? Will someone give you a sample code?

Related

Split a QAbstarctListModel into sub models

I have a list of custom objects that I need to split across multiple pages of a SwipeView.
Right now, I implement a QAbstractListModel to provide the data to my QML view through custom roles.
But when I have more then a given number of object, I need to split my model in multiple chunks that will be displayed on different pages of a SwipeView.
If my model has 20 object, my SwipeView will have 2 pages with 12 Items in the first one and the 8 remainings in the second page for example but the number of items is, of course, dynamic.
I know that I can use a QSortProxyFilter or a DelegateModel to filter my model on a criteria but I don't know how I can use them to create groups usable as submodels for the content of the pages of the SwipeView. Because of course, I cannot just change the filter when the page change because that wouldn't make the items visible when swiping from one page to the other.
Thanks for any hint or idea on how to achieve this.
Why don't you include a model into another model? You can return the model to QML via QVariant::fromValue. See my example:
models.h
class ChildItem{
public:
ChildItem() {}
};
class ChildModel: public QAbstractListModel{
Q_OBJECT
public:
explicit ChildModel(QObject *parent = nullptr);
void addItem(const ChildItem &item);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
signals:
void itemAdded();
protected:
QHash<int,QByteArray> roleNames() const;
private:
QVector<ChildItem> m_items;
};
class ModelItem{
public:
ModelItem() {}
ChildModel *childModel() const;
private:
ChildModel *m_childModel;
};
class MainModel: public QAbstractListModel{
Q_OBJECT
public:
explicit MainModel(QObject *parent = nullptr);
void addItem(const ModelItem &item);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
signals:
void itemAdded();
protected:
QHash<int,QByteArray> roleNames() const;
private:
QVector<ModelItem> m_items;
};
models.cpp
ChildModel *ModelItem::childModel() const{
return m_childModel;
}
QVariant MainModel::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= (int)m_items.size())
return QVariant();
const MainModel &item = m_items[index.row()];
switch (role) {
case MainModelRoles::ChildModel:{
return QVariant::fromValue(item.childModel());
}
default: {
break;
}
}
return QVariant();
}
QHash<int, QByteArray> MainModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[MainModelRoles::ChildModel] = "child_model";
return roles;
}
From within QML you can present model role name as a new model for another element. For example:
StackLayout which is your main element, includes Repeater.
Repeater model is MainModel class instance.
Repeater delegate includes ListView
ListView takes ChildModel as a model for itself (child_model reference)
So you can contain any amount of different models inside main model and expose them to QML as model property. Is this what you're looking for?

How to use removeRows with QStringListModel

I have a QStringListModel which works ok, but then I need to delete all the rows from it from QML.
I would expect removeRowsfunction from Qt documentation work like that, but I don't know how to use it property.
removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
I tried to use it like this:
myModel.removeRows(1, 1)
But I am getting thie error:
qrc:/Logger.qml:63: TypeError: Property 'removeRows' of object QStringListModel(0x337350) is not a function
Can someone explain how to use removeRows correctly? Thanks.
removeRows() is not invokable from QML. the solution is to make it invokable by creating a new class and overriding that method:
class StringListModel: public QStringListModel{
Q_OBJECT
public:
Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()){
return QStringListModel::removeRows(row, count, parent);
}
};
In the following link there is an example.

Accessing QAbstractListModel item in Qml without using a ListView

I have subclassed QAbstractListModel in order to have a model on the qml side. I can easily use this model in ListViews and other similar components that deal with models, however, I can't access it directly. This is what I am trying without success:
myModel[0].name // TypeError: Cannot read property 'name' of undefined
Is this possible? Am I using the wrong syntax?
You can access generic model (based on QAbstractListModel) easily when you use DelegateModel model as a mediator.
import QtQuick 2.2
import QtQml.Models 2.2
DelegateModel {
id: delegateModel
}
MyModel {
id: myModel
onDataLoaded: {
delegateModel.model = myModel;
for (var row = 0; row < myModel.rowCount(); row++) {
var item = delegateModel.items.get(row).model;
console.log(" name " + row + ":" + item.name);
}
}
}
(1) You're mixing up roles and properties.
Your model implements roles which are used to feed a delegate in a view. In your code, you try to access a property.
(2) A model is not an array, where you can access rows by the [] operator.
But you can write a getter function to achieve exactly that:
class ConversationListModel : public QAbstractListModel
{
Q_OBJECT
public:
enum ConversationRoles {
IdRole = Qt::UserRole, // 256
NameRole,
};
explicit ConversationListModel(QObject *parent = 0);
QHash<int, QByteArray> roleNames() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
Q_INVOKABLE ConversationModel* get(quint32 conversationId) const;
signals:
// ...
Than you need a data type that represents a row, e.g. ConversationModel. Now you can access a row using
myModel.get(0).name
As stated in (1), you now need to give ConversationModel a property called name
public:
explicit ConversationModel(QObject *parent = 0);
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
QString name() const;
To make the (correct) solution of Simon Warta work, you have to register ConversationModel as QML type. For example in your main you have to state
qmlRegisterType<ConversationModel>("ConversationModel", 1, 0, "ConversationModel");
Then in your qml file you have to import this type with
import ConversationModel 1.0
Afterwards everything works as expected and you can use
myModel.get(0).name
in your qml code, given that myModel is of type ConversationListModel and was registered using QDeclarativeContext::setContextProperty.

QTreeView with QAbstractItemModel and parent not known in the datamodel

I want to use QTreeView to visualize my class hierarchy. That hierarchy is given and I couldn't change it. But QAbstractItemModel force me to implement a parent() method in it. How can I do that?
So I have:
class ItemA
{
std::vector<Items1> items1;
std::vector<Items2> items2;
std::vector<Items3> items3;
};
class Items2
{
std::vector<Items1X> items1X;
std::vector<Items2X> items2X;
std::vector<Items3X> items3X;
};
...
How can I implement a QModelIndex parent(const QModelIndex &index) const; method for QAbstractItemModel?

QTableView - Not Getting Selection Changed Signal

I am fairly new to QT, and am having trouble understanding how the QTableView selection changed signal is handled. I have setup a window with an openGL widget and a QTableView. I have a data model class that is correctly populating the tableview, so I added a public slot to that class:
class APartsTableModel : public QAbstractTableModel
{
public:
AVehicleModel *vehicle;
explicit APartsTableModel(QObject *parent = 0);
//MVC functions
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &paret) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
public slots:
void selectionChangedSlot(const QItemSelection &newSelection,
const QItemSelection &oldSelection);
};
When I am ready to show the window with the table view, I allocate/initialize it like this:
//create the display view
AStarModelView *displayWindow = new AStarModelView(this,
starModel->vehicle);
//create the datamodel for the table view
APartsTableModel *dataModel = new APartsTableModel(displayWindow);
dataModel->vehicle = starModel->vehicle;
//create selection model for table view
QItemSelectionModel *selModel = new QItemSelectionModel(dataModel);
displayWindow->materialsTable->setSelectionModel(selModel);
//setup model and signal
displayWindow->materialsTable->setModel(dataModel);
connect(selModel,
SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
dataModel,
SLOT(selectionChangedSlot(const QItemSelection &, const QItemSelection &)));
//show the view
displayWindow->show();
When I set a breakpoint in the implementation of the slot function, I never hit it. I've also tried not allocating a new QItemSelectionModel, but that didn't work either. I'm really not sure what I'm doing wrong here.
When you call setModel() on the view, your locally allocated QItemSelectionModel is getting replaced by one created by the view. You shouldn't have to create your own selection model anyway. Just change your connect to
connect(displayWindow->materialsTable->selectionModel(),
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
dataModel,
SLOT(selectionChangedSlot(const QItemSelection&, const QItemSelection&)));
What's the first thing you should check in QT when signals/slots don't seem to be working correctly? That your class has the Q_OBJECT macro in it. Added this to the APartsTable class definition, and now I'm hitting the breakpoint.
When does Friday get here?
Just to pull the answer out of the discussion:
What's the first thing you should check in QT when signals/slots don't
seem to be working correctly? That your class has the Q_OBJECT macro
in it. Added this to the APartsTable class definition, and now I'm
hitting the breakpoint
.
virtual Qt::ItemFlags QAbstractItemModel::flags(const QModelIndex &index) const
must return Qt::ItemIsSelectable | otherFlags

Resources