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. Set Delegate for each cell in a QTableWidget?
Forum Updated to NodeBB v4.3 + New Features

Set Delegate for each cell in a QTableWidget?

Scheduled Pinned Locked Moved Solved General and Desktop
23 Posts 4 Posters 8.3k Views 1 Watching
  • 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.
  • H Offline
    H Offline
    hbatalha
    wrote on last edited by
    #1

    class QTableWidget provide 3 interfaces for setDelegate:

    1. setItemDelegate -- set delegate for whole QTableView

    2. setItemDelegateForRow -- set delegate for given row

    3. setItemDelegateForColumn -- set delegate for given column

    question: if I just want to set delegate for a cell, how can I do it?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Use one of the functions above and check to your desired model index inside the delegate.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      H 1 Reply Last reply
      2
      • Christian EhrlicherC Christian Ehrlicher

        Use one of the functions above and check to your desired model index inside the delegate.

        H Offline
        H Offline
        hbatalha
        wrote on last edited by
        #3

        @Christian-Ehrlicher I don't understand, how do I do that? I want each cell having an individual delegate item, like setCellWidget. This is my delegate class:

        #ifndef DELEGATEBUTTON_H
        #define DELEGATEBUTTON_H
        
        #include <QApplication>
        #include <QStyledItemDelegate>
        #include <QPushButton>
        #include <QMouseEvent>
        #include <QToolTip>
        #include <QPainter>
        #include <QPalette>
        #include <QTableWidget>
        
        
        class DelegateButton : public QStyledItemDelegate
        {
            Q_OBJECT
        #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
            Q_DISABLE_COPY_MOVE(DelegateButton)
        #else
            Q_DISABLE_COPY(TailButtonDelegate)
        #endif
        public:
            explicit DelegateButton(QObject* parent)
                :QStyledItemDelegate(parent),
                 tableWidget(qobject_cast<QTableWidget*>(parent))
            {
                mIsChecked = false;
                isDetailsButton = false;
                isEnabled = true;
                isHidden = false;
            }
            void update()
            {
                tableWidget->viewport()->update();
            }
            void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
            {
                Q_ASSERT(index.isValid());
                QStyleOptionViewItem opt = option;
                initStyleOption(&opt, index);
                const QWidget *widget = option.widget;
        
                QStyle *style = widget ? widget->style() : QApplication::style();
                style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                QStyleOptionButton buttonOption = buttonOptions(opt);
                if(! isHidden)
                    style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget);
            }
            QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
            {
                QStyleOptionViewItem opt = option;
                initStyleOption(&opt, index);
                const QSize baseSize = QStyledItemDelegate::sizeHint(option,index);
                const QRect butRect = buttonRect(opt);
                return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height()));
            }
            QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
            {
                QWidget* result = new QWidget(parent);
                result->setGeometry(option.rect);
                QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index);
                result->setFocusProxy(baseEditor);
                QStyleOptionViewItem opt = option;
                initStyleOption(&opt, index);
                const QRect butRect = buttonRect(opt);
                baseEditor->setObjectName("baseEditor");
                baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height());
                QPushButton* myButton = new QPushButton(result);
                myButton->setObjectName("myButton");
                myButton->setText(m_buttonText);
                myButton->setIcon(m_buttonIcon);
                myButton->setEnabled(false);
                myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height());
                connect(myButton, &QPushButton::clicked, this, &DelegateButton::clickedHelper);
                return result;
            }
            void setEditorData(QWidget *editor, const QModelIndex &index) const override
            {
                currentIndex = index;
                QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                Q_ASSERT(baseEditor);
                QStyledItemDelegate::setEditorData(baseEditor,index);
            }
            void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
            {
                QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                Q_ASSERT(baseEditor);
                QStyledItemDelegate::setModelData(baseEditor,model,index);
            }
            void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
            {
                QStyleOptionViewItem opt = option;
                initStyleOption(&opt, index);
                editor->setGeometry(opt.rect);
                const QRect butRect = buttonRect(opt);
                QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                Q_ASSERT(baseEditor);
                baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height());
                QWidget* myButton = editor->findChild<QWidget*>("myButton");
                Q_ASSERT(myButton);
                myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height());
            }
            const QString text() const
            {
                return m_buttonText;
            }
            void setText(const QString &newButtonText)
            {
                m_buttonText = newButtonText;
                update();
            }
            const QIcon &icon() const
            {
                return m_buttonIcon;
            }
            void setIcon(const QIcon &newButtonIcon)
            {
                m_buttonIcon = newButtonIcon;
                update();
            }
            void setChecked(bool checked)
            {
                mIsChecked = checked;
            }
            bool isChecked()
            {
                return mIsChecked;
            }
            void setToolTip(QString tooltip)
            {
                tooltipText = tooltip;
            }
            void setDetailsButton(bool idb)
            {
                isDetailsButton = idb;
                update();
            }
            void setEnabled(bool enabled)
            {
                isEnabled = enabled;
                update();
            }
            void setHidden(bool hide)
            {
                isHidden = hide;
                update();
            }
            void click()
            {
                mIsChecked = ! mIsChecked;
                clickedHelper();
            }
        
        Q_SIGNALS:
            void clicked(const QModelIndex &index);
            void mouseIn(const QModelIndex &index);
        protected:
            bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
            {
                Q_ASSERT(event);
                Q_ASSERT(model);
                Qt::ItemFlags flags = model->flags(index);
                if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled))
                {
                    if (event->type() == QEvent::MouseButtonRelease)
                    {
                        QStyleOptionViewItem viewOpt(option);
                        initStyleOption(&viewOpt, index);
                        const QRect butRect = buttonRect(viewOpt);
                        QMouseEvent *me = static_cast<QMouseEvent*>(event);
                        if (me->button() == Qt::LeftButton && butRect.contains(me->pos()))
                        {
                            mIsChecked = ! mIsChecked;
                            currentIndex = index;
                            clickedHelper();
                        }
                    }
                }
        
                return QStyledItemDelegate::editorEvent(event,model,option,index);
            }
            virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const
            {
                const QWidget *widget = option.widget;
                QStyle *style = widget ? widget->style() : QApplication::style();
                int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget);
                QStyleOptionButton buttonOption;
                buttonOption.text = m_buttonText;
                buttonOption.icon = m_buttonIcon;
                buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize));
                buttonOption.rect = skipRct ? QRect() : buttonRect(option);
                buttonOption.features = QStyleOptionButton::None;
                buttonOption.direction = option.direction;
                buttonOption.fontMetrics = option.fontMetrics;
                buttonOption.palette = option.palette;
                buttonOption.styleObject = option.styleObject;
        
                if(isEnabled)
                    buttonOption.state = QStyle::State_Enabled;
                else
                    buttonOption.state &= ~QStyle::State_Enabled;
        
                return buttonOption;
            }
            virtual QRect buttonRect(const QStyleOptionViewItem &option) const
            {
                const QStyleOptionButton buttonOption = buttonOptions(option, true);
                const QWidget *widget = option.widget;
                QStyle *style = widget ? widget->style() : QApplication::style();
                QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget);
                buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2));
        
                QRect r = option.rect;
                int x = isDetailsButton ? (r.left()+ r.width() - 10) : (r.center().x() - 6);
                int y = isDetailsButton ? r.top() : r.top() + 10;
                int s = isDetailsButton ? 10 : 20;
        
                return QRect(x, y, s, s);
            }
            virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override
            {
                if( !event || !view )
                    return false;
        
                if( event->type() == QEvent::ToolTip )
                {
                    QVariant tooltip = index.data( Qt::DisplayRole );
                    if( QApplication::keyboardModifiers() == Qt::AltModifier )
                    {
                        QToolTip::showText( event->globalPos(), tooltipText);
                    }
                    else
                    {
                        QToolTip::showText( event->globalPos(), tooltipText);
                    }
        
                    if( !QStyledItemDelegate::helpEvent( event, view, option, index ) )
                        QToolTip::hideText();
                    return true;
                }
        
                return QStyledItemDelegate::helpEvent( event, view, option, index );
            }   
        private:
            mutable QModelIndex currentIndex;
            QPainter* mPainter;
            QString m_buttonText;
            QIcon m_buttonIcon;
            bool mIsChecked;
            bool isDetailsButton;
            bool isEnabled;
            bool isHidden;
            QString tooltipText;
            QTableWidget* tableWidget;
        
            void clickedHelper()
            {
                clicked(currentIndex);
            }
        };
        
        #endif // DELEGATEBUTTON_H
        
        
        JonBJ 1 Reply Last reply
        1
        • H hbatalha

          @Christian-Ehrlicher I don't understand, how do I do that? I want each cell having an individual delegate item, like setCellWidget. This is my delegate class:

          #ifndef DELEGATEBUTTON_H
          #define DELEGATEBUTTON_H
          
          #include <QApplication>
          #include <QStyledItemDelegate>
          #include <QPushButton>
          #include <QMouseEvent>
          #include <QToolTip>
          #include <QPainter>
          #include <QPalette>
          #include <QTableWidget>
          
          
          class DelegateButton : public QStyledItemDelegate
          {
              Q_OBJECT
          #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
              Q_DISABLE_COPY_MOVE(DelegateButton)
          #else
              Q_DISABLE_COPY(TailButtonDelegate)
          #endif
          public:
              explicit DelegateButton(QObject* parent)
                  :QStyledItemDelegate(parent),
                   tableWidget(qobject_cast<QTableWidget*>(parent))
              {
                  mIsChecked = false;
                  isDetailsButton = false;
                  isEnabled = true;
                  isHidden = false;
              }
              void update()
              {
                  tableWidget->viewport()->update();
              }
              void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
              {
                  Q_ASSERT(index.isValid());
                  QStyleOptionViewItem opt = option;
                  initStyleOption(&opt, index);
                  const QWidget *widget = option.widget;
          
                  QStyle *style = widget ? widget->style() : QApplication::style();
                  style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                  QStyleOptionButton buttonOption = buttonOptions(opt);
                  if(! isHidden)
                      style->drawControl(QStyle::CE_PushButton, &buttonOption, painter, widget);
              }
              QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
              {
                  QStyleOptionViewItem opt = option;
                  initStyleOption(&opt, index);
                  const QSize baseSize = QStyledItemDelegate::sizeHint(option,index);
                  const QRect butRect = buttonRect(opt);
                  return QSize(baseSize.width()+butRect.width(),qMax(butRect.height(),baseSize.height()));
              }
              QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
              {
                  QWidget* result = new QWidget(parent);
                  result->setGeometry(option.rect);
                  QWidget* baseEditor = QStyledItemDelegate::createEditor(result,option,index);
                  result->setFocusProxy(baseEditor);
                  QStyleOptionViewItem opt = option;
                  initStyleOption(&opt, index);
                  const QRect butRect = buttonRect(opt);
                  baseEditor->setObjectName("baseEditor");
                  baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height());
                  QPushButton* myButton = new QPushButton(result);
                  myButton->setObjectName("myButton");
                  myButton->setText(m_buttonText);
                  myButton->setIcon(m_buttonIcon);
                  myButton->setEnabled(false);
                  myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height());
                  connect(myButton, &QPushButton::clicked, this, &DelegateButton::clickedHelper);
                  return result;
              }
              void setEditorData(QWidget *editor, const QModelIndex &index) const override
              {
                  currentIndex = index;
                  QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                  Q_ASSERT(baseEditor);
                  QStyledItemDelegate::setEditorData(baseEditor,index);
              }
              void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
              {
                  QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                  Q_ASSERT(baseEditor);
                  QStyledItemDelegate::setModelData(baseEditor,model,index);
              }
              void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
              {
                  QStyleOptionViewItem opt = option;
                  initStyleOption(&opt, index);
                  editor->setGeometry(opt.rect);
                  const QRect butRect = buttonRect(opt);
                  QWidget* baseEditor = editor->findChild<QWidget*>("baseEditor");
                  Q_ASSERT(baseEditor);
                  baseEditor->setGeometry(0,0,opt.rect.width()-butRect.width(),opt.rect.height());
                  QWidget* myButton = editor->findChild<QWidget*>("myButton");
                  Q_ASSERT(myButton);
                  myButton->setGeometry(opt.rect.width()-butRect.width(), 0, butRect.width(),butRect.height());
              }
              const QString text() const
              {
                  return m_buttonText;
              }
              void setText(const QString &newButtonText)
              {
                  m_buttonText = newButtonText;
                  update();
              }
              const QIcon &icon() const
              {
                  return m_buttonIcon;
              }
              void setIcon(const QIcon &newButtonIcon)
              {
                  m_buttonIcon = newButtonIcon;
                  update();
              }
              void setChecked(bool checked)
              {
                  mIsChecked = checked;
              }
              bool isChecked()
              {
                  return mIsChecked;
              }
              void setToolTip(QString tooltip)
              {
                  tooltipText = tooltip;
              }
              void setDetailsButton(bool idb)
              {
                  isDetailsButton = idb;
                  update();
              }
              void setEnabled(bool enabled)
              {
                  isEnabled = enabled;
                  update();
              }
              void setHidden(bool hide)
              {
                  isHidden = hide;
                  update();
              }
              void click()
              {
                  mIsChecked = ! mIsChecked;
                  clickedHelper();
              }
          
          Q_SIGNALS:
              void clicked(const QModelIndex &index);
              void mouseIn(const QModelIndex &index);
          protected:
              bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
              {
                  Q_ASSERT(event);
                  Q_ASSERT(model);
                  Qt::ItemFlags flags = model->flags(index);
                  if ((option.state & QStyle::State_Enabled) && (flags & Qt::ItemIsEnabled))
                  {
                      if (event->type() == QEvent::MouseButtonRelease)
                      {
                          QStyleOptionViewItem viewOpt(option);
                          initStyleOption(&viewOpt, index);
                          const QRect butRect = buttonRect(viewOpt);
                          QMouseEvent *me = static_cast<QMouseEvent*>(event);
                          if (me->button() == Qt::LeftButton && butRect.contains(me->pos()))
                          {
                              mIsChecked = ! mIsChecked;
                              currentIndex = index;
                              clickedHelper();
                          }
                      }
                  }
          
                  return QStyledItemDelegate::editorEvent(event,model,option,index);
              }
              virtual QStyleOptionButton buttonOptions(const QStyleOptionViewItem &option, bool skipRct=false) const
              {
                  const QWidget *widget = option.widget;
                  QStyle *style = widget ? widget->style() : QApplication::style();
                  int buttonIconSize = style->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget);
                  QStyleOptionButton buttonOption;
                  buttonOption.text = m_buttonText;
                  buttonOption.icon = m_buttonIcon;
                  buttonOption.iconSize = (QSize(buttonIconSize,buttonIconSize));
                  buttonOption.rect = skipRct ? QRect() : buttonRect(option);
                  buttonOption.features = QStyleOptionButton::None;
                  buttonOption.direction = option.direction;
                  buttonOption.fontMetrics = option.fontMetrics;
                  buttonOption.palette = option.palette;
                  buttonOption.styleObject = option.styleObject;
          
                  if(isEnabled)
                      buttonOption.state = QStyle::State_Enabled;
                  else
                      buttonOption.state &= ~QStyle::State_Enabled;
          
                  return buttonOption;
              }
              virtual QRect buttonRect(const QStyleOptionViewItem &option) const
              {
                  const QStyleOptionButton buttonOption = buttonOptions(option, true);
                  const QWidget *widget = option.widget;
                  QStyle *style = widget ? widget->style() : QApplication::style();
                  QSize buttonSize = style->sizeFromContents(QStyle::CT_PushButton, &buttonOption, QSize(), widget);
                  buttonSize.setWidth(qMin(buttonSize.width(),option.rect.width()/2));
          
                  QRect r = option.rect;
                  int x = isDetailsButton ? (r.left()+ r.width() - 10) : (r.center().x() - 6);
                  int y = isDetailsButton ? r.top() : r.top() + 10;
                  int s = isDetailsButton ? 10 : 20;
          
                  return QRect(x, y, s, s);
              }
              virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override
              {
                  if( !event || !view )
                      return false;
          
                  if( event->type() == QEvent::ToolTip )
                  {
                      QVariant tooltip = index.data( Qt::DisplayRole );
                      if( QApplication::keyboardModifiers() == Qt::AltModifier )
                      {
                          QToolTip::showText( event->globalPos(), tooltipText);
                      }
                      else
                      {
                          QToolTip::showText( event->globalPos(), tooltipText);
                      }
          
                      if( !QStyledItemDelegate::helpEvent( event, view, option, index ) )
                          QToolTip::hideText();
                      return true;
                  }
          
                  return QStyledItemDelegate::helpEvent( event, view, option, index );
              }   
          private:
              mutable QModelIndex currentIndex;
              QPainter* mPainter;
              QString m_buttonText;
              QIcon m_buttonIcon;
              bool mIsChecked;
              bool isDetailsButton;
              bool isEnabled;
              bool isHidden;
              QString tooltipText;
              QTableWidget* tableWidget;
          
              void clickedHelper()
              {
                  clicked(currentIndex);
              }
          };
          
          #endif // DELEGATEBUTTON_H
          
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @hbatalha
          In the example at https://doc.qt.io/qt-5/qabstractitemdelegate.html#details, you see

          void WidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                     const QModelIndex &index) const
          {
              if (index.column() == 1) {
                  ...
              } else
                  QStyledItemDelegate::paint(painter, option, index);
          }
          

          WidgetDelegate has been assigned as the item delegate (probably through setItemDelegate()) for all cells. The first thing it does in paint() is to look at the column/row of the passed-in index to see which cell it is being called on, and acts accordingly. This is how you apply a delegate to certain cells only: you have to assign the delegate to all cells and then have it check at runtime what it does/does not do for each cell.

          H 1 Reply Last reply
          0
          • JonBJ JonB

            @hbatalha
            In the example at https://doc.qt.io/qt-5/qabstractitemdelegate.html#details, you see

            void WidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                       const QModelIndex &index) const
            {
                if (index.column() == 1) {
                    ...
                } else
                    QStyledItemDelegate::paint(painter, option, index);
            }
            

            WidgetDelegate has been assigned as the item delegate (probably through setItemDelegate()) for all cells. The first thing it does in paint() is to look at the column/row of the passed-in index to see which cell it is being called on, and acts accordingly. This is how you apply a delegate to certain cells only: you have to assign the delegate to all cells and then have it check at runtime what it does/does not do for each cell.

            H Offline
            H Offline
            hbatalha
            wrote on last edited by hbatalha
            #5

            @JonB I think the problem is I have two different buttons that goes in their own columns in the same row. I will have to modify the delegate and create two buttons instead that goes in only one column I guess. This shall be the starting point.

            JonBJ 1 Reply Last reply
            0
            • H hbatalha

              @JonB I think the problem is I have two different buttons that goes in their own columns in the same row. I will have to modify the delegate and create two buttons instead that goes in only one column I guess. This shall be the starting point.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @hbatalha
              What? Why?

              As said before when using the delegate you get an index parameter which you can inspect and act on accordingly for desired rows, columns and/or cells. I don't know what your issue is.

              H 1 Reply Last reply
              1
              • JonBJ JonB

                @hbatalha
                What? Why?

                As said before when using the delegate you get an index parameter which you can inspect and act on accordingly for desired rows, columns and/or cells. I don't know what your issue is.

                H Offline
                H Offline
                hbatalha
                wrote on last edited by
                #7

                @JonB Maybe I am not understanding how to do by your proposed solution, this is the code without delegate:

                for(int i = 0, len = titlesList.size(); i < len; ++i) // len == 200 starts causing some lumpiness (at leat leat in my pc)
                {
                    const int row = ui->table->rowCount();
                
                    ui->table->setRowCount(row + 1);
                
                    QPushButton* button1= new QPushButton(this);
                    QPushButton* button2= new QPushButton(this);
                
                    ui->table->setItem(row, 0, new QTableWidgetItem(title));
                    ui->table->setItem(row, 1, new QTableWidgetItem("-"));
                    ui->table->setItem(row, 2, new QTableWidgetItem("-"));
                    ui->table->setItem(row, 3, new QTableWidgetItem("-"));
                    ui->table->setItem(row, 4, new QTableWidgetItem("-"));
                    ui->table->setCellWidget(row, 5, button1);
                    ui->table->setCellWidget(row, 6, button2);
                
                
                    for(int k = 0; k < 5; ++k)
                    {
                        QTableWidgetItem* item = ui->table->item(row, k);
                        item->setFlags(item->flags() & ~ Qt::ItemIsEditable);
                
                        if(k != 0)
                        {
                            item->setTextAlignment(Qt::AlignmentFlag::AlignCenter);
                        }
                    }
                
                    Record* record = new Record(title, destinationFolder, format,
                                                  qualityText, mRecordType);
                    record->button1(button1);
                    record->button2(button2);
                
                    allRecords.append(record);
                    activeRecords.append(record);
                    database.add(record);
                }
                

                Each button click causes an action to its row. How would I do that with the delegate class above?

                VRoninV 1 Reply Last reply
                0
                • H hbatalha

                  @JonB Maybe I am not understanding how to do by your proposed solution, this is the code without delegate:

                  for(int i = 0, len = titlesList.size(); i < len; ++i) // len == 200 starts causing some lumpiness (at leat leat in my pc)
                  {
                      const int row = ui->table->rowCount();
                  
                      ui->table->setRowCount(row + 1);
                  
                      QPushButton* button1= new QPushButton(this);
                      QPushButton* button2= new QPushButton(this);
                  
                      ui->table->setItem(row, 0, new QTableWidgetItem(title));
                      ui->table->setItem(row, 1, new QTableWidgetItem("-"));
                      ui->table->setItem(row, 2, new QTableWidgetItem("-"));
                      ui->table->setItem(row, 3, new QTableWidgetItem("-"));
                      ui->table->setItem(row, 4, new QTableWidgetItem("-"));
                      ui->table->setCellWidget(row, 5, button1);
                      ui->table->setCellWidget(row, 6, button2);
                  
                  
                      for(int k = 0; k < 5; ++k)
                      {
                          QTableWidgetItem* item = ui->table->item(row, k);
                          item->setFlags(item->flags() & ~ Qt::ItemIsEditable);
                  
                          if(k != 0)
                          {
                              item->setTextAlignment(Qt::AlignmentFlag::AlignCenter);
                          }
                      }
                  
                      Record* record = new Record(title, destinationFolder, format,
                                                    qualityText, mRecordType);
                      record->button1(button1);
                      record->button2(button2);
                  
                      allRecords.append(record);
                      activeRecords.append(record);
                      database.add(record);
                  }
                  

                  Each button click causes an action to its row. How would I do that with the delegate class above?

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                  How would I do that with the delegate class above?

                  DelegateButton *delegate1 = new DelegateButton(this);
                  DelegateButton *delegate2 = new DelegateButton(this);
                  view->setItemDelegateForColumn(5,delegate1);
                  view->setItemDelegateForColumn(6,delegate2);
                  

                  "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

                  H 1 Reply Last reply
                  0
                  • VRoninV VRonin

                    @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                    How would I do that with the delegate class above?

                    DelegateButton *delegate1 = new DelegateButton(this);
                    DelegateButton *delegate2 = new DelegateButton(this);
                    view->setItemDelegateForColumn(5,delegate1);
                    view->setItemDelegateForColumn(6,delegate2);
                    
                    H Offline
                    H Offline
                    hbatalha
                    wrote on last edited by
                    #9

                    @VRonin That is how I did, but the problem was that, say that I want to insert 30 rows, only the last delegate2 will be valid for the tablewidget, when I click one button it is supposed to change its icon, so with delegate button, when I click a button in a row, all the others delegate buttons in the other rows will be affected because ultimately they are the same and only last row will be affected. Every time a new row is inserted the new delegate button created will replace the last one with setItemDelegateForColumn.
                    That is how it behaved.

                    VRoninV 1 Reply Last reply
                    0
                    • Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Again: change your delegate to check for the index and do the painting accordingly...

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      1 Reply Last reply
                      2
                      • H hbatalha

                        @VRonin That is how I did, but the problem was that, say that I want to insert 30 rows, only the last delegate2 will be valid for the tablewidget, when I click one button it is supposed to change its icon, so with delegate button, when I click a button in a row, all the others delegate buttons in the other rows will be affected because ultimately they are the same and only last row will be affected. Every time a new row is inserted the new delegate button created will replace the last one with setItemDelegateForColumn.
                        That is how it behaved.

                        VRoninV Offline
                        VRoninV Offline
                        VRonin
                        wrote on last edited by VRonin
                        #11

                        @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                        when I click one button it is supposed to change its icon, so with delegate button, when I click a button in a row, all the others delegate buttons in the other rows will be affected because ultimately they are the same and only last row will be affected. Every time a new row is inserted the new delegate button created will replace the last one with setItemDelegateForColumn.

                        What I read in this is that you are storing data in the delegate. that should not happen.
                        The process should be:
                        click the delegate➡the delegate emits a signal (clicked(const QModelIndex &index))➡in the slot connected to that signal you store data in a custom role of the model (e.g. model->setData(index, index.data(Qt::UserRole).toBool() ? QVariant() : true, Qt::UserRole);)➡the delegate will use the data stored in this role to decide how to paint/create the button

                        "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

                        H 1 Reply Last reply
                        2
                        • VRoninV VRonin

                          @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                          when I click one button it is supposed to change its icon, so with delegate button, when I click a button in a row, all the others delegate buttons in the other rows will be affected because ultimately they are the same and only last row will be affected. Every time a new row is inserted the new delegate button created will replace the last one with setItemDelegateForColumn.

                          What I read in this is that you are storing data in the delegate. that should not happen.
                          The process should be:
                          click the delegate➡the delegate emits a signal (clicked(const QModelIndex &index))➡in the slot connected to that signal you store data in a custom role of the model (e.g. model->setData(index, index.data(Qt::UserRole).toBool() ? QVariant() : true, Qt::UserRole);)➡the delegate will use the data stored in this role to decide how to paint/create the button

                          H Offline
                          H Offline
                          hbatalha
                          wrote on last edited by
                          #12

                          @VRonin @Christian-Ehrlicher There's a disconnect here, I am not quite understanding what you are telling me. This is how my table is behaving:

                          5sm60k.gif

                          The last row is being changed because that is the last delegate button that was created. Each record takes the two buttons and they are connected and in turn each record is connected to a table row. So when I click a button it changes the status of the record it's connected to and then the row which the record is connected to is updated.

                          I need each row to have its own buttons. That's why I said that I need to modify the delegate so it paints two buttons instead like here and then use setItemDelegateForRow.

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

                            The shape of the play/pause button should depend on the data in the model. Coan you show us the slot where you you change the "In Queue" to "Paused"?

                            "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

                            H 1 Reply Last reply
                            0
                            • VRoninV VRonin

                              The shape of the play/pause button should depend on the data in the model. Coan you show us the slot where you you change the "In Queue" to "Paused"?

                              H Offline
                              H Offline
                              hbatalha
                              wrote on last edited by
                              #14

                              @VRonin Here are the connect's with QPushButton:

                              connect(pause_button, &QPushButton::clicked, record, &Record::pauseResume); // `pause_button` is `button1` in the code above
                              connect(record, &Record::progressUpdated, this, &MainWindow::onProgressUpdated);
                              

                              The slot:

                              void MainWindow::onProgressUpdated(const QString& command, QString status)
                              {
                                  const int row = commands_rows.key(command); // QMap
                              
                                  QTableWidgetItem* item = ui->table->item(row, 2);
                              
                                  bool isPercentage = false;
                              
                                  int progressPercentInt = status.toInt(&isPercentage);
                              
                                  if (progressPercentInt < 0)
                                  {
                                      status = tr("Error");
                                      isPercentage = false;
                                  }
                              
                                  if(isPercentage)
                                  {
                                      item->setText(status + "%");
                                  }
                                  else
                                  {
                                      item->setText(status);
                                  }
                              }
                              
                              VRoninV 1 Reply Last reply
                              0
                              • H hbatalha

                                @VRonin Here are the connect's with QPushButton:

                                connect(pause_button, &QPushButton::clicked, record, &Record::pauseResume); // `pause_button` is `button1` in the code above
                                connect(record, &Record::progressUpdated, this, &MainWindow::onProgressUpdated);
                                

                                The slot:

                                void MainWindow::onProgressUpdated(const QString& command, QString status)
                                {
                                    const int row = commands_rows.key(command); // QMap
                                
                                    QTableWidgetItem* item = ui->table->item(row, 2);
                                
                                    bool isPercentage = false;
                                
                                    int progressPercentInt = status.toInt(&isPercentage);
                                
                                    if (progressPercentInt < 0)
                                    {
                                        status = tr("Error");
                                        isPercentage = false;
                                    }
                                
                                    if(isPercentage)
                                    {
                                        item->setText(status + "%");
                                    }
                                    else
                                    {
                                        item->setText(status);
                                    }
                                }
                                
                                VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #15

                                @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                &Record::pauseResume

                                Can you show this slot please?

                                "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

                                H 1 Reply Last reply
                                0
                                • VRoninV VRonin

                                  @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                  &Record::pauseResume

                                  Can you show this slot please?

                                  H Offline
                                  H Offline
                                  hbatalha
                                  wrote on last edited by hbatalha
                                  #16

                                  @VRonin

                                  void Recod::pauseResume()
                                  { 
                                      if(isInQueue() || isToResume())
                                      {
                                          emit pogressUpdated(command, tr("Paused"));
                                  
                                          if(hasStarted)
                                          {
                                              process->kill();
                                          }
                                  
                                          status_ = Status::PAUSED;
                                          hasStarted = false;
                                      }
                                      else
                                      {
                                          emit progressUpdated(command, tr("In Queue"));
                                          status_ = Status::TO_RESUME;
                                          emit statusChanged(getArgsStr(), status());
                                      }
                                  }
                                  
                                  VRoninV 1 Reply Last reply
                                  0
                                  • H hbatalha

                                    @VRonin

                                    void Recod::pauseResume()
                                    { 
                                        if(isInQueue() || isToResume())
                                        {
                                            emit pogressUpdated(command, tr("Paused"));
                                    
                                            if(hasStarted)
                                            {
                                                process->kill();
                                            }
                                    
                                            status_ = Status::PAUSED;
                                            hasStarted = false;
                                        }
                                        else
                                        {
                                            emit progressUpdated(command, tr("In Queue"));
                                            status_ = Status::TO_RESUME;
                                            emit statusChanged(getArgsStr(), status());
                                        }
                                    }
                                    
                                    VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by VRonin
                                    #17

                                    @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                    status_ = Status::PAUSED;

                                    Yeah, see, you are using a global state to manage data that should live in the model. pauseResume should look more like:

                                    enum{
                                    StatusRole = Qt::UserRole
                                    };
                                    void Recod::pauseResume(const QModelIndex& index){
                                    if (index.data(StatusRole).toInt() == Status::PAUSED)
                                    model->setData(index,Status::TO_RESUME,StatusRole);
                                    else
                                    model->setData(index,Status::PAUSED,StatusRole);
                                    }
                                    

                                    This stores the state of the single item into the model. Signaling the change is handled by the model. You can then retrieve that state inside the delegate and paint accordingly

                                    "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

                                    H 1 Reply Last reply
                                    2
                                    • VRoninV VRonin

                                      @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                      status_ = Status::PAUSED;

                                      Yeah, see, you are using a global state to manage data that should live in the model. pauseResume should look more like:

                                      enum{
                                      StatusRole = Qt::UserRole
                                      };
                                      void Recod::pauseResume(const QModelIndex& index){
                                      if (index.data(StatusRole).toInt() == Status::PAUSED)
                                      model->setData(index,Status::TO_RESUME,StatusRole);
                                      else
                                      model->setData(index,Status::PAUSED,StatusRole);
                                      }
                                      

                                      This stores the state of the single item into the model. Signaling the change is handled by the model. You can then retrieve that state inside the delegate and paint accordingly

                                      H Offline
                                      H Offline
                                      hbatalha
                                      wrote on last edited by hbatalha
                                      #18

                                      @VRonin How I get this part, but since I will be having multiple rows how will I differentiate each delegate button with its row? In my for loop when I insert rows if I call setItemDelegateForColumn only once still all the rows that are inserted after will have the delegate buttons. Shouldn't I be using setItemDelegateForRow instead? Each record takes its buttons but only the last delegate buttons created in the for loop will be set into the columns. This is the part I am not getting.

                                      Sorry it's taking so much time but it's proving to be trickier for me to understand delegates fully. This is my first hands-on experience with them.

                                      VRoninV 1 Reply Last reply
                                      0
                                      • H hbatalha

                                        @VRonin How I get this part, but since I will be having multiple rows how will I differentiate each delegate button with its row? In my for loop when I insert rows if I call setItemDelegateForColumn only once still all the rows that are inserted after will have the delegate buttons. Shouldn't I be using setItemDelegateForRow instead? Each record takes its buttons but only the last delegate buttons created in the for loop will be set into the columns. This is the part I am not getting.

                                        Sorry it's taking so much time but it's proving to be trickier for me to understand delegates fully. This is my first hands-on experience with them.

                                        VRoninV Offline
                                        VRoninV Offline
                                        VRonin
                                        wrote on last edited by
                                        #19

                                        @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                        Each record takes its buttons but only the last delegate buttons created in the for loop will be set into the columns.

                                        Not sure I understand what you mean.

                                        If showing/not showing the buttons depend on a state of the item then we are back to the case above. Save such state in a role of the model and use it in the delegate.

                                        Maybe if you can formulate a simple concrete example we can get to the root of the problem

                                        "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

                                        H 1 Reply Last reply
                                        0
                                        • VRoninV VRonin

                                          @hbatalha said in Set Delegate for each cell in a QTableWidget?:

                                          Each record takes its buttons but only the last delegate buttons created in the for loop will be set into the columns.

                                          Not sure I understand what you mean.

                                          If showing/not showing the buttons depend on a state of the item then we are back to the case above. Save such state in a role of the model and use it in the delegate.

                                          Maybe if you can formulate a simple concrete example we can get to the root of the problem

                                          H Offline
                                          H Offline
                                          hbatalha
                                          wrote on last edited by
                                          #20

                                          @VRonin said in Set Delegate for each cell in a QTableWidget?:

                                          Not sure I understand what you mean.

                                          Ok, try having a QTableWidget with multiple rows and use setItemDelegateForColumn to add the delegate buttons like in my code above, then click a button in a row and have only that delegate button in that row be repainted (change icon). This is what I am unable to do.

                                          If you see the image below I click one button and all the other buttons change icon as well. I want to click one button and only that button to change its icon.
                                          5sm60k.gif

                                          Maybe if you can formulate a simple concrete example we can get to the root of the problem

                                          I will try to create one.

                                          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