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

                          20/22

                          16 Jun 2021, 20:18

                          • Login

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