0

I'm having trouble with correctly implementing a column of checkboxes on a class that inherits from QAbstractTableModel. Each row in the table has a checkbox that's initially checked when a new item comes in, which I need to be unchecked.

I've tried returning Qt::unchecked initially in setData, but when I do that I can't check/uncheck the box. Each item has an internal attribute checked, accessed via is_Checked(item #), set_Checked(item #). Below is code from the .cpp file, using Qt 4.11

QVariant ClassItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant();
    }

    int r = index.row();
    if (r >= m_data.size() || r < 0)
        return QVariant();

    int c = index.column();

    if (role == Qt::CheckStateRole)
    {
        if (c == 0)
        {
                //line below doesn't work since m_data[r].checked is set to false
                //initially, so when it returns Qt::Unchecked, it can't be toggled
                //
                //return m_data[r].is_Checked ? Qt::Checked : Qt::Unchecked

                //this works, but each new item in the table is initially checked since display is 
                //always true
                if (m_data[r].display)
                {
                    return Qt::Checked;
                }
                else
                {
                    return Qt::Unchecked;
                }
        }
    }

bool ClassItemmodel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
    {
        return false;
    }
    emit layoutAboutToBeChanged();
    int r = index.row();
    int c = index.column();

    if (role == Qt::CheckStateRole)
    {
        if (c == 0)
        {
            bool b = value.toBool();
            m_data[r].display = b;
            if(static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked)
            {
                set_Checked(r,false);
            }
            else
            {
                set_Checked(r,true);
            }
            if (!b)
            {
                emit layoutChanged();
            }
        }
    }
    return QAbstractItemModel::setData(index, value, role);
}

Qt::ItemFlags ClassItemModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    int c = index.column();

    if (c == 0)
    {
        return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
    }
    ....
 }
sean1441
  • 9
  • 2

1 Answers1

0

You are implementing setData() wrongly.

In data(), you can go back to using return m_data[r].is_Checked ? Qt::Checked : Qt::Unchecked;.

In setData(),

if (role == Qt::CheckStateRole)
{
    if (c == 0)
    {
        bool b = value.toBool();
        m_data[r].is_Checked = b;
        set_Checked(r, value == Qt::Checked);
        emit dataChanged(index, index, {role});
        if (!b)
            emit layoutChanged();
        return true;
    }
}
return QAbstractItemModel::setData(index, value, role);

Notice that dataChanged() has to be emited in the subclass and setData() returns true when the data is successfully set. The base class implementation always returns false.

Check QAbstractItemModel::setData()

Minh
  • 1,630
  • 1
  • 8
  • 18
  • 1
    That's a great point, I noticed during a unit test that it was always returning false. Still having the issue where each item is checked once its loaded into the table. Going to try and call automatically the setData function each time a new item is loaded to make the checkbox unchecked. – sean1441 Oct 07 '20 at 13:11