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. QListWidget with checkboxes - checking more than one row at a time
Forum Updated to NodeBB v4.3 + New Features

QListWidget with checkboxes - checking more than one row at a time

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 4 Posters 186 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.
  • J Offline
    J Offline
    Jackmill
    wrote last edited by Jackmill
    #5

    I think the challenge I'm having with that is differentiating between when the user clicks on the checkbox and when the user clicks anywhere in the QListView.

    I have tried subclassing QListView and reimplementing mouseReleaseEvent, but it never seems to be called:

    class MassCheckView : public QListView {
    	Q_OBJECT
    	public:
    		explicit MassCheckView(QWidget* parent = nullptr) : QListView(parent) {}
    
    		void mouseReleaseEvent(QMouseEvent *event) override;
    };
    

    --

    void MassCheckView::mouseReleaseEvent(QMouseEvent *event) {
    	auto under_mouse = childAt(event->position());
    	if (under_mouse) {
    		const auto indices = selectionModel()->selectedIndexes();
    		const auto first_checked = model()->data(indices.at(0), Qt::CheckStateRole).value<Qt::CheckState>();
    
    		for (const auto& idx : indices) {
    			model()->setData(model()->index(idx.row(), idx.column(), QModelIndex()),
    				first_checked ? Qt::Unchecked : Qt::Checked,
    				Qt::CheckStateRole);
    		}
    
    		return;
    	}
    
    	QListView::mouseReleaseEvent(event);
    }
    
    1 Reply Last reply
    0
    • Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote last edited by
      #6

      Now you're using a QListView instead a QListWidget... you have to monitor your model to see when the checkstate changed then.

      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
      0
      • J Offline
        J Offline
        Jackmill
        wrote last edited by
        #7

        Oh shoot; that's my mistake -- I've meant QListView for this whole post.

        How might I go about that? I can connect something to dataChanged, but as far as I'm aware it will still only change one index at a time regardless of how many rows are selected.

        Christian EhrlicherC 1 Reply Last reply
        0
        • J Jackmill

          Oh shoot; that's my mistake -- I've meant QListView for this whole post.

          How might I go about that? I can connect something to dataChanged, but as far as I'm aware it will still only change one index at a time regardless of how many rows are selected.

          Christian EhrlicherC Online
          Christian EhrlicherC Online
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote last edited by
          #8

          @Jackmill said in QListWidget with checkboxes - checking more than one row at a time:

          far as I'm aware it will still only change one index at a time regardless of how many rows are selected.

          Yes, you get the dataChanged() signal, then lookup the selection and set the rest.

          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
          0
          • J Offline
            J Offline
            Jackmill
            wrote last edited by
            #9

            I see. This seems to work:

            connect(model, &QAbstractListModel::dataChanged,
            		this, [table, model](const QModelIndex& topLeft, const QModelIndex& bottomRight) {
            			const auto selection = table->selectionModel()->selectedIndexes();
            
            			if (selection.isEmpty()) { return; }
            
            			const auto check = model->data(topLeft, Qt::CheckStateRole).value<Qt::CheckState>();
            
            			model->setDataChangedEnabled(false);
            			for (const auto& idx : selection) {
            				if (!idx.isValid() || idx == topLeft) { continue; }
            
            				model->setData(idx, check ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
            			}
            			model->setDataChangedEnabled(true);
            		});
            

            Enabling and disabling the emission of the dataChanged like this seems a little clunky but without it there's an endless loop and segfault.

            jeremy_kJ Christian EhrlicherC 2 Replies Last reply
            0
            • J Jackmill

              I see. This seems to work:

              connect(model, &QAbstractListModel::dataChanged,
              		this, [table, model](const QModelIndex& topLeft, const QModelIndex& bottomRight) {
              			const auto selection = table->selectionModel()->selectedIndexes();
              
              			if (selection.isEmpty()) { return; }
              
              			const auto check = model->data(topLeft, Qt::CheckStateRole).value<Qt::CheckState>();
              
              			model->setDataChangedEnabled(false);
              			for (const auto& idx : selection) {
              				if (!idx.isValid() || idx == topLeft) { continue; }
              
              				model->setData(idx, check ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
              			}
              			model->setDataChangedEnabled(true);
              		});
              

              Enabling and disabling the emission of the dataChanged like this seems a little clunky but without it there's an endless loop and segfault.

              jeremy_kJ Offline
              jeremy_kJ Offline
              jeremy_k
              wrote last edited by
              #10

              @Jackmill said in QListWidget with checkboxes - checking more than one row at a time:

              Enabling and disabling the emission of the dataChanged like this seems a little clunky but without it there's an endless loop and segfault.

              Blocking the dataChanged signal means that the view won't know that a particular cell needs to be redrawn. A flag or list of indexes to be modified could accomplish the same goal while leaving view management intact.

              Asking a question about code? http://eel.is/iso-c++/testcase/

              J 1 Reply Last reply
              0
              • J Jackmill

                I see. This seems to work:

                connect(model, &QAbstractListModel::dataChanged,
                		this, [table, model](const QModelIndex& topLeft, const QModelIndex& bottomRight) {
                			const auto selection = table->selectionModel()->selectedIndexes();
                
                			if (selection.isEmpty()) { return; }
                
                			const auto check = model->data(topLeft, Qt::CheckStateRole).value<Qt::CheckState>();
                
                			model->setDataChangedEnabled(false);
                			for (const auto& idx : selection) {
                				if (!idx.isValid() || idx == topLeft) { continue; }
                
                				model->setData(idx, check ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
                			}
                			model->setDataChangedEnabled(true);
                		});
                

                Enabling and disabling the emission of the dataChanged like this seems a little clunky but without it there's an endless loop and segfault.

                Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote last edited by
                #11

                @Jackmill said in QListWidget with checkboxes - checking more than one row at a time:

                check ? Qt::Checked

                And this is wrong - see https://doc.qt.io/qt-6/qt.html#CheckState-enum
                simply pass check

                Also notice that you have to map the indexes as soon as you have a proxy model in between.

                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
                0
                • jeremy_kJ jeremy_k

                  @Jackmill said in QListWidget with checkboxes - checking more than one row at a time:

                  Enabling and disabling the emission of the dataChanged like this seems a little clunky but without it there's an endless loop and segfault.

                  Blocking the dataChanged signal means that the view won't know that a particular cell needs to be redrawn. A flag or list of indexes to be modified could accomplish the same goal while leaving view management intact.

                  J Offline
                  J Offline
                  Jackmill
                  wrote last edited by
                  #12

                  @jeremy_k said in QListWidget with checkboxes - checking more than one row at a time:

                  A flag or list of indexes to be modified could accomplish the same goal while leaving view management intact.

                  How might I do this? I'm having trouble thinking of a way to call setData without causing an endless loop.

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Online
                    Christian EhrlicherC Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote last edited by
                    #13

                    Just remeber which you already have set and that you're currently setting the other checkboxes.

                    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
                    0
                    • jeremy_kJ Offline
                      jeremy_kJ Offline
                      jeremy_k
                      wrote last edited by
                      #14

                      @Jackmill said in QListWidget with checkboxes - checking more than one row at a time:

                      @jeremy_k said in QListWidget with checkboxes - checking more than one row at a time:

                      A flag or list of indexes to be modified could accomplish the same goal while leaving view management intact.

                      How might I do this? I'm having trouble thinking of a way to call setData without causing an endless loop.

                      void onDataChanged(const QModelIndex topLeft, const QModelIndex bottomRight, const QList<int> &roles)
                      {
                          static bool updating = false;
                          if (roles.contains(ItemDataRole::CheckStateRole) && !updating) {
                              updating = true;
                              auto value = topLeft.data(ItemDataRole::CheckStateRole);
                              for (auto index : selectionModel.selectedIndexes())
                                  model->setData(index, ItemDataRole::CheckStateRole, value);
                              updating = false;
                          }
                      }
                      

                      The code could also disconnect this (and only this) slot from the signal prior to the loop, and reconnect it at the end.

                      Asking a question about code? http://eel.is/iso-c++/testcase/

                      1 Reply Last reply
                      1

                      • Login

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