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. Delete QTableWidget selected rows
Forum Updated to NodeBB v4.3 + New Features

Delete QTableWidget selected rows

Scheduled Pinned Locked Moved Solved General and Desktop
22 Posts 5 Posters 3.7k Views 2 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.
  • V Offline
    V Offline
    VRonin
    wrote on 16 Jun 2021, 16:59 last edited by VRonin
    #13

    I see I confused you a bit. See this minimal example on how this works:

    #include <QApplication>
    #include <QTableWidget>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QDebug>
    
    class ExampleWidget : public QWidget{
        Q_DISABLE_COPY(ExampleWidget)
    public:
        explicit ExampleWidget(QWidget* parent = nullptr)
            :QWidget(parent)
        {
            tableWidget= new QTableWidget(0,1,this);
            connect(tableWidget->model(),&QAbstractItemModel::dataChanged,this,&ExampleWidget::checkboxChanged);
    
            addRowButton= new QPushButton(tr("Add Row"),this);
            connect(addRowButton,&QPushButton::clicked,this,&ExampleWidget::addRow);
    
            QVBoxLayout* mainLay = new QVBoxLayout(this);
            mainLay->addWidget(tableWidget);
            mainLay->addWidget(addRowButton);
        }
    private slots:
        void addRow(){
            QTableWidgetItem* item = new QTableWidgetItem;
            const int numRows = tableWidget->rowCount();
            item->setData(Qt::EditRole, numRows+1);
            item->setData(Qt::CheckStateRole,Qt::Checked); // makes the checkbox appear
            item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
            tableWidget->insertRow(numRows);
            tableWidget->setItem(numRows,0,item);
        }
        void checkboxChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
            if(roles.contains(Qt::CheckStateRole)|| roles.isEmpty()){
                for(int i=topLeft.row();i<=bottomRight.row();++i){
                    for(int j=topLeft.column();j<=bottomRight.column();++j){
                        qDebug() << "checkbox changed in row " << i << " column " << j;
                        QTableWidgetItem* item = tableWidget->item(i,j);
                        if(item->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked)
                            qDebug() << "checkbox is checked";
                        else
                            qDebug() << "checkbox is uncecked";
                    }
                }
            }
        }
    private:
        QTableWidget* tableWidget;
        QPushButton* addRowButton;
    };
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc,argv);
        ExampleWidget wid;
        wid.show();
        return app.exec();
    }
    

    As you can see the connect is done only once and it's overall really fast. If you don't want your slot to be triggered when a new item is inserted then you just need to remove || roles.isEmpty()
    Forgot to mention this requires Qt >= 5.12

    "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 16 Jun 2021, 18:03
    3
    • V VRonin
      16 Jun 2021, 16:59

      I see I confused you a bit. See this minimal example on how this works:

      #include <QApplication>
      #include <QTableWidget>
      #include <QPushButton>
      #include <QVBoxLayout>
      #include <QDebug>
      
      class ExampleWidget : public QWidget{
          Q_DISABLE_COPY(ExampleWidget)
      public:
          explicit ExampleWidget(QWidget* parent = nullptr)
              :QWidget(parent)
          {
              tableWidget= new QTableWidget(0,1,this);
              connect(tableWidget->model(),&QAbstractItemModel::dataChanged,this,&ExampleWidget::checkboxChanged);
      
              addRowButton= new QPushButton(tr("Add Row"),this);
              connect(addRowButton,&QPushButton::clicked,this,&ExampleWidget::addRow);
      
              QVBoxLayout* mainLay = new QVBoxLayout(this);
              mainLay->addWidget(tableWidget);
              mainLay->addWidget(addRowButton);
          }
      private slots:
          void addRow(){
              QTableWidgetItem* item = new QTableWidgetItem;
              const int numRows = tableWidget->rowCount();
              item->setData(Qt::EditRole, numRows+1);
              item->setData(Qt::CheckStateRole,Qt::Checked); // makes the checkbox appear
              item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
              tableWidget->insertRow(numRows);
              tableWidget->setItem(numRows,0,item);
          }
          void checkboxChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
              if(roles.contains(Qt::CheckStateRole)|| roles.isEmpty()){
                  for(int i=topLeft.row();i<=bottomRight.row();++i){
                      for(int j=topLeft.column();j<=bottomRight.column();++j){
                          qDebug() << "checkbox changed in row " << i << " column " << j;
                          QTableWidgetItem* item = tableWidget->item(i,j);
                          if(item->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked)
                              qDebug() << "checkbox is checked";
                          else
                              qDebug() << "checkbox is uncecked";
                      }
                  }
              }
          }
      private:
          QTableWidget* tableWidget;
          QPushButton* addRowButton;
      };
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc,argv);
          ExampleWidget wid;
          wid.show();
          return app.exec();
      }
      

      As you can see the connect is done only once and it's overall really fast. If you don't want your slot to be triggered when a new item is inserted then you just need to remove || roles.isEmpty()
      Forgot to mention this requires Qt >= 5.12

      H Offline
      H Offline
      hbatalha
      wrote on 16 Jun 2021, 18:03 last edited by hbatalha
      #14

      @VRonin A good solution but I do have a question:

      void checkboxChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
              if(roles.contains(Qt::CheckStateRole)|| roles.isEmpty()){
                  for(int i=topLeft.row();i<=bottomRight.row();++i){
                      for(int j=topLeft.column();j<=bottomRight.column();++j){
                          qDebug() << "checkbox changed in row " << i << " column " << j;
                          QTableWidgetItem* item = tableWidget->item(i,j);
                          if(item->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked)
                              qDebug() << "checkbox is checked";
                          else
                              qDebug() << "checkbox is uncecked";
                      }
                  }
              }
          }
      

      From what I could see, isn't that a little expensive to check all the checkboxes every time one is changed, suppose the user has a table with 2 hundreds rows?

      Edit: the topLeft.row() is the exact row where the checkbox is modified so it can be used instead of iterating through all the columns and rows.

      V 1 Reply Last reply 16 Jun 2021, 18:27
      0
      • H hbatalha
        16 Jun 2021, 18:03

        @VRonin A good solution but I do have a question:

        void checkboxChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
                if(roles.contains(Qt::CheckStateRole)|| roles.isEmpty()){
                    for(int i=topLeft.row();i<=bottomRight.row();++i){
                        for(int j=topLeft.column();j<=bottomRight.column();++j){
                            qDebug() << "checkbox changed in row " << i << " column " << j;
                            QTableWidgetItem* item = tableWidget->item(i,j);
                            if(item->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked)
                                qDebug() << "checkbox is checked";
                            else
                                qDebug() << "checkbox is uncecked";
                        }
                    }
                }
            }
        

        From what I could see, isn't that a little expensive to check all the checkboxes every time one is changed, suppose the user has a table with 2 hundreds rows?

        Edit: the topLeft.row() is the exact row where the checkbox is modified so it can be used instead of iterating through all the columns and rows.

        V Offline
        V Offline
        VRonin
        wrote on 16 Jun 2021, 18:27 last edited by
        #15

        @hbatalha said in Delete QTableWidget selected rows:

        to check all the checkboxes

        I'm not checking all the checkboxes. The signal tells you that something has changed in the rectangle with corners topLeft bottomRight so i check only that rectangle. 99% of the cases that rectangle is just a single item (topLeft==bottomRight) so you end up checking only 1 item

        "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 2 Replies Last reply 16 Jun 2021, 18:44
        0
        • V VRonin
          16 Jun 2021, 18:27

          @hbatalha said in Delete QTableWidget selected rows:

          to check all the checkboxes

          I'm not checking all the checkboxes. The signal tells you that something has changed in the rectangle with corners topLeft bottomRight so i check only that rectangle. 99% of the cases that rectangle is just a single item (topLeft==bottomRight) so you end up checking only 1 item

          H Offline
          H Offline
          hbatalha
          wrote on 16 Jun 2021, 18:44 last edited by
          #16

          @VRonin I think I misspoke, when I say "check all the checkboxes" I mean to check all the checkboxes if they are checked or unchecked.

          Anyway, I understand how it works now. Thank you very much.

          1 Reply Last reply
          0
          • V VRonin
            16 Jun 2021, 18:27

            @hbatalha said in Delete QTableWidget selected rows:

            to check all the checkboxes

            I'm not checking all the checkboxes. The signal tells you that something has changed in the rectangle with corners topLeft bottomRight so i check only that rectangle. 99% of the cases that rectangle is just a single item (topLeft==bottomRight) so you end up checking only 1 item

            H Offline
            H Offline
            hbatalha
            wrote on 16 Jun 2021, 19:25 last edited by
            #17

            @VRonin Is there a way to change the checkbox color? maybe inside it.

            1 Reply Last reply
            0
            • V Offline
              V Offline
              VRonin
              wrote on 16 Jun 2021, 19:30 last edited by
              #18

              See https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview

              The QTableView's checkbox indicator can also be customized. In the following snippet the indicator background-color in unchecked state is customized:

              QTableView::indicator:unchecked {
                  background-color: #d7d6d5
              }
              

              "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 16 Jun 2021, 19:56
              1
              • V VRonin
                16 Jun 2021, 19:30

                See https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview

                The QTableView's checkbox indicator can also be customized. In the following snippet the indicator background-color in unchecked state is customized:

                QTableView::indicator:unchecked {
                    background-color: #d7d6d5
                }
                
                H Offline
                H Offline
                hbatalha
                wrote on 16 Jun 2021, 19:56 last edited by
                #19

                @VRonin It looked kinda weird. So I tried to change the background-color for both checked and unchecked but it only works for one.
                This is the result:
                Screenshot_6.png

                I want a similar result I achieved with a QCheckBox by setting the palette:
                Screenshot_5.png

                The code for QCheckBox:

                       QCheckBox *title_ckbox = new QCheckBox(title);
                        title_ckbox->setToolTip(title);
                
                        QPalette p = title_ckbox->palette( );
                        QColor blue( 0, 0, 255 );
                        p.setColor( QPalette::Active, QPalette::Base, blue );
                        title_ckbox->setPalette(p);
                

                Is it possible to have something like that?

                H 1 Reply Last reply 16 Jun 2021, 20:18
                0
                • H hbatalha
                  16 Jun 2021, 19:56

                  @VRonin It looked kinda weird. So I tried to change the background-color for both checked and unchecked but it only works for one.
                  This is the result:
                  Screenshot_6.png

                  I want a similar result I achieved with a QCheckBox by setting the palette:
                  Screenshot_5.png

                  The code for QCheckBox:

                         QCheckBox *title_ckbox = new QCheckBox(title);
                          title_ckbox->setToolTip(title);
                  
                          QPalette p = title_ckbox->palette( );
                          QColor blue( 0, 0, 255 );
                          p.setColor( QPalette::Active, QPalette::Base, blue );
                          title_ckbox->setPalette(p);
                  

                  Is it possible to have something like that?

                  H Offline
                  H Offline
                  hbatalha
                  wrote on 16 Jun 2021, 20:18 last edited by
                  #20

                  @VRonin I was able to smooth the problem by doing this:

                  QTableView::indicator:unchecked {
                    border: 1px solid blue
                   }
                  

                  It is not exactly what I wanted but it does it for now.

                  1 Reply Last reply
                  0
                  • V Offline
                    V Offline
                    VRonin
                    wrote on 16 Jun 2021, 20:24 last edited by VRonin
                    #21

                    @hbatalha said in Delete QTableWidget selected rows:

                    Is it possible to have something like that?

                    class CheckBoxDelegate : public QStyledItemDelegate{
                        Q_DISABLE_COPY(CheckBoxDelegate)
                    public:
                        using QStyledItemDelegate::QStyledItemDelegate;
                    protected:
                        void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
                            QStyledItemDelegate::initStyleOption(option,index);
                            option->palette.setColor( QPalette::Active, QPalette::Base, Qt::blue );
                        }
                    };
                    

                    tableWidget->setItemDelegate(new CheckBoxDelegate(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

                    H 1 Reply Last reply 16 Jun 2021, 22:09
                    1
                    • V VRonin
                      16 Jun 2021, 20:24

                      @hbatalha said in Delete QTableWidget selected rows:

                      Is it possible to have something like that?

                      class CheckBoxDelegate : public QStyledItemDelegate{
                          Q_DISABLE_COPY(CheckBoxDelegate)
                      public:
                          using QStyledItemDelegate::QStyledItemDelegate;
                      protected:
                          void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
                              QStyledItemDelegate::initStyleOption(option,index);
                              option->palette.setColor( QPalette::Active, QPalette::Base, Qt::blue );
                          }
                      };
                      

                      tableWidget->setItemDelegate(new CheckBoxDelegate(this));

                      H Offline
                      H Offline
                      hbatalha
                      wrote on 16 Jun 2021, 22:09 last edited by
                      #22

                      @VRonin worked like charm. Thank you for all your help and for your time. I really appreciate it.

                      1 Reply Last reply
                      0

                      22/22

                      16 Jun 2021, 22:09

                      • Login

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