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

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 :)

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.

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);
}

Using QComboBox with QSqlQueryModel

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.

QTableView and unique IDs

I'm new to Qt and coming from C# .Net. I am trying to replicate a fairly simple program I wrote in C# in Qt as a learning tool. I have a data model that inherits QAbstractTableModel and implements:
rowCount,
columnCount,
data,
setData,
headerData
flags
My data structure is a map
std::map<int, CBDataRow>
So the idea was that each row would have a unique int ID and a struct containing the rest of the row information.
What I am stuck on now is how to update my data model when the user makes an edit in the QTableView object. The setData function does get called. Here it is:
bool CBDatabaseModel::setData(const QModelIndex &index, const QVariant &value, int role) {
bool success = false;
if(role == Qt::EditRole) {
success = m_data.UpdateRow(index, value);
}
if(success) {
emit dataChanged(index, index);
return true;
} else {
return false;
}
}
Now you see that the UpdateRow() function gets called here on an edit. That function should find the unique id in the map and update the appropriate members of its CBDataRow struct. My problem is that I have no idea how to get the unique ID out of the QModelIndex object that gets passed into the edit function.
For example:
User edits the "CB Name" cell of row 3. The data in row three has a unique ID of 100. That value of 100 is in the QTableView in a hidden column, column index 0. So what I need to do is simply:
(Psuedo code)
it = m_data.find(unique_id);
it->second.cb_name = value.toString();
Since the user was editing column 1, how do i find the unique ID that is contained in column 0?
I would recommend to reimplement index() method of your model and there create indexes by using the call createIndex(row,col, unique_id);
Then in any place where you got QModelIndex, you can always extract unique_id = model_index.internalId();
In my opinion you can store your data in an array and index your element simply accessing through index.row():
QVector<CBDataRow> m_data;
....
bool CBDatabaseModel::setData(const QModelIndex &index, const QVariant &value, int role) {
bool success = false;
if(role == Qt::EditRole && index.row() < m_data.size()) {
success = m_data.at(index.row()).UpdateRow(index.column(), value);
}
if(success) {
emit dataChanged(index, index);
return true;
} else {
return false;
}
}
if you are worrying about element sorting you can derive your model from a QSortFilterProxyModel (instead of a QAbstractTableModel) and then reimplement
bool CBDatabaseModel::lessThan(const QModelIndex &left,
const QModelIndex &right) const
without define a internal id by yourself.
I hope this can help you.

Display image in QTreeView

I'm trying to show an image in a QTreeView together with some other data. To to this I've created an QAbstractItemModel. In the data method, I return some strings for column index 0 and 1 and for the third I wish to return an image. This image however, is not being displayed.
When I return the image as a decoration it displays fine but I wish to add click listeners to the image that will trigger some events. I also wish to position my image to the far right in the treeview and this seems to require a custom delegate. For these reasons I've created a separate column for the image instead.
Image is created in constructor like this: mEditImage = QImage(":/images/myImage.png");
MyModel
QVariant MyModel::data(const QModelIndex &index, int role) const {
if (!index.isValid()) {
return QVariant();
}
if(role == Qt::FontRole) {
return fontData(index);
}
if(role == Qt::ForegroundRole) {
return foreGroundData(index);
}
MyModelItem *item = getItem(index);
/*
* Use decoration to display image. Probably needs a
* custom delegate to be able to position the image correctly.
* (http://www.qtcentre.org/threads/49639-decoration-position-and-alignment)
* (https://qt-project.org/forums/viewthread/24493)
*
* Will use extra column for now instead. Might help with click
* listeners as well.
*
* if(role == Qt::DecorationRole && item->parent() != mRootItem) {
return index.column() == 1 ? mEditImage : QVariant();
}*/
if(role == Qt::SizeHintRole) {
return mEditImage.size();
}
if (role == Qt::DisplayRole) {
QString id = QString::number(item->id());
QString name = item->name();
if(item->parent() != mRootItem && index.column() == 2) {
return mEditImage;
}
if(item->parent() == mRootItem){
return index.column() == 0 ? name : "";
} else {
return index.column() == 0 ? id : name;
}
} else if(role == Qt::BackgroundRole) {
return QVariant();
}
I've had a look here:
http://www.qtcentre.org/threads/29550-How-do-I-display-a-picture-on-a-QTableView-cell
How to set an image for a row?
I've tried changing the image to a QPixmap and QIcon and also tried embedding it in a QLabel (which could not be converted to a QVariant) without luck. Changing the image to a QString displays the string so the row/column logic seems fine. Removing the SizeHintRole logic doesn't make any difference either.
Any help in understanding how to display image data in a QTreeView would be helpful. I seem to be going at this from the wrong direction.
Cheers.
It doesn't matter, how to store image. QPixmap is prefferable for speed drawing.
QVariant MyModel::data(const QModelIndex &index, int role) const
{
item = itemFromIndex( index ); // Your item implementation
...
case Qt::DisplayRole:
return item->getText();
case Qt::DecorationRole:
return item->getImage();
}
Read Qt docs about roles, it's good - http://doc.qt.io/qt-4.8/qt.html#ItemDataRole-enum