Using QComboBox with QSqlQueryModel - c++

To speed-up QComboBox work with very big data set want to try to use QSqlQueryModel instead of QStandardItemModel. However text data in QComboBox I need to map to an ID, which is stored and accessible currently by itemData(rowIndex, Qt::UserRole). In QSqlQueryModel query there will be 2 columns: ID and Text; and QComboBox setModelColumn(1) is defined, i.e. Text.
How to correctly subclass or redefine QSqlQueryModel, if combobox->itemData(rowIndex, Qt::UserRole) have to contain ID? Who had implemented such things or know link to a source? If I define QVariant QSqlQueryModel::data(const QModelIndex & item, int role = Qt::DisplayRole) in a such way:
QVariant MySqlModel::data(const QModelIndex &index, int role) const
{
if(role == Qt::UserRole && index.column() == 1)
return QSqlQueryModel::data(this->index(index.row(), 0), Qt::DisplayRole);
return QSqlQueryModel::data(index, role);
}
will it work, i.e. whether combobox->itemData(rowIndex, Qt::UserRole) will contain ID in this case? Or need to investigate Qt sources?

Yeah, according to QComboBox code should work:
QVariant QComboBox::itemData(int index, int role) const
{
Q_D(const QComboBox);
QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
return d->model->data(mi, role);
}
Will implement this.

Related

Why can't you use setData() to set background color of a Cell in QTreeView?

I'm using the following code to try to change the background color of a cell at a given QModelIndex.
ui->TreeView->model()->setData(index, QVariant(QBrush (QColor(Qt::green))) , Qt::BackgroundRole);
where index is given by the dataChanged() signal.
This isn't working. Any ideas why?
Here's my reimplemented setData function.
bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
TreeItem *item = getItem(index); //gets item a given index
bool result = item->setData(index.column(), value);
if (result)
emit dataChanged(index, index);
return result;
}
And here is the setData method for the underlying item:
bool TreeItem::setData(int column, const QVariant &value)
{
if (column < 0 || column >= itemData.size())
return false;
itemData[column] = value;
return true;
}
Apologies for the vague question. I've managed to solve it by myself so I will post here in case anyone is ever stuck on a similar issue.
The problem for me was that I hadn't reimplemented QAbstractItemView's data() method to account for the new role.
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
TreeItem *item = getItem(index);
if (role == Qt::BackgroundRole)
return item->data(index.column());
//and so on...
AFAIK the data() method gives the treeview the data out of the model that it needs to present. Within this method I hadn't accounted for the case when role == Qt::BackgroundRole so the view was never given the appropriate information out of the model.

QSqlRelationalTableModel QTableView colorizing rows

What is the right way to color-code rows in a QTableView?
I'm developing a spreadsheet application that should color-code its rows based on a specific value set in one of the columns. I use QSqlRelationalTableModel and QSqlRelationalDelegate; because, the value that should determine the color is a foreign key.
Why can't it be as simple as the following? Any ideas?
model->setData( model->index( index.row(), index.column() ),
QBrush(Qt::red),
Qt::BackgroundRole );
You should overwrite the data function of QSqlRelationalTableModel and when you get the Qt :: BackgroundRole role to filter according to your case and return the appropriate QBrush, in the following example filter by the foreign field and check that it is equal to Lima:
Example:
sqlrelationaltablemodel.h
#ifndef SQLRELATIONALTABLEMODEL_H
#define SQLRELATIONALTABLEMODEL_H
#include <QSqlRelationalTableModel>
class SqlRelationalTableModel : public QSqlRelationalTableModel
{
Q_OBJECT
public:
SqlRelationalTableModel(QObject * parent = 0, QSqlDatabase db = QSqlDatabase());
QVariant data(const QModelIndex & item, int role = Qt::DisplayRole) const;
};
#endif // SQLRELATIONALTABLEMODEL_H
sqlrelationaltablemodel.cpp
#include "sqlrelationaltablemodel.h"
#include <QBrush>
SqlRelationalTableModel::SqlRelationalTableModel(QObject *parent, QSqlDatabase db)
:QSqlRelationalTableModel(parent, db)
{
}
QVariant SqlRelationalTableModel::data(const QModelIndex &item, int role) const
{
if(role == Qt::BackgroundRole)
if(QSqlRelationalTableModel::data(index(item.row(), 2), Qt::DisplayRole).toString().trimmed() == "Lima")
return QVariant(QBrush(Qt::red));
return QSqlRelationalTableModel::data(item, role);
}
Output:
The complete example can be found here.

Add virtual column to Qt SQL model using a proxy

