Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Changing an image using QStyledItemDelegate in TableView
Forum Update on Monday, May 27th 2025

Changing an image using QStyledItemDelegate in TableView

Scheduled Pinned Locked Moved Unsolved General and Desktop
21 Posts 4 Posters 5.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gabor53
    wrote on last edited by
    #1

    Hi,

    My goal is to replace an image in a tableview using a delegate by clicking on a button which opens a QFileDialog. So far:

    • I created an editor (a button) in createEditor;

    • in setEditorData the QFileDialog opens and stores the chosen file name.
      I want to use this file name in setModelData to get the pixmap and update the model and the database. I don't seem to able to transfer the data between setEditorData and setModelData. How am I supposed to do this correctly?
      Thank you.

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      Separate the editor from the delagate.

      Editor (imagepickbutton.h):

      #include <QWidget>
      #include <QPushButton>
      #include <QIcon>
      #include <QFileDialog>
      class ImagePickButton : public QWidget{
          Q_OBJECT
          Q_DISABLE_COPY(ImagePickButton)
      public:
          explicit ImagePickButton(QWidget* parent=Q_NULLPTR):QWidget(parent){
              m_mainButton=new QPushButton(tr("Select Image"),this);
              QHBoxLayout* mainLay=new QHBoxLayout(this);
              mainLay->addWidget(m_mainButton);
              connect(m_mainButton,&QPushButton::clicked,this,&ImagePickButton::selectImageFile);
          }
          const QString& selectedFile() const {return m_selectedFile;}
          void setSelectedFile(const QString& val){
              if(m_selectedFile==val)
                  return;
              m_selectedFile=val;
              if(m_selectedFile.isEmpty()){
                  m_mainButton->setText(tr("Select Image"));
                  m_mainButton->setIcon(QIcon());
              }
              else{
                  m_mainButton->setText(QString());
                  m_mainButton->setIcon(QIcon(m_selectedFile));
              }
              emit selectedFileChanged(m_selectedFile);
          }
      protected slots:
          void selectImageFile(){
              const QString newFile=QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), tr("Images (*.png *.xpm *.jpg)"));
              if(!newFile.isEmpty())
                  setSelectedFile(newFile);
          }
      signals:
          void selectedFileChanged(const QString& fileName);
      private:
          QString m_selectedFile;
          QPushButton* m_mainButton;
      };
      

      Delegate (imagedelegate.h):

      #include "imagepickbutton.h"
      #include <QStyledItemDelegate>
      #include <QModelIndex>
      class ImageDelegate : public QStyledItemDelegate{
          Q_OBJECT
          Q_DISABLE_COPY(ImageDelegate)
      public:
          explicit ImageDelegate (QObject *parent = Q_NULLPTR) : QStyledItemDelegate(parent){}
          virtual QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
              Q_UNUSED(option);
              Q_UNUSED(index);
              return new ImagePickButton(parent);
          }
          virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE{
              ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
              Q_ASSERT(imgPick);
              imgPick->setSelectedFile(index.data(Qt::UserRole).toString());
          }
          virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE{
              ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
              Q_ASSERT(imgPick);
              if(imgPick->selectedFile().isEmpty()){
                      model->setData(index,QVariant(),Qt::UserRole);
                      model->setData(index, QVariant(),Qt::DecorationRole);
              }else{
                      model->setData(index,imgPick->selectedFile(),Qt::UserRole);
                      model->setData(index, QIcon(imgPick->selectedFile()),Qt::DecorationRole);
              }
          }
          virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
              Q_UNUSED(index);
              editor->setGeometry(option.rect);
          }
      };
      

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      G 1 Reply Last reply
      2
      • VRoninV VRonin

        Separate the editor from the delagate.

        Editor (imagepickbutton.h):

        #include <QWidget>
        #include <QPushButton>
        #include <QIcon>
        #include <QFileDialog>
        class ImagePickButton : public QWidget{
            Q_OBJECT
            Q_DISABLE_COPY(ImagePickButton)
        public:
            explicit ImagePickButton(QWidget* parent=Q_NULLPTR):QWidget(parent){
                m_mainButton=new QPushButton(tr("Select Image"),this);
                QHBoxLayout* mainLay=new QHBoxLayout(this);
                mainLay->addWidget(m_mainButton);
                connect(m_mainButton,&QPushButton::clicked,this,&ImagePickButton::selectImageFile);
            }
            const QString& selectedFile() const {return m_selectedFile;}
            void setSelectedFile(const QString& val){
                if(m_selectedFile==val)
                    return;
                m_selectedFile=val;
                if(m_selectedFile.isEmpty()){
                    m_mainButton->setText(tr("Select Image"));
                    m_mainButton->setIcon(QIcon());
                }
                else{
                    m_mainButton->setText(QString());
                    m_mainButton->setIcon(QIcon(m_selectedFile));
                }
                emit selectedFileChanged(m_selectedFile);
            }
        protected slots:
            void selectImageFile(){
                const QString newFile=QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), tr("Images (*.png *.xpm *.jpg)"));
                if(!newFile.isEmpty())
                    setSelectedFile(newFile);
            }
        signals:
            void selectedFileChanged(const QString& fileName);
        private:
            QString m_selectedFile;
            QPushButton* m_mainButton;
        };
        

        Delegate (imagedelegate.h):

        #include "imagepickbutton.h"
        #include <QStyledItemDelegate>
        #include <QModelIndex>
        class ImageDelegate : public QStyledItemDelegate{
            Q_OBJECT
            Q_DISABLE_COPY(ImageDelegate)
        public:
            explicit ImageDelegate (QObject *parent = Q_NULLPTR) : QStyledItemDelegate(parent){}
            virtual QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                Q_UNUSED(option);
                Q_UNUSED(index);
                return new ImagePickButton(parent);
            }
            virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE{
                ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
                Q_ASSERT(imgPick);
                imgPick->setSelectedFile(index.data(Qt::UserRole).toString());
            }
            virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE{
                ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
                Q_ASSERT(imgPick);
                if(imgPick->selectedFile().isEmpty()){
                        model->setData(index,QVariant(),Qt::UserRole);
                        model->setData(index, QVariant(),Qt::DecorationRole);
                }else{
                        model->setData(index,imgPick->selectedFile(),Qt::UserRole);
                        model->setData(index, QIcon(imgPick->selectedFile()),Qt::DecorationRole);
                }
            }
            virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                Q_UNUSED(index);
                editor->setGeometry(option.rect);
            }
        };
        
        G Offline
        G Offline
        gabor53
        wrote on last edited by
        #3

        @VRonin
        Thank you. I'm supposed to do this in the cpp file right?

        VRoninV 1 Reply Last reply
        0
        • G gabor53

          @VRonin
          Thank you. I'm supposed to do this in the cpp file right?

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by mrjj
          #4

          Those are two header files but you could (and should, for efficiency) split them in .h and .cpp

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          G 1 Reply Last reply
          0
          • VRoninV VRonin

            Those are two header files but you could (and should, for efficiency) split them in .h and .cpp

            G Offline
            G Offline
            gabor53
            wrote on last edited by
            #5

            @VRonin
            I've started to implement it. I created a c++ class with .h and .cpp for the editor.
            My .h file looks like this:

            #ifndef IMAGEPICKBUTTON_H
            #define IMAGEPICKBUTTON_H
            
            #include <QObject>
            #include <QWidget>
            #include <QPushButton>
            #include <QHBoxLayout>
            
            class ImagePickButton : public QWidget
            {
                Q_OBJECT
                Q_DISABLE_COPY (ImagePickButton)
            
            public:
                explicit ImagePickButton(QWidget *parent = Q_NULLPTR);
            
            
                const QString& selectedFile() const
                {
                    return m_selectedFile;
                }
            
                void setSelectedFile(const QString& val);
            
            protected slots:
                void selectImageFile();
            
            signals:
                void selectedFileChanged(const QString& fileName);
            
            private:
            
                QString m_selectedFile;
                QPushButton* m_mainButton;
            
            };
            
            #endif // IMAGEPICKBUTTON_H
            
            

            My .cpp file:

            #include "imagepickbutton.h"
            
            ImagePickButton::ImagePickButton(QWidget *parent) : QWidget(parent)
            {
                m_mainButton = new QPushButton(tr("Select Image"),this);
                QHBoxLayout* mainLay = new QHBoxLayout(this);
                mainLay->addWidget(m_mainButton);
                connect(m_mainButton,&QPushButton::clicked,this,&ImagePickButton::selectImageFile);
            
            
                void setSelectedFile(const QString& val)
                {
                    if(m_selectedFile == val)
                        return;
            
                    m_selectedFile = val;
            
                    if(m_selectedFile.isEmpty())
                        {
                            m_mainButton->setText(tr("Select Image"));
                            m_mainButton->setIcon(QIcon());
                        }
                    else
                        {
                            m_mainButton->setText(QString());
                            m_mainButton->setIcon(QIcon(m_selectedFile));
                        }
                    emit selectedFileChanged(m_selectedFile);
                }
            }
            
            

            It gives me an error message for void setSelectedFile(const QString& val) saying that function definition is not allowed here. Am I supposed to leave it in the .h?

            1 Reply Last reply
            0
            • p3c0P Offline
              p3c0P Offline
              p3c0
              Moderators
              wrote on last edited by
              #6

              @gabor53 You have added setSelectedFile definition inside the constructor. Move it outside.

              157

              1 Reply Last reply
              2
              • G Offline
                G Offline
                gabor53
                wrote on last edited by gabor53
                #7

                How can I link the new imagepickbutton to the existing mydelegate class?
                In myDelegate.cpp I currently have:

                    if((index.column () == 3))//image
                        {
                            QPushButton *button = new QPushButton(parent) ;
                          button->setMaximumWidth (100);
                        button->setStyleSheet ("background-color: rgba(255, 255, 255, 0);");
                
                            return button;
                        }
                
                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by SGaist
                  #8

                  Hi,

                  The same way you do for other classes, include the header file and use the class.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  G 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Hi,

                    The same way you do for other classes, include the header file and use the class.

                    G Offline
                    G Offline
                    gabor53
                    wrote on last edited by
                    #9

                    @SGaist
                    I'm still struggling linking the new code to the existing mydelegate.cpp.
                    If I connect the editor from imagepickbutton like this:

                                ImagePickButton *myImagePickButton = new ImagePickButton;
                                myImagePickButton->ImagePickButton::setSelectedFile(QString &val);
                    

                    I get 2 error messages:

                    1. val is not declared in this scope
                    2. expected primary expression '&' token

                    How and where should I connect the new code? I should connect the whole class somewhere or I have to use each function separately? In the second case how can I access the first few lines of imagepickupbutton:

                    ImagePickButton::ImagePickButton(QWidget *parent) : QWidget(parent)
                    {
                        m_mainButton = new QPushButton(tr("Select Image"),this);
                        QHBoxLayout* mainLay = new QHBoxLayout(this);
                        mainLay->addWidget(m_mainButton);
                        connect(m_mainButton, &QPushButton::clicked, this, &ImagePickButton::selectImageFile);
                    }
                    ``
                    which creates the actual button? 
                    Thank you for your help.
                    1 Reply Last reply
                    0
                    • VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by
                      #10

                      I posted the complete code above that takes care of everything, just use that one.

                      if((index.column () == 3))

                      The delegate should never have this kind of code inside. The delegate should not depend on the model. use setItemDelegateForColumn in the view to obtain that result

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      G 1 Reply Last reply
                      2
                      • VRoninV VRonin

                        I posted the complete code above that takes care of everything, just use that one.

                        if((index.column () == 3))

                        The delegate should never have this kind of code inside. The delegate should not depend on the model. use setItemDelegateForColumn in the view to obtain that result

                        G Offline
                        G Offline
                        gabor53
                        wrote on last edited by gabor53
                        #11

                        @VRonin
                        When I try to implement your code I end up with different error messages.
                        If I leave everything in the .h file like this:

                        virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE
                                {
                                    ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
                                    Q_ASSERT(imgPick);
                                    if(imgPick->selectedFile().isEmpty())
                                        {
                                            model->setData(index,QVariant(),Qt::UserRole);
                                            model->setData(index, QVariant(),Qt::DecorationRole);
                                        }
                                    else
                                        {
                                            model->setData(index,imgPick->selectedFile(),Qt::UserRole);
                                            model->setData(index, QIcon(imgPick->selectedFile()),Qt::DecorationRole);
                                        }
                                }
                        
                                virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE
                                {
                                    ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
                                    Q_ASSERT(imgPick);
                                    if(imgPick->selectedFile().isEmpty())
                                        {
                                            model->setData(index,QVariant(),Qt::UserRole);
                                            model->setData(index, QVariant(),Qt::DecorationRole);
                                        }
                                    else
                                        {
                                            model->setData(index,imgPick->selectedFile(),Qt::UserRole);
                                            model->setData(index, QIcon(imgPick->selectedFile()),Qt::DecorationRole);
                                        }
                                }
                        
                        

                        I get an error message saying expected token ';' got 'const'. If I move the definition to the cpp file I get an error saying unexpected token ImagePickButton. What am I doing incorrectly? Thank you

                        1 Reply Last reply
                        0
                        • VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on last edited by
                          #12

                          Looks like you forgot some #includes, added them to my original post

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          G 1 Reply Last reply
                          0
                          • VRoninV VRonin

                            Looks like you forgot some #includes, added them to my original post

                            G Offline
                            G Offline
                            gabor53
                            wrote on last edited by
                            #13

                            @VRonin
                            I have in the .h file:

                            virtual void setEditorData(QWidget *editor, const QModelIndex &index);
                            

                            In the .cpp:

                            void ImageDelegate::setEditorData(QWidget *editor, const QModelIndex &index)
                            {
                                ImagePickButton* imgPick = qobject_cast<ImagePickButton*>(editor);
                                Q_ASSERT(imgPick);
                                imgPick->setSelectedFile(index.data(Qt::UserRole));
                            }
                            

                            It gives me the following error message:
                            C:\Programming\Projects\Folkfriends_1_0\imagedelegate.cpp:18: error: no matching function for call to 'ImagePickButton::setSelectedFile(QVariant)'
                            imgPick->setSelectedFile(index.data(Qt::UserRole));

                                                                              ^
                            

                            C:\Programming\Projects\Folkfriends_1_0\imagedelegate.h:4: In file included from ..\Folkfriends_1_0\imagedelegate.h:4:0,
                            C:\Programming\Projects\Folkfriends_1_0\imagedelegate.cpp:1: from ..\Folkfriends_1_0\imagedelegate.cpp:1:
                            C:\Programming\Projects\Folkfriends_1_0\imagepickbutton.h:18: candidate: void ImagePickButton::setSelectedFile(const QString&)
                            void setSelectedFile(const QString& val);
                            ^
                            C:\Programming\Projects\Folkfriends_1_0\imagepickbutton.h:18: note: no known conversion for argument 1 from 'QVariant' to 'const QString&'

                            What should I change? Everything else builds correctly.

                            1 Reply Last reply
                            0
                            • p3c0P Offline
                              p3c0P Offline
                              p3c0
                              Moderators
                              wrote on last edited by
                              #14

                              @gabor53 setSelectedFile expects a QString parameter so convert the QVariant returned by data to QString.

                              157

                              1 Reply Last reply
                              1
                              • VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #15

                                easy fix imgPick->setSelectedFile(index.data(Qt::UserRole).toString());

                                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                ~Napoleon Bonaparte

                                On a crusade to banish setIndexWidget() from the holy land of Qt

                                G 1 Reply Last reply
                                2
                                • VRoninV VRonin

                                  easy fix imgPick->setSelectedFile(index.data(Qt::UserRole).toString());

                                  G Offline
                                  G Offline
                                  gabor53
                                  wrote on last edited by
                                  #16

                                  @VRonin
                                  Thank you. This part works now. I added

                                  ImagePickButton *myImagePickButton = new ImagePickButton(this);
                                  myImagePickButton->show();
                                  

                                  to mydeelgate.cpp createEditor.

                                  When the user clicks on the image now it creates the button saying "Select Image". But this button is not on the view; it is separated from it and appears in the top left corner of the screen. How can I add it to the view so the button is on the actual image the user is trying to change? Thank you.

                                  1 Reply Last reply
                                  0
                                  • VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by
                                    #17

                                    do not call show() just return that widget from that method. Again I'd advise you just to use the code I posted above even for the delegate

                                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                    ~Napoleon Bonaparte

                                    On a crusade to banish setIndexWidget() from the holy land of Qt

                                    G 1 Reply Last reply
                                    1
                                    • VRoninV VRonin

                                      do not call show() just return that widget from that method. Again I'd advise you just to use the code I posted above even for the delegate

                                      G Offline
                                      G Offline
                                      gabor53
                                      wrote on last edited by
                                      #18

                                      @VRonin
                                      I definitely want to use the code you posted. Should I call the method returning the widget from myDelegate.cpp or from fixdb.cpp where the model is set up? Currently I have this:

                                       ui->tableView_Fix->setItemDelegate (new myDelegate);
                                      

                                      This declares that the delegate will be myDelegate from now on for everything. Can this work somehow ?

                                          ui->tableView_Fix->setItemDelegateForColumn(3, new ImageDelegate);
                                          ui->tableView_Fix->setItemDelegate (new myDelegate);
                                      

                                      Saying that if column 3 is chosen go with ImageDelegate; all other cases myDelegate.
                                      It this is the way, what is missing? Currently it opens a text window in column 4). Thank you.

                                      1 Reply Last reply
                                      0
                                      • VRoninV Offline
                                        VRoninV Offline
                                        VRonin
                                        wrote on last edited by
                                        #19

                                        do it the other way around and do not leak memory:

                                            ui->tableView_Fix->setItemDelegate (new myDelegate(this));
                                        ui->tableView_Fix->setItemDelegateForColumn(3, new ImageDelegate(this));
                                        
                                        

                                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                        ~Napoleon Bonaparte

                                        On a crusade to banish setIndexWidget() from the holy land of Qt

                                        G 2 Replies Last reply
                                        0
                                        • VRoninV VRonin

                                          do it the other way around and do not leak memory:

                                              ui->tableView_Fix->setItemDelegate (new myDelegate(this));
                                          ui->tableView_Fix->setItemDelegateForColumn(3, new ImageDelegate(this));
                                          
                                          
                                          G Offline
                                          G Offline
                                          gabor53
                                          wrote on last edited by gabor53
                                          #20
                                          This post is deleted!
                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved