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. [SOLVED] Delegate won't call setModelData with a QWidget/TableView
QtWS25 Last Chance

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

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 3 Posters 6.4k Views
  • 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.
  • giupignaG Offline
    giupignaG Offline
    giupigna
    wrote on last edited by giupigna
    #1

    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.

    kshegunovK 1 Reply Last reply
    0
    • giupignaG giupigna

      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.

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      @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?

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      0
      • giupignaG Offline
        giupignaG Offline
        giupigna
        wrote on last edited by
        #3

        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!

        kshegunovK 1 Reply Last reply
        0
        • giupignaG giupigna

          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!

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #4

          @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

          Read and abide by the Qt Code of Conduct

          giupignaG 1 Reply Last reply
          1
          • kshegunovK kshegunov

            @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

            giupignaG Offline
            giupignaG Offline
            giupigna
            wrote on last edited by
            #5

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

            kshegunovK 1 Reply Last reply
            0
            • giupignaG giupigna

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

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #6

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

              Read and abide by the Qt Code of Conduct

              giupignaG 1 Reply Last reply
              0
              • kshegunovK kshegunov

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

                giupignaG Offline
                giupignaG Offline
                giupigna
                wrote on last edited by
                #7

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

                kshegunovK 1 Reply Last reply
                0
                • giupignaG giupigna

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

                  kshegunovK Offline
                  kshegunovK Offline
                  kshegunov
                  Moderators
                  wrote on last edited by kshegunov
                  #8

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

                  Read and abide by the Qt Code of Conduct

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

                    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.

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

                    kshegunovK 1 Reply Last reply
                    0
                    • SGaistS SGaist

                      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.

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #10

                      @SGaist
                      Yes, good point. Thanks!

                      Read and abide by the Qt Code of Conduct

                      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