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.
  • G Offline
    G Offline
    giupigna
    wrote on 15 Apr 2016, 07:51 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.

    K 1 Reply Last reply 15 Apr 2016, 08:17
    0
    • G giupigna
      15 Apr 2016, 07:51

      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.

      K Offline
      K Offline
      kshegunov
      Moderators
      wrote on 15 Apr 2016, 08:17 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
      • G Offline
        G Offline
        giupigna
        wrote on 15 Apr 2016, 09:02 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!

        K 1 Reply Last reply 15 Apr 2016, 09:19
        0
        • G giupigna
          15 Apr 2016, 09:02

          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!

          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 15 Apr 2016, 09:19 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

          G 1 Reply Last reply 15 Apr 2016, 09:54
          1
          • K kshegunov
            15 Apr 2016, 09:19

            @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

            G Offline
            G Offline
            giupigna
            wrote on 15 Apr 2016, 09:54 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.

            K 1 Reply Last reply 15 Apr 2016, 10:12
            0
            • G giupigna
              15 Apr 2016, 09:54

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

              K Offline
              K Offline
              kshegunov
              Moderators
              wrote on 15 Apr 2016, 10:12 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

              G 1 Reply Last reply 15 Apr 2016, 12:02
              0
              • K kshegunov
                15 Apr 2016, 10:12

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

                G Offline
                G Offline
                giupigna
                wrote on 15 Apr 2016, 12:02 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!

                K 1 Reply Last reply 15 Apr 2016, 12:30
                0
                • G giupigna
                  15 Apr 2016, 12:02

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

                  K Offline
                  K Offline
                  kshegunov
                  Moderators
                  wrote on 15 Apr 2016, 12:30 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
                  • S Offline
                    S Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on 15 Apr 2016, 20:31 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

                    K 1 Reply Last reply 16 Apr 2016, 01:02
                    0
                    • S SGaist
                      15 Apr 2016, 20:31

                      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.

                      K Offline
                      K Offline
                      kshegunov
                      Moderators
                      wrote on 16 Apr 2016, 01:02 last edited by
                      #10

                      @SGaist
                      Yes, good point. Thanks!

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      0

                      9/10

                      15 Apr 2016, 20:31

                      • Login

                      • Login or register to search.
                      9 out of 10
                      • First post
                        9/10
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved