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. Signal for checkbox toggle in QListWidget or QTableWidget

Signal for checkbox toggle in QListWidget or QTableWidget

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 4 Posters 5.1k 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
    Jendker
    wrote on last edited by
    #1

    Hello everyone!

    I am struggling with getting the signal while the checkbox toggle (either change to 'Qt::Checked' or 'Qt::Unchecked') in QListWidget or QTableWidget. I am creating the checkboxes according to this post: https://forum.qt.io/post/172238 by SetBetterPass. The problem is that the QStandardItem does not have the signal for 'check' or 'uncheck', what I managed to do was to have the signal when the item is clicked with e.g. QListWidget::itemChanged, but it is not what I am looking for...

    I was searching for the solution on my own for a long time, but because I did not find anything suitable I am writing my question here.

    Thank you for your help!

    1 Reply Last reply
    1
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What is your purpose for that signal ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • AmoghA Offline
        AmoghA Offline
        Amogh
        wrote on last edited by
        #3

        You have to write your own signal, and check if the condition is checked or unchecked according to your requirements and then emit the signal in that condition

        1 Reply Last reply
        1
        • J Offline
          J Offline
          Jendker
          wrote on last edited by
          #4

          Thanks a lot for your answers and sorry for not responding for so long...

          @SGaist
          I would like to add the counter in the GUI which would show how many fields in the QTableWidget or QListWidgets are checked. I guess it would have to emit the signal every time the checkbox's state is change.

          The thing is, that having any signal, which would only intercepting clicking on the field would not be enough, because the state can be also changed by the button, which selects / deselects all the variables. So actually the state of the checkbox should be observed.

          1 Reply Last reply
          0
          • VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by VRonin
            #5

            For what you are doing there are 2 solutions:

            The first one is easy but is a drag on performance if your table/list becomes big. Just recount the checked cells after any dataChanged signal:

            QObject::connect(tableWidget->model(), &QAbstractItemModel::dataChanged, [this]()->void {
                    const int rowCount = tableWidget->model()->rowCount();
                    unsigned int checkedCells = 0;
                    for (int i = 0; i < rowCount; ++i) {
                        if (tableWidget->model()->index(i, 0/*change column according to use case*/).data(Qt::CheckStateRole).toInt() == Qt::Checked)
                            ++checkedCells;
                    }
                    countCheckedLabel->setText(countCheckedLabel->locale().toString(checkedCells));
                });
            

            the alternative is setting up a proper "signal" for the check changing. This is more complicated but is much faster (at a cost of more memory, of course)

            private:
                enum { OldCheckRole = Qt::CheckStateRole + Qt::UserRole };
                Q_SIGNAL void checkChanged(const QModelIndex&);
                Q_SLOT void checkTheCheck(const QModelIndex& topLeft, const QModelIndex& bottomRight)
                {
                    Q_ASSERT(topLeft.isValid());
                    Q_ASSERT(bottomRight.isValid());
                    Q_ASSERT(topLeft.model() == tableWidget->model());
                    const QModelIndex parentIdx = topLeft.parent();
                    Q_ASSERT(parentIdx == bottomRight.parent()); //avoid undefined behavior
                    for (int rowItr = topLeft.row(); rowItr <= bottomRight.row(); ++rowItr) {
                        for (int colItr = topLeft.column(); colItr <= bottomRight.column(); ++colItr) {
                            const QModelIndex currIdx = topLeft.model()->index(rowItr, colItr, parentIdx);
                            if (currIdx.data(Qt::CheckStateRole).toInt() == currIdx.data(OldCheckRole).toInt())
                                continue; // the check did not change, nothing to do
                            tableWidget->model()->setData(currIdx, currIdx.data(Qt::CheckStateRole), OldCheckRole);
                            checkChanged(currIdx);
                        }
                    }
                }
            

            then before doing anything with the widget do the connection:
            QObject::connect(tableWidget->model(),&QAbstractItemModel::dataChanged,this,&MyClass::checkTheCheck);

            "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

            J 1 Reply Last reply
            5
            • VRoninV VRonin

              For what you are doing there are 2 solutions:

              The first one is easy but is a drag on performance if your table/list becomes big. Just recount the checked cells after any dataChanged signal:

              QObject::connect(tableWidget->model(), &QAbstractItemModel::dataChanged, [this]()->void {
                      const int rowCount = tableWidget->model()->rowCount();
                      unsigned int checkedCells = 0;
                      for (int i = 0; i < rowCount; ++i) {
                          if (tableWidget->model()->index(i, 0/*change column according to use case*/).data(Qt::CheckStateRole).toInt() == Qt::Checked)
                              ++checkedCells;
                      }
                      countCheckedLabel->setText(countCheckedLabel->locale().toString(checkedCells));
                  });
              

              the alternative is setting up a proper "signal" for the check changing. This is more complicated but is much faster (at a cost of more memory, of course)

              private:
                  enum { OldCheckRole = Qt::CheckStateRole + Qt::UserRole };
                  Q_SIGNAL void checkChanged(const QModelIndex&);
                  Q_SLOT void checkTheCheck(const QModelIndex& topLeft, const QModelIndex& bottomRight)
                  {
                      Q_ASSERT(topLeft.isValid());
                      Q_ASSERT(bottomRight.isValid());
                      Q_ASSERT(topLeft.model() == tableWidget->model());
                      const QModelIndex parentIdx = topLeft.parent();
                      Q_ASSERT(parentIdx == bottomRight.parent()); //avoid undefined behavior
                      for (int rowItr = topLeft.row(); rowItr <= bottomRight.row(); ++rowItr) {
                          for (int colItr = topLeft.column(); colItr <= bottomRight.column(); ++colItr) {
                              const QModelIndex currIdx = topLeft.model()->index(rowItr, colItr, parentIdx);
                              if (currIdx.data(Qt::CheckStateRole).toInt() == currIdx.data(OldCheckRole).toInt())
                                  continue; // the check did not change, nothing to do
                              tableWidget->model()->setData(currIdx, currIdx.data(Qt::CheckStateRole), OldCheckRole);
                              checkChanged(currIdx);
                          }
                      }
                  }
              

              then before doing anything with the widget do the connection:
              QObject::connect(tableWidget->model(),&QAbstractItemModel::dataChanged,this,&MyClass::checkTheCheck);

              J Offline
              J Offline
              Jendker
              wrote on last edited by
              #6

              @VRonin

              Very impressive! Thank you for your input! Works like a charm :) I guess I need to get a bit more familiar with the Model/View programming, it is very powerful.

              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