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.6k 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.
  • VRoninV VRonin

    @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 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
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on 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
      1
      • VRoninV VRonin

        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 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
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on 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
          3
          • VRoninV VRonin

            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 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.

            VRoninV 1 Reply Last reply
            0
            • H hbatalha

              @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.

              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on 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
              0
              • VRoninV VRonin

                @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 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
                • VRoninV VRonin

                  @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 last edited by
                  #17

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

                  1 Reply Last reply
                  0
                  • VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on 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
                    1
                    • VRoninV VRonin

                      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 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
                      0
                      • H hbatalha

                        @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 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
                        • VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on 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
                          1
                          • VRoninV VRonin

                            @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 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

                            • Login

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