[SOLVED] Delegate won't call setModelData with a QWidget/TableView



  • I subclassed the AbstractTableModel and I created a TableView and myown Delegate
    If I create a QCheckBox or a QRadioButton etc.. and return it, the delegate works calling all functions like setEditorData, setModelData.
    But as I would move the control to the center of the cell, I tried the following code

    QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        if (!index.isValid())
            return QStyledItemDelegate::createEditor(parent, option, index);
    
        QWidget *w = new QWidget(parent);
        w->setAutoFillBackground(true);
        QVBoxLayout *layout = new QVBoxLayout;
        w->setLayout(layout);
    
        QCheckBox *cb = new QCheckBox();
        layout->addWidget(cb);
    
        return w;
    }
    

    With this code, the delegate calls UpdateGeometry, setEditorData, but never setModelData.

    If I use a TableWidget instead of a TableView, the delegate works fine.


  • Qt Champions 2016

    @giupigna

    http://doc.qt.io/qt-5/qstyleditemdelegate.html#setModelData

    Do you have a user property defined in your editor? If not, have you overriden the setModelData method of the delegate?



  • this is my overriden method:

    void Delegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
    if (!index.isValid())
    return QStyledItemDelegate::setModelData(editor, model, index);

    qDebug() << "setModelData";
    QCheckBox *cb = editor->findChild<QCheckBox*>();
    model->setData(index, cb->isChecked());
    

    }

    I don't have defined a User Property in my editor. How can I fix it?

    Thanks!


  • Qt Champions 2016

    @giupigna
    The user property is optional. In any case I noticed you don't commit the data from the editor and I believe this is why your setModelData method is not called.

    QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        // ...
        QCheckBox *cb = new QCheckBox();
        layout->addWidget(cb);
        
       //< You should commit the data when it's changed.
       QSignalMapper * mapper = new QSignalMapper(cb);
       mapper->setMapping(cb, w);
       QObject::connect(cb, SIGNAL(toggled(bool)), mapper, SLOT(map()));
       QObject::connect(mapper, SIGNAL(mapped(QWidget *)), this, SIGNAL(commitData(QWidget *)));
    }
    

    PS:
    You could look at the Star delegate example for further guidance



  • @kshegunov

    Yes I saw the Star delegate Example. In that code, the editor is a subclass of QWidget, like I want in my application.
    But the table in that case is a TableWidget and not a TableView. Infact I tried my code using a TableWidget and it works, but using a tableView it stops to work.
    I also connected the checkbox with a signal and slot to commitData to model, but "the program has unexpectedly finished"

    I don't understand why also if I create and return a QCheckbox, it works fine and I don't need any signal to emit.

    I've installed Qt 5.6.


  • Qt Champions 2016

    @giupigna

    But the table in that case is a TableWidget and not a TableView.

    QTableWidget is a convenience class that extends QTableView, it should work either way.

    I also connected the checkbox with a signal and slot to commitData to model, but "the program has unexpectedly finished"

    You should debug that. Probably you're getting a segmentation fault somewhere. If I had to guess this line:

    QCheckBox *cb = editor->findChild<QCheckBox*>();
    

    in Delegate::setModelData returns NULL and then calling cb->isChecked() is crashing (dereferencing NULL pointer is not possible).

    I don't understand why also if I create and return a QCheckbox, it works fine and I don't need any signal to emit.

    QCheckBox is derived from QAbstractButton, which in turn has the optional user property, so Qt knows what property change signifies that the data should be written to the model.



  • @kshegunov
    Ok, I fixed the bug crash. It was in the createEditor method. Now it's working.
    But if I would create a complex widget as editor, how can I create it using the USER property?

    class MyWidget : public QWidget
    {
        Q_OBJECT
        Q_PROPERTY(bool check READ check WRITE setCheck NOTIFY checkChanged USER true)
    public:
        explicit MyWidget(QWidget *parent = 0);
    
        bool check() const;
        void setCheck(bool value) const;
    
    Q_SIGNALS:
        void checkChanged(bool);
    
    private:
        QCheckBox *m_check;
    };
    

    where check and setCheck methods return and set the value of checkbox.

    How does the delegate realize that the bool variable is changed? Is it correct written in this way?

    Thanks so much!


  • Qt Champions 2016

    @giupigna said:

    How does the delegate realize that the bool variable is changed? Is it correct written in this way?

    Your code is correct (only remove the const modifier for setCheck). Do remember, however, to emit the notification signal from the setCheck method (or connect it to the toggled signal of the checkbox).

    void MyWidget::setCheck(bool value)
    {
        m_check->setChecked(value);
    
        emit checkChanged(value); //< This is how Qt knows when the property has changed
    }
    

    Or:

    MyWidget::MyWidget(QWidget * parent = NULL)
        : QWidget(parent), m_check(new QCheckBox(this))
    {
        QObject::connect(m_check, SIGNAL(toggled(bool)), this, SIGNAL(checkChanged(bool)));  //< Delegate the signal
    }
    
    void MyWidget::setCheck(bool value)
    {
        m_check->setChecked(value);  //< Should be sufficient, as the signal will be emitted when the checkbox's notification is raised
    }
    

    Thanks so much!

    No problem.


  • Lifetime Qt Champion

    Hi,

    @kshegunov , in your first implementation of setCheck, there's a check missing. You'll be emitting checkChanged even if m_check's current value is already matching the value of value.


  • Qt Champions 2016

    @SGaist
    Yes, good point. Thanks!


Log in to reply
 

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