I display an SQL table in a view using a QSqlTableModel.
I want to display an additional status column based on the row data, for that I use a custom QIdentityProxyModel where I increase the columnCount and return data for that new virtual column which does not exist in the QSqlTableModel.
int MyProxyModel::columnCount(const QModelIndex& parent) const
{
return sourceModel() ? (sourceModel()->columnCount() + 1) : 0;
}
QVariant MyProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (section == columnCount()-1 &&
orientation == Qt::Horizontal &&
role == Qt::DisplayRole)
{
return tr("MyHeader");
}
return QIdentityProxyModel::headerData(section, orientation, role);
}
QVariant MyProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
qDebug() << "data " << proxyIndex.row() << proxyIndex.column();
// ...never called for my extra column (== columnCount()-1)
if (proxyIndex.column() == columnCount()-1 && role == Qt::DisplayRole)
return QString("I am virtual");
return QIdentityProxyModel::data(proxyIndex, role);
}
Edit: I changed the code for something more simple regarding to the comments. I still have the same problem.
My problem is that the view never asks data for my virtual column, it calls data() for all other columns of the actual SQL table but not the last virtual one, what have I missed ?
Also, the header data is working well for my extra column, the problem is only with the data. The view draws the extra column, but content is empty (even alternating row background is not painted).
Thx !
The view needs to get the QModelIndex objects for the virtual column, so I also needed to override the index function in the proxy :
QModelIndex MyProxyModel::index(int row, int column, const QModelIndex &parent) const
{
if (column == columnCount()-1)
return createIndex(row, column);
return QIdentityProxyModel::index(row, column);
}
I didn't mind the parent because I only have a table (from database), though I do not know how it could be dealt with if needed because createIndex does not allow to specify a parent.
The m_mySqlTableColumnCount member is unnecessary. You'd have to ensure it's always correct by listening to the source model's signals that update the column count. Alas, it's unnecessary. You want to pass the column count request through to the source model:
int MyProxyModel::columnCount(const QModelIndex& parent) const
{
return sourceModel() ? (QIdentityProxyModel::columnCount() + 1) : 0;
}
Then:
QVariant MyProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (section == columnCount()-1 &&
orientation == Qt::Horizontal &&
role == Qt::DisplayRole)
{
return tr("MyHeader");
}
return QIdentityProxyModel::headerData(section, orientation, role);
}
QVariant MyProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
if (proxyIndex.column() == columnCount()-1) {
qDebug() << proxyIndex.row() << proxyIndex.column();
...
}
return QIdentityProxyModel::data(proxyIndex, role);
}

Qt checkboxes in QTableView

I'm using this code to query sqlite and put the results in a QTableView.
//MainWindow.cpp
void MainWindow::on_pushButton_clicked()
{
QSqlQueryModel * modal=new QSqlQueryModel();
connOpen();
QSqlQuery* qry=new QSqlQuery(mydb);
qry->prepare("select * from database");
qry->exec();
modal->setQuery(*qry);
//from stack
modal->insertColumn(0);
ui->tableView->setModel(modal);
//from stack
ui->tableView->resizeColumnsToContents();
int p;
for(p=0; p<modal->rowCount(); p++)
{
ui->tableView->setIndexWidget(modal->index(p,0),new QCheckBox());
}
connClose();
qDebug() <<(modal->rowCount());
}
I've seen several examples of the web for adding checkboxes to a column, but I'm not quite sure what to use for my simple example.
This answer suggests a few lines that doesn't seem standard.
There are more examples like this and this one that appear to outline what I need, but it's unclear to where you place the code.
What I intend to do is to have column 1 checkable. On next btn press, If checked those rows of data get written to a file.
I still need to understand how to loop thru the selected data, or perhaps I need to get the ids of the checked rows and do another query.
Questions:
How do you add 1 column of editable checkboxes to QTableView?
How do you loop through values in the QTableView data, so values of the checked rows can be accessed?
How do you check all/none?
I think the best way to have a column of checkable cells is to create your item model, e.g. by subclassing the QSqlQueryModel.
You must reimplement the flags() method to make checkable the cells.
Also you need to reimplement the data() method to return the check state and the setData() method and to set the check state. You must implement your own logic to keep track of the check state of every rows (e.g. using an array of Qt::CheckState that you must initialize and resize when the model data changes).
Yuo can start with something like this:
class MyModel : public QSqlQueryModel
{
public:
Qt::ItemFlags flags(const QModelIndex & index) const
{
if(index.column() == 0)
return QSqlQueryModel::flags(index) | Qt::ItemIsUserCheckable;
return QSqlQueryModel::flags(index);
}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const
{
if(index.column() == 0 && role == Qt::CheckStateRole)
{
//implement your logic to return the check state
//....
}
else
return QSqlQueryModel::data(index, role);
}
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)
{
if(index.column() == 0 && role == Qt::CheckStateRole)
{
//implement your logic to set the check state
//....
}
else
QSqlQueryModel::setData(index, value, role);
}
};
Se also:
Model Subclassing
QAbstractItemModel documentation

How to set data (Qt::UserRole) into QSqlQueryModel column?

I have QSqlQueryModel that handling data , im trying to set Qt::UserRole to column
but i can’t figure a way to do it i have implement the data method :
basically what i want is to hide the Qt::DisplayRole of ndex.column() 4 and set it to Qt::UserRole
QVariant MyListSqlModel::data(const QModelIndex &index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);
QVariant valueEmpty = "";
int j = index.column();
if (value.isValid() && role == Qt::DisplayRole && j== 4 )
{
QModelIndex LinkIndex = QSqlQueryModel::index(index.row(),4);
setData(LinkIndex,value,Qt::UserRole); // this is not working and gives me erorr
return valueEmpty;
}
else
{
return value;
}
}
it give me this error that i know what it is the implement method is not const
error C2662: 'MyListSqlModel::setData' : cannot convert 'this' pointer from 'const MyListSqlModel' to 'MyListSqlModel&'
but what is the right way to do it ?
As I understand from the code you want to ignore the Qt::DisplayRole of the column 4. In that case you don't have to deal with the UserRole but just return empty QVariant
QVariant MyListSqlModel::data(const QModelIndex &index, int role) const
{
if(index.column() == 4 && role == Qt::DisplayRole)
return QVariant();
//else process the data in ususal way
}
Please correct me if I misunderstood the question
edit
Thanks for the comment. I have started myself using custom roles for my models. The workflow goes like this:
Define a custom user role in the header
enum MyDataRoles {
MyDisplayRole = Qt::UserRole + 10
}
Now for the setData I am using a snippet from here.
And for getting the data you can use snippet from here. You just have to check for the MyDisplayRole
I hope that helps :)