Signal for checkbox toggle in QListWidget or QTableWidget



  • 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!


  • Lifetime Qt Champion

    Hi,

    What is your purpose for that signal ?



  • 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



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



  • 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);



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


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.