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. How to invoke QStyledItemDelegate::setModelData when using custom editors?
QtWS25 Last Chance

How to invoke QStyledItemDelegate::setModelData when using custom editors?

Scheduled Pinned Locked Moved Solved General and Desktop
delegatedelegate modelsetmodeldataeditorpush button
9 Posts 3 Posters 1.2k 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.
  • B Offline
    B Offline
    bibasmall
    wrote on 12 May 2023, 10:12 last edited by bibasmall 5 Dec 2023, 10:20
    #1

    Hello everyone!

    I'm using QPushButton as editor and I want to call QStyledItemDelegate::setModelData overrode method each time the button is clicked. So here is my code:

    QWidget* CEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
    {
              //...
              connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);
    }
    
    void CEditorDelegate::CommitData()
    {
    	QPushButton* editor = qobject_cast<QPushButton*>(sender());
    	if (!editor)
    		return;
    	emit commitData(editor);
    }
    
    void CEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
    {
            //...
    	model->setData(index, data, Qt::EditRole);
    }
    

    But I see that setModelData is never called. What am I doing wrong?
    I am also surprised that even here I saw an approach with std::bind in connect, so in my case that would be

    connect(pButton, &QPushButton::clicked, this, std::bind(&QStyledItemDelegate::commitData, this, pButton));
    

    But in fact it won't work, because QStyledItemDelegate::createEditor is const, so it looks like I am doing something wrong with my non-const CommitData method even if it's called due to successful connection.

    My code is based on this topic, for example:
    QStyledItemDelegate with Custom Widget: setModelData function never gets called

    J 1 Reply Last reply 12 May 2023, 10:32
    0
    • B bibasmall deleted this topic on 12 May 2023, 10:16
    • B bibasmall restored this topic on 12 May 2023, 10:19
    • J JonB
      12 May 2023, 11:29

      @James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

      is that you are not emitting the commitData signal from your CommitData method.

      But the OP has always shown he does do that.

      Here's how you can modify your CommitData method to emit the commitData signal:

      void CEditorDelegate::CommitData()
      {
          QPushButton* editor = qobject_cast<QPushButton*>(sender());
          if (!editor)
              return;
          emit commitData(editor); // emit the commitData signal
      }
      

      This is precisely what the OP showed he currently has, character for character.

      B Offline
      B Offline
      bibasmall
      wrote on 12 May 2023, 12:19 last edited by bibasmall 5 Dec 2023, 12:26
      #8

      @JonB
      In addition to my previous post — setModelData is called with such connects, so it seems with sender() I just abused a bug.

      connect(pButton, &QPushButton::clicked, this, std::bind(&CEditorDelegate::CommitData, const_cast<CEditorDelegate*>(this), pButton));
      //or
      connect(pButton, &QPushButton::clicked, [nonConstThis = const_cast<CEditorDelegate*>(this), pButton]() { nonConstThis->CommitData(pButton); });
      

      Actually I don't understand how do I customise editors behaviour more elegantly (considering const_cast a bad practise), since most of the QStyledItemDelegate methods are constant while signals are not.

      1 Reply Last reply
      0
      • B bibasmall
        12 May 2023, 10:12

        Hello everyone!

        I'm using QPushButton as editor and I want to call QStyledItemDelegate::setModelData overrode method each time the button is clicked. So here is my code:

        QWidget* CEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
        {
                  //...
                  connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);
        }
        
        void CEditorDelegate::CommitData()
        {
        	QPushButton* editor = qobject_cast<QPushButton*>(sender());
        	if (!editor)
        		return;
        	emit commitData(editor);
        }
        
        void CEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
        {
                //...
        	model->setData(index, data, Qt::EditRole);
        }
        

        But I see that setModelData is never called. What am I doing wrong?
        I am also surprised that even here I saw an approach with std::bind in connect, so in my case that would be

        connect(pButton, &QPushButton::clicked, this, std::bind(&QStyledItemDelegate::commitData, this, pButton));
        

        But in fact it won't work, because QStyledItemDelegate::createEditor is const, so it looks like I am doing something wrong with my non-const CommitData method even if it's called due to successful connection.

        My code is based on this topic, for example:
        QStyledItemDelegate with Custom Widget: setModelData function never gets called

        J Offline
        J Offline
        JonB
        wrote on 12 May 2023, 10:32 last edited by
        #2

        @bibasmall said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

        But I see that setModelData is never called. What am I doing wrong?

        You use QPushButton* editor = qobject_cast<QPushButton*>(sender());. I would never use sender(). Have you verified what that is returning? If sender() is nullptr or not a QPushButton* you won't emit commitData(editor).

        B 1 Reply Last reply 12 May 2023, 10:44
        0
        • J JonB
          12 May 2023, 10:32

          @bibasmall said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

          But I see that setModelData is never called. What am I doing wrong?

          You use QPushButton* editor = qobject_cast<QPushButton*>(sender());. I would never use sender(). Have you verified what that is returning? If sender() is nullptr or not a QPushButton* you won't emit commitData(editor).

          B Offline
          B Offline
          bibasmall
          wrote on 12 May 2023, 10:44 last edited by bibasmall 5 Dec 2023, 10:54
          #3

          @JonB
          What would you use instead of sender()?
          The other way I see here is const_cast<CEditorDelegate*>(this) in CEditorDelegate::createEditor, what is really ugly.

          @JonB said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

          Have you verified what that is returning?

          I did, I see that commitData is actually emitted in debugger.

          J 1 Reply Last reply 12 May 2023, 11:26
          0
          • J Offline
            J Offline
            James Gallegos
            wrote on 12 May 2023, 11:23 last edited by
            #4

            The reason why the setModelData method is not being called is that you are not emitting the commitData signal from your CommitData method. The commitData signal is what triggers the setModelData method in the delegate. Therefore, you need to emit this signal from your CommitData method.

            Here's how you can modify your CommitData method to emit the commitData signal:

            void CEditorDelegate::CommitData()
            {
                QPushButton* editor = qobject_cast<QPushButton*>(sender());
                if (!editor)
                    return;
                emit commitData(editor); // emit the commitData signal
            }
            
            

            Regarding your use of std::bind in the connect statement, it is unnecessary and can be replaced with a lambda function that calls the CommitData method directly. The const qualifier on the createEditor method is not relevant here, as you are not trying to modify the object's state within the method.

            Here's an example of how you can modify the connect statement to use a lambda function:

            connect(pButton, &QPushButton::clicked, this, [this, pButton]() {
                CommitData();
            });
            
            

            This lambda function captures this and pButton by value, and calls the CommitData method when the button is clicked.

            J 1 Reply Last reply 12 May 2023, 11:29
            0
            • B bibasmall
              12 May 2023, 10:44

              @JonB
              What would you use instead of sender()?
              The other way I see here is const_cast<CEditorDelegate*>(this) in CEditorDelegate::createEditor, what is really ugly.

              @JonB said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

              Have you verified what that is returning?

              I did, I see that commitData is actually emitted in debugger.

              J Offline
              J Offline
              JonB
              wrote on 12 May 2023, 11:26 last edited by
              #5

              @bibasmall
              sender() became unnecessary when new style connect() syntax allowing C++ lambdas for slots was introduced a decade ago.

              connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(pButton); } );
              
              void CEditorDelegate::CommitData(QPushButton *btn)
              {
              }
              

              I'm not sure about why your emit commitData(editor) does not cause setModelData() to be called. When I did editing delegates I did not emit commitData(editor) and I did not have another widget like a button to conclude editing. I just overrode setEditorData() & setModelData(), and it all just "worked".

              B 1 Reply Last reply 12 May 2023, 11:48
              0
              • J James Gallegos
                12 May 2023, 11:23

                The reason why the setModelData method is not being called is that you are not emitting the commitData signal from your CommitData method. The commitData signal is what triggers the setModelData method in the delegate. Therefore, you need to emit this signal from your CommitData method.

                Here's how you can modify your CommitData method to emit the commitData signal:

                void CEditorDelegate::CommitData()
                {
                    QPushButton* editor = qobject_cast<QPushButton*>(sender());
                    if (!editor)
                        return;
                    emit commitData(editor); // emit the commitData signal
                }
                
                

                Regarding your use of std::bind in the connect statement, it is unnecessary and can be replaced with a lambda function that calls the CommitData method directly. The const qualifier on the createEditor method is not relevant here, as you are not trying to modify the object's state within the method.

                Here's an example of how you can modify the connect statement to use a lambda function:

                connect(pButton, &QPushButton::clicked, this, [this, pButton]() {
                    CommitData();
                });
                
                

                This lambda function captures this and pButton by value, and calls the CommitData method when the button is clicked.

                J Offline
                J Offline
                JonB
                wrote on 12 May 2023, 11:29 last edited by JonB 5 Dec 2023, 11:31
                #6

                @James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

                is that you are not emitting the commitData signal from your CommitData method.

                But the OP has always shown he does do that.

                Here's how you can modify your CommitData method to emit the commitData signal:

                void CEditorDelegate::CommitData()
                {
                    QPushButton* editor = qobject_cast<QPushButton*>(sender());
                    if (!editor)
                        return;
                    emit commitData(editor); // emit the commitData signal
                }
                

                This is precisely what the OP showed he currently has, character for character.

                B 1 Reply Last reply 12 May 2023, 12:19
                0
                • J JonB
                  12 May 2023, 11:26

                  @bibasmall
                  sender() became unnecessary when new style connect() syntax allowing C++ lambdas for slots was introduced a decade ago.

                  connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(pButton); } );
                  
                  void CEditorDelegate::CommitData(QPushButton *btn)
                  {
                  }
                  

                  I'm not sure about why your emit commitData(editor) does not cause setModelData() to be called. When I did editing delegates I did not emit commitData(editor) and I did not have another widget like a button to conclude editing. I just overrode setEditorData() & setModelData(), and it all just "worked".

                  B Offline
                  B Offline
                  bibasmall
                  wrote on 12 May 2023, 11:48 last edited by bibasmall 5 Dec 2023, 11:56
                  #7

                  @JonB
                  The reason why I used sender() is on the screenshot — my code won't compile if I call the non-const method for const this .
                  842a332c-9e04-4c2b-8675-698c4b838be6-image.png
                  Somehow it compiles when CommitData has no arguments and the connection looks like this (so that's why I get the pointer to the editor from sender()):

                  connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);
                  

                  Though I'm sure it's a bug and it shouldn't compile for the same qualifier reason.
                  I've used the same approach before to force QCombobox close right after selecting an option, so I emitted two signals:

                  	emit commitData(editor);
                  	emit closeEditor(editor);
                  

                  And I had no problem with invoking setModelData. But for a button setModelData is just silently not called. I see that the signal is emitted after I click the button, but no reaction after.

                  J 1 Reply Last reply 12 May 2023, 12:20
                  0
                  • J JonB
                    12 May 2023, 11:29

                    @James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:

                    is that you are not emitting the commitData signal from your CommitData method.

                    But the OP has always shown he does do that.

                    Here's how you can modify your CommitData method to emit the commitData signal:

                    void CEditorDelegate::CommitData()
                    {
                        QPushButton* editor = qobject_cast<QPushButton*>(sender());
                        if (!editor)
                            return;
                        emit commitData(editor); // emit the commitData signal
                    }
                    

                    This is precisely what the OP showed he currently has, character for character.

                    B Offline
                    B Offline
                    bibasmall
                    wrote on 12 May 2023, 12:19 last edited by bibasmall 5 Dec 2023, 12:26
                    #8

                    @JonB
                    In addition to my previous post — setModelData is called with such connects, so it seems with sender() I just abused a bug.

                    connect(pButton, &QPushButton::clicked, this, std::bind(&CEditorDelegate::CommitData, const_cast<CEditorDelegate*>(this), pButton));
                    //or
                    connect(pButton, &QPushButton::clicked, [nonConstThis = const_cast<CEditorDelegate*>(this), pButton]() { nonConstThis->CommitData(pButton); });
                    

                    Actually I don't understand how do I customise editors behaviour more elegantly (considering const_cast a bad practise), since most of the QStyledItemDelegate methods are constant while signals are not.

                    1 Reply Last reply
                    0
                    • B bibasmall
                      12 May 2023, 11:48

                      @JonB
                      The reason why I used sender() is on the screenshot — my code won't compile if I call the non-const method for const this .
                      842a332c-9e04-4c2b-8675-698c4b838be6-image.png
                      Somehow it compiles when CommitData has no arguments and the connection looks like this (so that's why I get the pointer to the editor from sender()):

                      connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);
                      

                      Though I'm sure it's a bug and it shouldn't compile for the same qualifier reason.
                      I've used the same approach before to force QCombobox close right after selecting an option, so I emitted two signals:

                      	emit commitData(editor);
                      	emit closeEditor(editor);
                      

                      And I had no problem with invoking setModelData. But for a button setModelData is just silently not called. I see that the signal is emitted after I click the button, but no reaction after.

                      J Offline
                      J Offline
                      JonB
                      wrote on 12 May 2023, 12:20 last edited by JonB 5 Dec 2023, 12:26
                      #9

                      @bibasmall
                      I'm not understanding what is going on with your const or not. The slot CommitData() must not be const. Is it??

                      Hmm, you mean you call it from CEditorDelegate::createEditor(), that is const, so its this is const, and you can't then use that for the slot object? Then I really don't know why it's OK for the connect() to actual slot but not to lambda (I suspect it's this issue, not because the new CommitData(QPushButton *btn) parameter....

                      Is your CommitData() const? Doesn't look like it. If you made it const does that allow the connect()?

                      UPDATE
                      I think this has crossed with your latest. I believe you show there you have found a way. I prefer the second one.

                      Basically you have raised a "gotcha": createEditor() is const, and that prevents you from connecting a slot to this inside it, which is something one might well want to do. It (apparently) works when &CEditorDelegate::CommitData is passed on its own as a standalone argument, but not if you try a lambda with this->CommitData(). If the C++ super-experts here see this they might comment....

                      1 Reply Last reply
                      0
                      • B bibasmall has marked this topic as solved on 12 May 2023, 14:48

                      7/9

                      12 May 2023, 11:48

                      • Login

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