Set text to QLabel if no Image from QSqlTableModel (QDataWidgetMapper) is available
-
@JonB hi maybe you added a proxy model that returned a default value of the original was null ?
-
@JonB hi maybe you added a proxy model that returned a default value of the original was null ?
@SGaist Yes, I mapped a subclass QSortFilterProxyModel. My code:
#include "imagefiltermodel.h" ImageFilterModel::ImageFilterModel(){} ImageFilterModel::~ImageFilterModel() { qDebug() << "ImageFilterModel deleted"; } void ImageFilterModel::setIdFilter(const int &id) { if(mIdFilterValue != id) { mIdFilterValue = id; emit invalidateFilter(); } } bool ImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_UNUSED(source_parent) if(mIdFilterValue == -1){ return true; } else { const int id = sourceModel()->index(source_row, mIdColumn).data().toInt(); return (id == mIdFilterValue); } }
The original model returns NULL. How can I proceed now? Do you have any tips? I am currently a bit overwhelmed and see no approach how I can continue. What I should look for or what I can try. Would be good if you could help me. Thanks for the support!
-
Re-implement the data method and manage your special case there.
-
@SGaist Implementing the data method doesn't seem to be correct either (at least I think). Here is my code first:
QVariant ImageFilterModel::data(const QModelIndex &index, int role) const { qDebug() << "DataIndex: " << index; if(!index.isValid()){ qDebug() << "Index in datamethod is invalid"; return QVariant(); } return QSortFilterProxyModel::data(index,role); }
In the first step I wanted to know if this method is really called. Therefore I just implemented a simple qDebug(). But here it goes again. If I select a dataset where no image is stored, then it does not jump into the data method. Can you help me please? Thanks a lot!
-
@SGaist Implementing the data method doesn't seem to be correct either (at least I think). Here is my code first:
QVariant ImageFilterModel::data(const QModelIndex &index, int role) const { qDebug() << "DataIndex: " << index; if(!index.isValid()){ qDebug() << "Index in datamethod is invalid"; return QVariant(); } return QSortFilterProxyModel::data(index,role); }
In the first step I wanted to know if this method is really called. Therefore I just implemented a simple qDebug(). But here it goes again. If I select a dataset where no image is stored, then it does not jump into the data method. Can you help me please? Thanks a lot!
@Gabber
I have now had a chance to fire up my Qt machine. But among my variety of projects I am unable to find "special handling ofQVariant()
(invalid/emptyQVariant
) or databaseNULL
", if I did have such a case.I do see the following in one project:
/*virtual*/ void BoardCellDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const /*override*/ { QVariant data(index.data()); if (!data.isValid()) { ...
That
!data.isValid()
test captures whenindex.data()
returnsQVariant()
, for "no value there". And this code is hit (and works) when certain cells do have "no data". So the implication is I find it does still call the delegate in this case....If you still find that is not the case, I think @SGaist's
@JonB hi maybe you added a proxy model that returned a default value of the original was null ?
would be: derive from
QIdentityProxyModel
, set its source to your model and add e.g.QVariant YourIdentityProxyModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const { if (!index.isValid()) return QVariant(); QVariant v(QIdentityProxyModel::data(index, role)); if (role == Qt::DisplayRole && index.column() == imageColumnNumber) if (!v.isValid()) v = "No image available"; return v; }
I think that ought work.
If you are still having problems:
- Temporarily remove your
QSortFilterProxyModel
and get it working without that. (This might even allow my earlier case above to work, where I do seepaint()
being called.) - I do not recognise your earlier
QModelIndex(-1,-1,0x0,QObject(0x0)). That is, if no index exists.
This is truly an invalid index, not invalid/empty/NULL data. Which is a different case, if Qt thinks an index is not valid it's not going to draw/output anything. Maybe that is all to do with your database foreign keys and
NULL
s.I would simplify your case while I figured out the behaviour/workaround for the no-image case you want to handle. Remove
QSortFilterProxyModel
, don't do foreign keys, have a database column just containNULL
(at least in certain rows). Reduce to a simple minimum, get that working like you want, then build up from there to your real case. - Temporarily remove your
-
@Gabber
I have now had a chance to fire up my Qt machine. But among my variety of projects I am unable to find "special handling ofQVariant()
(invalid/emptyQVariant
) or databaseNULL
", if I did have such a case.I do see the following in one project:
/*virtual*/ void BoardCellDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const /*override*/ { QVariant data(index.data()); if (!data.isValid()) { ...
That
!data.isValid()
test captures whenindex.data()
returnsQVariant()
, for "no value there". And this code is hit (and works) when certain cells do have "no data". So the implication is I find it does still call the delegate in this case....If you still find that is not the case, I think @SGaist's
@JonB hi maybe you added a proxy model that returned a default value of the original was null ?
would be: derive from
QIdentityProxyModel
, set its source to your model and add e.g.QVariant YourIdentityProxyModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const { if (!index.isValid()) return QVariant(); QVariant v(QIdentityProxyModel::data(index, role)); if (role == Qt::DisplayRole && index.column() == imageColumnNumber) if (!v.isValid()) v = "No image available"; return v; }
I think that ought work.
If you are still having problems:
- Temporarily remove your
QSortFilterProxyModel
and get it working without that. (This might even allow my earlier case above to work, where I do seepaint()
being called.) - I do not recognise your earlier
QModelIndex(-1,-1,0x0,QObject(0x0)). That is, if no index exists.
This is truly an invalid index, not invalid/empty/NULL data. Which is a different case, if Qt thinks an index is not valid it's not going to draw/output anything. Maybe that is all to do with your database foreign keys and
NULL
s.I would simplify your case while I figured out the behaviour/workaround for the no-image case you want to handle. Remove
QSortFilterProxyModel
, don't do foreign keys, have a database column just containNULL
(at least in certain rows). Reduce to a simple minimum, get that working like you want, then build up from there to your real case.@JonB Thank you very much for your answer. I can't derive from
QIdentityProxyModel
because I need filtering the model.My plan is to select an item from a QListView (the QListView is assigned a QSqlRelationTableModel). From there I get the ID of the record and search in my ImageFilterModel for the corresponding images and map them via the QDataWidgetMapper.
If I now derive my class from
QIdentityProxyModel
, then I no longer have the search functionsetIdFilter
, because there theemit invalidateFilter()
; no longer exists.I didn't think it would be so complicated. I'm sure I'm not the first to want something like this. Is there any other possibility? I definitely can't do without the filtration.
- Temporarily remove your
-
@JonB Thank you very much for your answer. I can't derive from
QIdentityProxyModel
because I need filtering the model.My plan is to select an item from a QListView (the QListView is assigned a QSqlRelationTableModel). From there I get the ID of the record and search in my ImageFilterModel for the corresponding images and map them via the QDataWidgetMapper.
If I now derive my class from
QIdentityProxyModel
, then I no longer have the search functionsetIdFilter
, because there theemit invalidateFilter()
; no longer exists.I didn't think it would be so complicated. I'm sure I'm not the first to want something like this. Is there any other possibility? I definitely can't do without the filtration.
@Gabber said in Set text to QLabel if no Image from QSqlTableModel (QDataWidgetMapper) is available:
I can't derive from QIdentityProxyModel because I need filtering the model.
I have no idea why you think this. You can. If necessary, and when working, you can have either of:
database -> QSqlTableModel -> QIdentityProxyModel -> QSortFilterProxyModel -> view database -> QSqlTableModel -> QSortFilterProxyModel -> QIdentityProxyModel -> view
Which one of these two depends on the exact behaviour you want for the "empty" image values. My initial preference would be for the second.
I merely suggested you remove the
QSortFilterProxyModel
temporarily while you get things working for the display of "No image" working, to simplify things.If I now derive my class from QIdentityProxyModel, then I no longer have the search function setIdFilter, because there the emit invalidateFilter(); no longer exists.
I don't understand what you mean by this. If it's relevant, don't forget that even if you use proxy models you can always access
sourceModel()
if you need to get at the original model for whatever reason.I reiterate: I do not recognise your
if the QModelIndex imageIndex has the following value: QModelIndex(-1,-1,0x0,QObject(0x0)). That is, if no index exists.
I don't know where you get that from, if I were you I would find out.
I didn't think it would be so complicated. I'm sure I'm not the first to want something like this. Is there any other possibility?
If you want to try out how it behaves with the very basic minimum of code, have you tried just deriving from
QSqlTableModel
and overriding itsdata(Qt::DisplayRole)
to return "No image available" string when column is pixmap blob but has valueNULL
instead of the blob/image? It's not ideal but maybe it will work for your "simple" desire? I don't know how that will relate to yourQDataWidegtMapper
situation.... -
@JonB said in Set text to QLabel if no Image from QSqlTableModel (QDataWidgetMapper) is available:
I reiterate: I do not recognise your
if the QModelIndex imageIndex has the following value: QModelIndex(-1,-1,0x0,QObject(0x0)). That is, if no index exists.
I had output this information from the following function via qDebug()). This appears exactly then if I select a data record with which no picture was deposited.
void MainWindow::dataIndexChanged(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); QModelIndex galleryImageIndex; QModelIndex index = selected.indexes().first(); int fungusId = mFungusTableModel->data(index.siblingAtColumn(0)).toInt(); QByteArray galleryImage = mFungusTableModel->data(index.siblingAtColumn(8)).toByteArray(); mImageFilterModel->setIdFilter(fungusId); int numberOfImages = mImageFilterModel->rowCount(); for(int imageRow=0; imageRow<=numberOfImages; imageRow++){ QModelIndex imageIndex = mImageFilterModel->index(imageRow,1); QModelIndex sourceIndex = mImageFilterModel->mapToSource(imageIndex); if(!imageIndex.isValid()){; break; } QByteArray image = mImageFilterModel->data(imageIndex.siblingAtColumn(1)).toByteArray(); if(image == galleryImage){ galleryImageIndex = mImageFilterModel->index(imageRow,0); break; } } mDataMapper->setCurrentModelIndex(index); mImageMapper->setCurrentModelIndex(galleryImageIndex); }
@JonB said in Set text to QLabel if no Image from QSqlTableModel (QDataWidgetMapper) is available:
database -> QSqlTableModel -> QIdentityProxyModel -> QSortFilterProxyModel -> view
database -> QSqlTableModel -> QSortFilterProxyModel -> QIdentityProxyModel -> viewOkay again for dummies to write down. I have now done the following.
I made a class called
ImageProxyModel
. This class looks like:#include "imageproxymodel.h" ImageProxyModel::ImageProxyModel(QObject *parent) : QIdentityProxyModel{parent} { } QVariant ImageProxyModel::data(const QModelIndex &index, int role) const { auto imageColumnNumber = 1; if(!index.isValid()) return QVariant(); QVariant v(QIdentityProxyModel::data(index, role)); if (role == Qt::DisplayRole && index.column() == imageColumnNumber) if (!v.isValid()) v = "No image available"; return v; }
So my
ImageFilterModel
class looks like this:#include "imagefiltermodel.h" ImageFilterModel::ImageFilterModel(){} ImageFilterModel::~ImageFilterModel() { qDebug() << "ImageFilterModel deleted"; } void ImageFilterModel::setIdFilter(const int &id) { if(mIdFilterValue != id) { mIdFilterValue = id; emit invalidateFilter(); } } bool ImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_UNUSED(source_parent) if(mIdFilterValue == -1){ return true; } else { const int id = sourceModel()->index(source_row, mIdColumn).data().toInt(); return (id == mIdFilterValue); } }
In the constructor of the mainwindow.cpp I do the following:
mImageFilterModel = new ImageFilterModel; mImageProxyModel = new ImageProxyModel(this); mImageTableModel = mDatabaseManager->imageTableModel(); // mImageTableModel = QSqlRelationalTableModel mImageProxyModel->setSourceModel(mImageTableModel); mImageFilterModel->setSourceModel(mImageProxyModel); mImageMapper->setModel(mImageFilterModel); mImageMapper->setItemDelegate(new ImageDelegate(mImageMapper)); // mImageMapper = QDataWidgetMapper mImageMapper->addMapping(ui->imageView, mImageTableModel->fieldIndex("Bild"));
And my
ImageDelegate
class looks like this:ImageDelegate::ImageDelegate(QObject *parent): QItemDelegate(parent) {} ImageDelegate::~ImageDelegate() { qDebug() << "ImageDelegate deleted"; } void ImageDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QLabel *label = qobject_cast<QLabel *>(editor); if (label) { QByteArray imageData = index.data(Qt::EditRole).toByteArray(); QPixmap pixmap; if (pixmap.loadFromData(imageData)){ int width = label->width(); int height = label->height(); label->setPixmap(pixmap.scaled(width,height,Qt::KeepAspectRatio)); } } QItemDelegate::setEditorData(editor, index); } void ImageDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QLabel *label = qobject_cast<QLabel *>(editor); if (label) { QBuffer buffer; buffer.open(QIODevice::WriteOnly); if (label->pixmap(Qt::ReturnByValue).save(&buffer)) model->setData(index, buffer.data(), Qt::EditRole); } }
If I select a record from my QListView the function dataIndexChanged is called (see above).
Now the result of the current state: Image selection works as expected, but if no image is stored in the database, the last selected image remains stored in the QLabel instead of the text "No Image available".
So where is our thinking error? What have I possibly implemented incorrectly? Can you please look over it again?
Thanks for all the support! Without you I would be lost.
-
Hi,
You do not set the text on the label. You just change the image if you get a valid image.
-
Hi,
You do not set the text on the label. You just change the image if you get a valid image.
@SGaist
Can you please tell me in which function this is missing? Am slowly despairing... -
setEditorData
-
@SGaist
That is exactly my problem. When I select a data set from my QListView that does not contain an image, it no longer jumps into this function. -
Might be a silly question but how do you know that ?
-
@SGaist The debugger does not jump to this function. I can make a breakpoint in the setEditorData. As soon as I select a record with an image it jumps into the function and I can debug the whole thing. If I select a dataset that does not contain an image it does not jump into the setEditorData function.
Now the function currently looks like this and it still doesn't work.
void ImageDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QLabel *label = qobject_cast<QLabel *>(editor); if (label) { QByteArray imageData = index.data(Qt::EditRole).toByteArray(); QPixmap pixmap; if (pixmap.loadFromData(imageData)){ int width = label->width(); int height = label->height(); label->setPixmap(pixmap.scaled(width,height,Qt::KeepAspectRatio)); }else{ label->setText("Bla"); } } QItemDelegate::setEditorData(editor, index); }
-
What if you have only ImageProxyModel between your mapper and model ?
-
@SGaist
Now I have the follow in my constructor of mainwindowmImageTableModel = mDatabaseManager->imageTableModel(); // mImageTableModel = QSqlRelationalTableModel mImageProxyModel->setSourceModel(mImageTableModel); mImageMapper->setModel(mImageProxyModel); mImageMapper->setItemDelegate(new ImageDelegate(mImageMapper)); // mImageMapper = QDataWidgetMapper mImageMapper->addMapping(ui->imageView, mImageTableModel->fieldIndex("Bild"));
And my dataIndexChanged method
void MainWindow::dataIndexChanged(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); QModelIndex galleryImageIndex; QModelIndex index = selected.indexes().first(); int fungusId = mFungusTableModel->data(index.siblingAtColumn(0)).toInt(); QByteArray galleryImage = mFungusTableModel->data(index.siblingAtColumn(8)).toByteArray(); // mImageFilterModel->setIdFilter(fungusId); int numberOfImages = mImageProxyModel->rowCount(); // int numberOfImages = mImageFilterModel->rowCount(); for(int imageRow=0; imageRow<=numberOfImages; imageRow++){ QModelIndex imageIndex = mImageProxyModel->index(imageRow,1); // QModelIndex imageIndex = mImageFilterModel->index(imageRow,1); // QModelIndex sourceIndex = mImageFilterModel->mapToSource(imageIndex); if(!imageIndex.isValid()){; break; } // QByteArray image = mImageFilterModel->data(imageIndex.siblingAtColumn(1)).toByteArray(); QByteArray image = mImageProxyModel->data(imageIndex.siblingAtColumn(1)).toByteArray(); if(image == galleryImage){ // galleryImageIndex = mImageFilterModel->index(imageRow,0); galleryImageIndex = mImageProxyModel->index(imageRow,0); break; } } mDataMapper->setCurrentModelIndex(index); mImageMapper->setCurrentModelIndex(galleryImageIndex);
Unfortunately, this does not work. I am missing the filtering for the corresponding data set to display only the corresponding images.
-
I have found a way the whole thing seems to work. However, I don't know if it's clean or if it can lead to difficulties, since I'm working with Model / View. Maybe you two can take a look at it. Thanks for your active support!
void MainWindow::dataIndexChanged(const QItemSelection &selected, const QItemSelection &deselected) { Q_UNUSED(deselected); QModelIndex galleryImageIndex; QModelIndex index = selected.indexes().first(); int fungusId = mFungusTableModel->data(index.siblingAtColumn(0)).toInt(); QByteArray galleryImage = mFungusTableModel->data(index.siblingAtColumn(8)).toByteArray(); mImageFilterModel->setIdFilter(fungusId); int numberOfImages = mImageFilterModel->rowCount(); if(numberOfImages != 0){ for(int imageRow=0; imageRow<=numberOfImages; imageRow++){ QModelIndex imageIndex = mImageFilterModel->index(imageRow,1); if(!imageIndex.isValid()){; break; } QByteArray image = mImageFilterModel->data(imageIndex.siblingAtColumn(1)).toByteArray(); if(image == galleryImage){ galleryImageIndex = mImageFilterModel->index(imageRow,0); break; } } mImageMapper->setCurrentModelIndex(galleryImageIndex); } else { ui->imageView->setText("No Image available"); } mDataMapper->setCurrentModelIndex(index); }