Replacing image in QStyledItemDelegate



  • I have a QStyledItemDelegate and I use its editor to edit data in a database. One of my fields in the db is a BLOB storing an image. The image appears in the tableview managed by the delegate. How can I switch the image to an other one using a delegate? (The point would be that when the user figures out that the wrong image was linked to the record give her an opportunity to change the image without deleting the whole record.)
    Thank you.



  • I think you have to reimplement
    void YourItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    function. You may need QApplication::style()->drawControl(QStyle::CE_Control, &button, painter); to allow user interacts with item so that she can change the im
    age.


  • Moderators

    @samdol said in Replacing image in QStyledItemDelegate:

    You may need QApplication::style()->drawControl(QStyle::CE_Control, &button, painter); to allow user interacts with item so that she can change the image.

    Sorry but that is not true. As the method-name already implies, this only draws a control. So no interaction handling.

    To change the icon persistently you need to update the icon in the model - e.g. by using setData(index, QVariant::fromValue<QPixmap>(...), Qt::DecorationRole). If the model is correctly implemented the icon is updated automatically.

    If you just want to paint a different icon but leave the actual data unchanged do this:

    void MyItemDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
    {
              QStyledItemDelegate::initStyleOption(option, index);
    
              if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option))  {
                       if( v4->features & QStyleOptionViewItemV2::HasDecoration )
                                v4->icon = QIcon(...);
              }
    }
    


  • @raven-worx
    Thank you. I actually want to change the icon and update the database with that icon.



  • @raven-worx
    My original idea was that when the image field is chosen I replace the original image with a QPushbutton. When the button is clicked it opens QFile and lets the user choose a different picture. Than the icon in the view is changed to the new image and the new image is saved into the db.


  • Moderators

    @gabor53
    you can do this by creating a custom editor widget in createEditor(). Save the filepath (e.g. with setProperty("file-path")on the pushbutton, and read it again on save in setModelData(). In there you call model->setData().
    If not already done you of course need to implement setData() in your model to save the value (image,...) back to the DB.



  • @raven-worx
    I created the button in createEditor().

                QPushButton *button = new QPushButton(parent) ;
                button->setMaximumWidth (100);
    

    In setEditorData() I have

       QPushButton *button = qobject_cast<QPushButton*>(editor);
        if(button)
            {
                button->setIcon (QIcon("C:/Programming/Projects/Folkfriends_1_0/icons/fix.png"));
            }
    

    .At this point I think I should have a button if the user clicks on the image but after clicking on the image I get a textEditor. What did I miss? Thank you.


  • Moderators

    @gabor53
    show the whole createEditor() method pls.



  • @raven-worx
    I found the problem. The correct code is

     QPushButton *button = qobject_cast<QPushButton*>(editor);
        if(button)
            {
                button->setIcon (QIcon("C:/Programming/Projects/Folkfriends_1_0/icons/fix.png"));
    return button;
            }
    

    I missed the return...



  • @raven-worx
    My next step (as I have the button now) is to place the original image on the button.
    In setEditorData I have the following:

    QPushButton *button = qobject_cast<QPushButton*>(editor);
        if(button)
            {            
                QPixmap buttonPix;
                buttonPix.loadFromData (index.model ()->data (index,Qt::DisplayRole).toByteArray ());
    
                qDebug() << "Fix image size: " << buttonPix.size();
    
                button->setIcon (QIcon(buttonPix));
    
            }
    

    I hoped to create a QPixmap from the BLOB in the database located where the index points. I wanted to place the pixmap on the button as an icon. The button is still there but the original image is not on the button and I also got the message
    Fix image size: QSize(0, 0)
    which shows my QPixmap is empty. What step did I miss? Thank you.


  • Moderators

    @gabor53 said in Replacing image in QStyledItemDelegate:

    I missed the return...

    yes, i was suspecting that.

    @gabor53 said in Replacing image in QStyledItemDelegate:

    I hoped to create a QPixmap from the BLOB in the database located where the index points

    basically your code looks correct.
    Whats the image format of the image blob?
    Does your model's data() method really return a QByteArray for the Qt::DisplayRole?
    Please show your data() implementation.



  • @raven-worx
    The image format is jpg.
    I believe the model's data() method returns a QByteArray, but here is the code:
    The function that saves the image to the db:

    QFile fileReview(fileNameChosen);
    
        if(fileReview.open (QIODevice::ReadOnly))
            {
                fileByteArray = fileReview.readAll ();
            }
    
    QFile fileReview(fileNameChosen);
    
        if(fileReview.open (QIODevice::ReadOnly))
            {
                fileByteArray = fileReview.readAll ();
            }
    

    The model's data() implementation:

     QStandardItemModel *fixModel = new QStandardItemModel(this);
        ui->tableView_Fix->setModel (fixModel);
    
        for(int row1 = 0; query_fix.next (); row1++)
            {
                if(row1 == 0)
                    {
                        const QSqlRecord qRec = query_fix.record();
                        qDebug() << "The number of records (MainWindow): " << qRec;
                        fixModel->insertColumns (0, qRec.count());
                        qDebug() << "fixdb record count: " << qRec.count ();
                    }
    
                fixModel->insertRow (row1);
                fixModel->setData (fixModel->index (row1,0),query_fix.value (0));
                fixModel->setData (fixModel->index (row1,1),query_fix.value (1));
                fixModel->setData (fixModel->index (row1,2), query_fix.value (13));
    
                fixPixmap.loadFromData (query_fix.value (2).toByteArray ());
                fixPixmap = fixPixmap.scaled (100,100,Qt::KeepAspectRatio);
    
                fixModel->setData (fixModel->index (row1,3),fixPixmap,Qt::DecorationRole);
                fixModel->setData (fixModel->index (row1,4),query_fix.value (11));
                fixModel->setData (fixModel->index (row1,5),query_fix.value (10));
                fixModel->setData (fixModel->index (row1,6),query_fix.value (3));
                fixModel->setData (fixModel->index(row1,7),query_fix.value (4));
                fixModel->setData (fixModel->index (row1,8),query_fix.value (12));
                fixModel->setData (fixModel->index (row1,9),query_fix.value (7));
                fixModel->setData (fixModel->index (row1,10),query_fix.value (8));
                fixModel->setData (fixModel->index (row1,11),query_fix.value (9));
    
                ui->tableView_Fix->setRowHeight (row1,100);
            }
    
    

    Thank you.



  • @raven-worx
    I also noticed, that for some reason all the images are saved 45 degrees turned right so all the vertical images are horizontal.



  • Ran the debugger and got the following at this line:

         QPixmap buttonPix;
                buttonPix.loadFromData (index.model ()->data (index,Qt::DisplayRole).toByteArray ());
    

    In the Locals and Expressions window I got the following Name - Value - Type values:
    buttonPix - (invalid) - QPixmap.
    I'm wondering why is it invalid? (Or what can make it invalid?)
    Thank you.


  • Moderators

    @gabor53
    you are already returning a QPixmap (fixModel->setData (fixModel->index (row1,3),fixPixmap,Qt::DecorationRole);) not a QByteArray



  • @raven-worx
    I tried to use

    buttonPix.loadFromData (index.model ()->data (index,Qt::DisplayRole).toByteArray ());
    

    without toByteArray() but it didn't work. I assumed that the model stores the data as a QVariant so I tried to do the following:

    QPixmap buttonPix;
                QVariant pic;
                pic = (index.data (Qt::DisplayRole));
                buttonPix.loadFromData (pic.toByteArray());
    
                button->setIcon (QIcon(buttonPix));
    
                int row = index.row ();
                int col = index.column ();
    
                qDebug() << "SetEditorData row, col: " << "(" << row << "," << col << ")";
    
                qDebug() << "Fix image size: " << buttonPix.size();          
    
                return;
    
    

    and the message I got was identical to the previous one:
    QPixmap::scaled: Pixmap is a null pixmap
    SetEditorData row, col: ( 1 , 3 )
    Fix image size: QSize(0, 0)

    After running Debug at the

      QPixmap buttonPix;
    
    

    line the buttonPix value was buttonPix (481622520x389579424) QPixmap
    which changed to buttonPix (Invalid) QPixmap at the QVariant pic line. What am I missing here? Is this a completely incorrect idea? Thank you.


Log in to reply
 

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