Reading image from QSqlTableModel



  • Hi,
    I'm trying to read an image from an SQLite db using QSqlTableModel (and display it in a TableView). In the delegate I have the following code:

    void FixViewDelegate::setModelData(QWidget* editor, QSqlTableModel* fixModel, const QModelIndex& index) const {
    
      Q_UNUSED(editor);
      Q_UNUSED(index);
    
      QPixmap fixPic;
      fixPic.loadFromData (fixModel->record (1).value ("Pic").toByteArray ());
    
      qDebug() << "Fixmodel pic: " << fixPic;
      qDebug() << "Fixmodel pic size: " << fixPic.size ();
    
    }
    
    

    I keep getting the following message:
    QPixmap::scaled: Pixmap is a null pixmap
    Wgat did I miss? Thank you for your help.



  • Hi, apparently loadFromData fails.
    You have hardcoded fixModel->record(1) - are you sure the data is there? In row number one?
    Rows are numbered in zero-based manner.
    Other problem might be that field "Pic" returns invalid value.



  • Hi @artwaw ,
    The data is there. There is an image in each record in the Pic field. Is it the correct way I'm trying to load the image?
    Thank you.



  • @gabor53 Actually in the method you posted here there should not be any hardcoded values. I would post rather elaborate answer a bit later in the evening, I am commuting now.



  • @artwaw
    Thank you. I would appreciate that. Also I assigned the delegate to the view like this:

    
      QSqlTableModel* fixModel = new QSqlTableModel(this);
      fixModel->setTable ("Items");
      fixModel->setEditStrategy (QSqlTableModel::OnFieldChange);
      fixModel->setSort (2, Qt::DescendingOrder);
    
      fixModel->select ();
    
      ui->tableView_Fix->setItemDelegateForColumn(3, new FixViewDelegate (this));
    

    The goal would be to get the delegate draw the image each time.


  • Lifetime Qt Champion

    Hi,

    How did you store the image data in your database ?



  • Hi @SGaist ,
    I store them as a QByteArray:

    QPixmap pix2(fileNameChosen);
      int w = 0;
      int h = 0;
      w = ui->Image_Display_Label->width ();
      h = ui->Image_Display_Label->height ();
      ui->Image_Display_Label->setPixmap (pix2.scaled(w, h, Qt::KeepAspectRatio));
    
      QFile fileReview(fileNameChosen);
    
      if(fileReview.open (QIODevice::ReadOnly)) {
        fileByteArray = fileReview.readAll ();
    

  • Moderators

    @gabor53 What @SGaist probably means is: what data type do you use for the pixmap column in the table in the database?



  • Hi @jsulm ,
    It's BLOB.



  • @gabor53 ,

    What is the size of the bytearray?



  • @Vinod-Kuntoji
    100 x 100



  • @gabor53 ,
    The blob you are using, is it a raw bytearray or png, jpeg byterray?



  • @Vinod-Kuntoji
    It is jpeg bytearray.



  • @gabor53 ,

    Then you should specify "JPG" in loadFromData function.

    QPixmap fixPic;
    fixPic.loadFromData (fixModel->record (1).value ("Pic").toByteArray (),"JPG");



  • @Vinod-Kuntoji
    Thank you. I've noticed an other issue: the program execution enters fixviewdelegate.cpp but never reads the actual function:

    void FixViewDelegate::setModelData(QWidget* editor, QSqlTableModel* fixModel, const QModelIndex& index) const {
    
      Q_UNUSED(index);
      Q_UNUSED(editor);
    
      qDebug() << "Entered fixViewDelegate (2).";
    
      QPixmap fixPic;
      fixPic.loadFromData (fixModel->record (1).value ("Pic").toByteArray (), "JPG");
      qDebug() << "Fixmodel pic: " << fixPic;
      qDebug() << "Fixmodel pic size: " << fixPic.size ();
    
    }
    
    

    What can I do to fix this problem?



  • @gabor53 said in Reading image from QSqlTableModel:

    execution

    What is that function?


  • Moderators

    @gabor53
    what is output of the following code in the console:

    qDebug() << QImageReader::supportedImageFormats();
    

    Also on what system are you running your application?



  • Hi @raven-worx ,

    The output is

    ("bmp", "cur", "dds", "gif", "icns", "ico", "jpeg", "jpg", "pbm", "pgm", "png", "ppm", "svg", "svgz", "tga", "tif", "tiff", "wbmp", "webp", "xbm", "xpm").
    I run Qt 5.8 on Windows 10.


  • Moderators

    @gabor53
    ok that at least ensures you can read jpg images.
    Now the only possibility is that the data you retrieve from the database isn't valid imagedata.

    QByteArray ba = fixModel->record (1).value ("Pic").toByteArray ();
    qDebug() << ba.size() << ba;
    


  • @raven-worx
    I added it to the

    void FixViewDelegate::setModelData(QWidget* editor, QSqlTableModel* fixModel, const QModelIndex& index) const {
    
    

    function but it doesnt display anything. I know program execution goes from fixdb.cpp to FixViewDelegate, but it does nothing with setModelData. As this delegate supposed to handle displaying the image without clicking on the table I think something is missing. How can I render the image using this delegate each time the tableView is displayed?
    The delegate so far looks like this:

    #include "fixviewdelegate.h"
    
    FixViewDelegate::FixViewDelegate(QObject* parent) : QStyledItemDelegate(parent) {
      qDebug() << "Entered fixViewDelegate (1).";
    }
    
    void FixViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    
      Q_UNUSED(painter);
      Q_UNUSED(option);
      Q_UNUSED(index);
    }
    
    QSize FixViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
    
      Q_UNUSED(option);
      Q_UNUSED(index);
    
    }
    
    void FixViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
    
      Q_UNUSED(editor);
      Q_UNUSED(index);
    
    }
    
    void FixViewDelegate::setModelData(QWidget* editor, QSqlTableModel* fixModel, const QModelIndex& index) const {
    
      Q_UNUSED(index);
      Q_UNUSED(editor);
    
    
      qDebug() << "Entered fixViewDelegate (2).";
      QByteArray ba = fixModel->record (1).value ("Pic").toByteArray ();
      qDebug() << ba.size() << ba;
    
    //  qDebug() << "Fixmodel pic: " << fixPic;
    //  qDebug() << "Fixmodel pic size: " << fixPic.size ();
    
    }
    
    
    

    Thank you for your help.


  • Moderators

    @gabor53
    2 reasons your csetModelData() isn't called:

    1. the correct signatur for setModelData() would be: void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
    2. setModelData() is used as the name implies to set data in the model. Means when the editor has finished editing and wants to save

    the correct method to reimplement is the delegates paint() and sizeHint() methods. In there you check if the column is your image column and do the work appropriately, else just call the base class implementation.



  • @raven-worx
    Thank you. I'm working on it.



  • @raven-worx
    I believe in the paint() method I need to use

    void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
    

    How can I get the pixmap out of the model?



  • @gabor53 of course. Model's data() method returns QVariant, you can get QByteArray this way.



  • This post is deleted!


  • @artwaw
    The delegate's paint looks like this:

    void FixViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    

    I can get the index of the item from QModelIndex& index, but as there is no model, how can I get the QByteArray from the db (or model)?
    Thank you.



  • @artwaw
    As I have no access to the model, is it OK to use a query to get the bytearray from the model?


  • Lifetime Qt Champion

    Index is your point of access to the model. See QModelIndex::data.



  • @SGaist
    I tried the following:

    QVariant fixImg;
    
      fixImg = index.data (Qt::DisplayRole);
    
      QPixmap pixMap2;
      pixMap2 = fixImg.value<QPixmap>();
    
      qDebug() << "pixMap2 size: " << pixMap2.size ();
      qDebug() << "pixMap2 width: " << pixMap2.width ();
    
    

    No error message, but the size is 0. Did I miss a step?
    Thank you.


  • Lifetime Qt Champion

    Do you store a QPixmap in your model for that role ?



  • It's a QByteArray.



  • @SGaist
    I ran

     QVariant fixImg(index.data (Qt::EditRole));
    
      qDebug() << "QVariant type: " << fixImg.type ();
    

    and the result was
    QVariant type: QVariant::QString


  • Moderators

    @gabor53 said in Reading image from QSqlTableModel:

    It's a QByteArray.

    QByteArray of what? What and how are you storing in the DB? What is the data type of the corresponding column?



  • @jsulm
    QByteArray of the original image. The data type of that column is BLOB.


  • Moderators

    @gabor53
    i asked in a post before:

    QByteArray ba = fixModel->record (1).value ("Pic").toByteArray ();
    qDebug() << ba.size() << ba;
    

    in your delegates paint() method (if really a QByteArray is returned) do the following:

    if( index.column() == NUMBER_OF_PIXMAP_COLUMN )
    {
          QByteArray ba = index.data( ROLE_USED_IN_MODEL ).toByteArray();
         QPixmap pix;
            pix.loadFromData ( ba );
         painter->save();
             painter->translate( option.rect.topLeft() );
             painter->drawPixmap( pix );
         painter->restore();
    }
    

    I you should probably post your model code to avoid further guessing.



    • I don't like index.column() == NUMBER_OF_PIXMAP_COLUMN as it ties the delegate to a single model so I consider it bad design, view->setItemDelegateForColumn() should be used instead.
    • index.data( ROLE_USED_IN_MODEL ) it's a QSqlTableModel so just delete ROLE_USED_IN_MODEL and use the default
    • It's a QStyledItemDelegate so let's use style
    void FixViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    QPixmap loadedImage;
    loadedImage.loadFromData(index.data().toByteArray());
    const QWidget *widget = option.widget;
    QStyle *style = widget ? widget->style() : QApplication::style();
    style->drawItemPixmap(painter,option.rect,Qt::AlignCenter,loadedImage);
    }
    


  • This post is deleted!


  • @VRonin
    Thank you. It runs without error, but paint nothing in the view.



  • How do you save your image in the database? do you save it via Qt? can you show us the save part of the code?



  • @VRonin
    Sure. I also added

     qDebug() << "loadedImage size: " << loadedImage.size ();
    

    and the result is
    loadedImage size: QSize(0, 0)

    I save the image via Qt like this:

    #include "review.h"
    #include "ui_review.h"
    
    Review::Review(QWidget* parent) :
      QDialog(parent),
      ui(new Ui::Review) {
      ui->setupUi(this);
    
      connect(this, &Review::RecAdded, this, &Review::updateTable);
    
    }
    
    Review::~Review() {
      delete ui;
    }
    
    void Review::dispRev(QString sID, QString& name, QString& whatChosen, QString& fileNameChosen, QString& materialChosen, QString& colorChosen, QString& description, QDate& adoptDate, QString& SignedbyChosen, QString& history, QString& age, QString& notesTemp) {
      name = name.simplified ();
      description = description.simplified ();
    
      ui->ID_display_Label->setText (sID);
      ui->Name_Disp_Label->setText (name);
      ui->What_Display_Label->setText (whatChosen);
      ui->MadeOf_Disp_Label->setText (materialChosen);
      ui->Color_Disp_Label->setText (colorChosen);
      ui->textBrowser_Descr->setText (description);
      adoptDateStr = adoptDate.toString ("MM/dd/yyyy");
      ui->AdoptionDate_Disp_Label->setText (adoptDateStr);
      ui->SignedBy_Disp_label->setText (SignedbyChosen);
      ui->textBrowser_History->setText (history);
      ui->Age_Display_Label_2->setText (age);
      ui->textBrowser_Notes->setText (notesTemp);
    
    
      QPixmap pix2(fileNameChosen);
      int w = 0;
      int h = 0;
      w = ui->Image_Display_Label->width ();
      h = ui->Image_Display_Label->height ();
      ui->Image_Display_Label->setPixmap (pix2.scaled(w, h, Qt::KeepAspectRatio));
    
      QFile fileReview(fileNameChosen);
    
      if(fileReview.open (QIODevice::ReadOnly)) {
        fileByteArray = fileReview.readAll ();
      }
    
      nameReview = name;
      whatReview = whatChosen;
      fileNameReview = fileNameChosen;
      materialReview = materialChosen;
      colorReview = colorChosen;
      descriptionReview = description;
      adoptDateReview = adoptDate;
      SignedbyReview = SignedbyChosen;
      historyReview = history;
      sIDReview = sID;
      ageReview = age;
      notesReview = notesTemp;
    
    }
    
    
    void Review::on_pushButton_Add_to_DB_clicked() {
    
    //    date = adoptDateReview.toString ("MM/dd/yyyy");
      qDebug() << "date in review.cpp: " << date;
      QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE", "writedb");
      db.setDatabaseName (fileQstring);
    
      QSqlQuery querys(db);
    
      if(!db.open ())
    
      {
        qDebug() << "The database is not open (submit)!";
      } else {
        qDebug() << "The database is open (submit)!";
      }
      querys.prepare("INSERT INTO Items (ID, Name, Pic, Description, AdoptDate, History, Age, Notes, Color, Material, Signed, What) VALUES(:ID, :Name, :Pic, :Description, :AdoptDate, :History, :Age, :Notes, :Color, :Material, :Signed, :What)" );
      querys.bindValue (":ID", sIDReview);
      querys.bindValue (":Name", nameReview);
      querys.bindValue (":Pic", fileByteArray);
      querys.bindValue (":Description", descriptionReview);
      querys.bindValue (":AdoptDate", adoptDateStr);
      querys.bindValue (":History", historyReview);
      querys.bindValue (":Age", ageReview);
      querys.bindValue (":Notes", notesReview);
      querys.bindValue (":Color", colorReview);
      querys.bindValue (":Material", materialReview);
      querys.bindValue (":Signed", SignedbyReview);
      querys.bindValue (":What", whatReview);
    
      bool result = querys.exec ();
    
      if(!result) {
        qDebug() << "Error inserting into the main db!" << querys.lastError ();
    
        QMessageBox::warning (this, "Add to Database Warning", "<b><font size='16' color='red'>Error 1002: The Friend was not added to the database.");
    
      } else {
        qDebug() << "Entered FunctAdd OK loop.";
    
        QMessageBox::information (this, "Confirmation", "<b><font size = '16' color = 'green'>The Friend was added to the database.</font>");
    
    
    
        emit RecAdded ();
      }
    }
    
    
    void Review::on_pushButton_Fix_clicked() {
      Additem* mAdditem = new Additem(this);
      mAdditem->FixFriend (sIDReview, nameReview, whatReview, fileNameReview, materialReview, colorReview, descriptionReview, date, SignedbyReview, historyReview, ageReview, notesReview);
    
    
      mAdditem->show ();
    }
    
    
    void Review::updateTable() {
      qDebug() << "Entered updateTable!";
      MainWindow* mMainWindow = new MainWindow(this);
    
      mMainWindow->Addview ();
      mMainWindow->show ();
    }
    
    

    Data in the db is stored as BLOB.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.