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 1.3k 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.
  • Kent-DorfmanK Offline
    Kent-DorfmanK Offline
    Kent-Dorfman
    wrote on last edited by
    #2

    You don't mention the mouse/keyboard sequence you use to attempt multi-select. so, as remedial as it sounds, that is my first question.

    I light my way forward with the fires of all the bridges I've burned behind me.

    1 Reply Last reply
    0
    • J Offline
      J Offline
      Jackmill
      wrote on last edited by
      #3

      In terms of user input, either by clicking and dragging on rows, or using the shift or ctrl key as defined by the selection mode enum, and then clicking on the checkbox on any of the selected rows. I haven't tried programmatically selecting rows.

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

        You have to implement such a behavior by yourself. Simply retrieve the selected rows, iterate over them and set the check state you want.

        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 on 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 on 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 on 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 on 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 on 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 Online
                    jeremy_kJ Online
                    jeremy_k
                    wrote on 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 on 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 on 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 on 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 Online
                            jeremy_kJ Online
                            jeremy_k
                            wrote on 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