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 VRonin
    4 Jun 2021, 09:23

    @hbatalha said in Delete QTableWidget selected rows:

    How would I connect the checkbox when clicked?

    QObject::connect(tableWidget->model(),&QAbstractItemModel::dataChanged,[](const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
        if(roles.isEmpty() || roles.contains(Qt::CheckStateRole){
            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;
                }
            }
        }
    });
    

    how to check if it is checked?

    tableWidgetItem->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked

    H Offline
    H Offline
    hbatalha
    wrote on 16 Jun 2021, 16:24 last edited by
    #10

    @VRonin said in Delete QTableWidget selected rows:

    @hbatalha said in Delete QTableWidget selected rows:

    How would I connect the checkbox when clicked?

    QObject::connect(tableWidget->model(),&QAbstractItemModel::dataChanged,[](const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles){
        if(roles.isEmpty() || roles.contains(Qt::CheckStateRole){
            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;
                }
            }
        }
    });
    

    I am trying to change the implementation however it is proving to be quite difficult for me to connect it. I need to connect it in a way that I will know whether I am checking or unchecking the checkbox. I tried this every time I add a row:

            QTableWidgetItem* item = ui->table->item(dest_row, 0);
            item->setData(Qt::CheckStateRole,Qt::Checked); // makes the checkbox appear
            item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
    
            QObject::connect(ui->table->model(),&QAbstractItemModel::dataChanged,[item](const QModelIndex& topLeft,
                             const QModelIndex& bottomRight, const QVector<int>& roles)
            {
                if(item->data(Qt::CheckStateRole).value<Qt::CheckState>() == Qt::Checked)
                {
                    //do something
                }
            });
    
    

    But it is not practical since it becomes too slow when adding a lot of rows in a loop for example.

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

      Are you calling QObject::connect every time you add a row? No, that should only be done once when you create the model (in the constructor)

      "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, 16:36
      1
      • V VRonin
        16 Jun 2021, 16:28

        Are you calling QObject::connect every time you add a row? No, that should only be done once when you create the model (in the constructor)

        H Offline
        H Offline
        hbatalha
        wrote on 16 Jun 2021, 16:36 last edited by
        #12

        @VRonin yeah, I just did that to be able to grab the item. What I really want to know is just whether I am checking or unchecking.

        1 Reply Last reply
        0
        • 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

                            19/22

                            16 Jun 2021, 19:56

                            • Login

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