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. setModelData crashes program
Forum Updated to NodeBB v4.3 + New Features

setModelData crashes program

Scheduled Pinned Locked Moved Unsolved General and Desktop
29 Posts 8 Posters 8.2k Views 3 Watching
  • 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.
  • mrjjM mrjj

    Hi
    Just a small question.
    Is this code related to
    https://forum.qt.io/topic/83393/centering-qcombobox-in-table-cell
    where you also used a layout to center the combobox ?
    I wonder if the
    QComboBox* whatComboEditor = qobject_cast<QComboBox*>(editor);
    then is correct ?
    but add check to it
    if (!whatComboEditor) {
    qDebug() << "fail to cast whatComboEditor";
    return;
    }

    G Offline
    G Offline
    gabor53
    wrote on last edited by
    #10

    @mrjj
    It is related to the referenced post. This is part of the same delegate. I added the suggested check and I got the "fail to cast whatComboEditor" message.
    Here is the whole delegate:

    #include "whatfixviewdelegate.h"
    
    WhatFixViewDelegate::WhatFixViewDelegate(QObject* parent) : QStyledItemDelegate(parent) {
    
    }
    
    QWidget* WhatFixViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
    
      Q_UNUSED(option);
      Q_UNUSED(index);
    
      QWidget* w = new QWidget( parent );
    
      QComboBox* whatComboEditor = new QComboBox(w);
      whatComboEditor->setFrame(true);
      whatComboEditor->setStyleSheet("background-color:rgb(255,217,229);" );
      whatComboEditor->setEditable(true);
    
      whatComboEditor->setMaximumWidth (100);
      whatComboEditor->setMinimumWidth (100);
      whatComboEditor->setMaximumHeight (30);
      whatComboEditor->setMinimumHeight (30);
    
      whatComboEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
      QVBoxLayout* whatLayout = new QVBoxLayout;
      whatLayout->addWidget (whatComboEditor, 0, Qt::AlignCenter);
      whatLayout->setMargin (2);
    
      w->setLayout (whatLayout);
    
      QSqlQuery queryLoadWhat("SELECT What FROM  What_Table ORDER BY What asc", db);
    
      while(queryLoadWhat.next()) {
        QString whatItem = queryLoadWhat.value(0).toString();
        whatComboEditor->addItem(whatItem);
      }
      return w;
    }
    
    void WhatFixViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
    
      QComboBox* whatComboEditor = qobject_cast<QComboBox*>(editor);
      if(whatComboEditor) {
        whatComboEditor->addItem(index.model()->data(index, Qt::EditRole).toString());
        whatComboEditor->setCurrentText(index.model()->data(index, Qt::EditRole).toString());
      }
    }
    
    void WhatFixViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
      Q_UNUSED(index);
    
      editor->setGeometry(option.rect);
    }
    
    void WhatFixViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* fixModel, const QModelIndex& index) const {
      QComboBox* whatComboEditor = qobject_cast<QComboBox*>(editor);
      if (!whatComboEditor) {
        qDebug() << "fail to cast whatComboEditor";
        return;
      }
    
    
    
      QString newWhatText;
    
      newWhatText = whatComboEditor->currentText ();//crashes
      qDebug() << "newWhatText: " <<  whatComboEditor->currentText ();
    
      fixModel->setData (index, newWhatText, Qt::EditRole);
    
      fixModel->submit ();
    }
    
    

    What should be the next step? Thank you.

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #11

      Hi
      You should find the combobox in the widget with
      QComboBox* whatComboEditor = editor->findChild< QComboBox*>();
      if (whatComboEditor ) { ...use it... }
      in the other functions since you now have a real widget in between.
      as you say

      QWidget* WhatFixViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
        QWidget* w = new QWidget( parent );
      ....
        return w; <<< that is the place holder widget you return as "editor"
      }
      
      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #12

        In your case, you should call findChild on editor. Your QComboBox is in a layout inside a QWidget so you can't cast it like that directly.

        An alternative would be to create a custom widget which wraps the QComboBox and that you could use in the same manner.

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

        1 Reply Last reply
        3
        • JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #13

          And always check the return result of a qobject_cast<>, for safety, certainly while developing! :)

          JonBJ 1 Reply Last reply
          4
          • G Offline
            G Offline
            gabor53
            wrote on last edited by
            #14

            Thank you. I redid it as recommended and now it looks like this:

            #include "whatfixviewdelegate.h"
            
            WhatFixViewDelegate::WhatFixViewDelegate(QObject* parent) : QStyledItemDelegate(parent) {
            
            }
            
            QWidget* WhatFixViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
            
              Q_UNUSED(option);
              Q_UNUSED(index);
            
              QWidget* w = new QWidget( parent );
            
              QComboBox* whatComboEditor = new QComboBox(w);
              whatComboEditor->setFrame(true);
              whatComboEditor->setStyleSheet("background-color:rgb(255,217,229);" );
              whatComboEditor->setEditable(true);
            
              whatComboEditor->setMaximumWidth (100);
              whatComboEditor->setMinimumWidth (100);
              whatComboEditor->setMaximumHeight (30);
              whatComboEditor->setMinimumHeight (30);
            
              whatComboEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
            
              QVBoxLayout* whatLayout = new QVBoxLayout;
              whatLayout->addWidget (whatComboEditor, 0, Qt::AlignCenter);
              whatLayout->setMargin (2);
            
              w->setLayout (whatLayout);
            
              QSqlQuery queryLoadWhat("SELECT What FROM  What_Table ORDER BY What asc", db);
            
              while(queryLoadWhat.next()) {
                QString whatItem = queryLoadWhat.value(0).toString();
                whatComboEditor->addItem(whatItem);
              }
              return w;
            }
            
            void WhatFixViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
              QComboBox* whatComboEditor = editor->findChild<QComboBox*>();
            
              if(whatComboEditor) {
                whatComboEditor->addItem(index.model()->data(index, Qt::EditRole).toString());
                whatComboEditor->setCurrentText(index.model()->data(index, Qt::EditRole).toString());
              }
            }
            
            void WhatFixViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
              Q_UNUSED(index);
            
              editor->setGeometry(option.rect);
            }
            
            void WhatFixViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* fixModel, const QModelIndex& index) const {
            
              QComboBox* whatComboEditor = editor->findChild<QComboBox*>();
              if (whatComboEditor) {
                  QString newWhatText;
                
                  newWhatText = whatComboEditor->currentText ();//crashes
                  qDebug() << "newWhatText: " <<  whatComboEditor->currentText ();
                
                  fixModel->setData (index, newWhatText, Qt::EditRole);
                
                  fixModel->submit ();
              }
            }
            
            

            Now it doesn't crash, but when I add an item from the QComboBox, all the data from the line disappears like this:
            0_1506565863276_Capture.JPG
            When I reload the table all the data are back and the newly chosen item is also there (it was saved in the db). What can I add to prevent the data from disappearing?

            VRoninV 1 Reply Last reply
            0
            • G gabor53

              Thank you. I redid it as recommended and now it looks like this:

              #include "whatfixviewdelegate.h"
              
              WhatFixViewDelegate::WhatFixViewDelegate(QObject* parent) : QStyledItemDelegate(parent) {
              
              }
              
              QWidget* WhatFixViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
              
                Q_UNUSED(option);
                Q_UNUSED(index);
              
                QWidget* w = new QWidget( parent );
              
                QComboBox* whatComboEditor = new QComboBox(w);
                whatComboEditor->setFrame(true);
                whatComboEditor->setStyleSheet("background-color:rgb(255,217,229);" );
                whatComboEditor->setEditable(true);
              
                whatComboEditor->setMaximumWidth (100);
                whatComboEditor->setMinimumWidth (100);
                whatComboEditor->setMaximumHeight (30);
                whatComboEditor->setMinimumHeight (30);
              
                whatComboEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
              
                QVBoxLayout* whatLayout = new QVBoxLayout;
                whatLayout->addWidget (whatComboEditor, 0, Qt::AlignCenter);
                whatLayout->setMargin (2);
              
                w->setLayout (whatLayout);
              
                QSqlQuery queryLoadWhat("SELECT What FROM  What_Table ORDER BY What asc", db);
              
                while(queryLoadWhat.next()) {
                  QString whatItem = queryLoadWhat.value(0).toString();
                  whatComboEditor->addItem(whatItem);
                }
                return w;
              }
              
              void WhatFixViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
                QComboBox* whatComboEditor = editor->findChild<QComboBox*>();
              
                if(whatComboEditor) {
                  whatComboEditor->addItem(index.model()->data(index, Qt::EditRole).toString());
                  whatComboEditor->setCurrentText(index.model()->data(index, Qt::EditRole).toString());
                }
              }
              
              void WhatFixViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const {
                Q_UNUSED(index);
              
                editor->setGeometry(option.rect);
              }
              
              void WhatFixViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* fixModel, const QModelIndex& index) const {
              
                QComboBox* whatComboEditor = editor->findChild<QComboBox*>();
                if (whatComboEditor) {
                    QString newWhatText;
                  
                    newWhatText = whatComboEditor->currentText ();//crashes
                    qDebug() << "newWhatText: " <<  whatComboEditor->currentText ();
                  
                    fixModel->setData (index, newWhatText, Qt::EditRole);
                  
                    fixModel->submit ();
                }
              }
              
              

              Now it doesn't crash, but when I add an item from the QComboBox, all the data from the line disappears like this:
              0_1506565863276_Capture.JPG
              When I reload the table all the data are back and the newly chosen item is also there (it was saved in the db). What can I add to prevent the data from disappearing?

              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #15

              @gabor53 said in setModelData crashes program:

              What can I add to prevent the data from disappearing?

              Sounds like a model bug. What is fixModel?

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              VRoninV 1 Reply Last reply
              0
              • JonBJ JonB

                And always check the return result of a qobject_cast<>, for safety, certainly while developing! :)

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #16

                @JNBarchan said in setModelData crashes program:

                And always check the return result of a qobject_cast<>, for safety, certainly while developing! :)

                In my nice (non-Qt) C# background, this kind of casting is built into the language. For qobject_cast<> we write:

                ComboBox cb = editor as CombBox;

                where the as operator returns null if editor cannot be cast to ComboBox at runtime. We use this if editor might not be a ComboBox.

                However, if editor must be/is intended to be a ComboBox, we write:

                ComboBox cb = (ComboBox) editor;

                where the direct cast throws a runtime Exception if editor is not a ComboBox (i.e. as would return null). This saves a lot of code/accidents.

                It would be nice if Qt offered a "variant" of qobject_cast<> in C++ which checked and automatically threw an Exception if the return result is NULL/0....?

                VRoninV 1 Reply Last reply
                0
                • JonBJ JonB

                  @JNBarchan said in setModelData crashes program:

                  And always check the return result of a qobject_cast<>, for safety, certainly while developing! :)

                  In my nice (non-Qt) C# background, this kind of casting is built into the language. For qobject_cast<> we write:

                  ComboBox cb = editor as CombBox;

                  where the as operator returns null if editor cannot be cast to ComboBox at runtime. We use this if editor might not be a ComboBox.

                  However, if editor must be/is intended to be a ComboBox, we write:

                  ComboBox cb = (ComboBox) editor;

                  where the direct cast throws a runtime Exception if editor is not a ComboBox (i.e. as would return null). This saves a lot of code/accidents.

                  It would be nice if Qt offered a "variant" of qobject_cast<> in C++ which checked and automatically threw an Exception if the return result is NULL/0....?

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #17

                  you just need to add Q_ASSERT(whatComboEditor); to have that

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  JonBJ 1 Reply Last reply
                  2
                  • VRoninV VRonin

                    you just need to add Q_ASSERT(whatComboEditor); to have that

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #18

                    @VRonin said in setModelData crashes program:

                    you just need to add Q_ASSERT(whatComboEditor); to have that

                    Ah, OK. It's just that you have to remember to write that every time after each qobject_cast<>, it would be nice to have them combined in one statement. I suppose you would write:

                    Q_ASSERT(whatComboEditor = qobject_cast<>)

                    but is Q_ASSERT code removed in non-debug code and/or does it evaluate its argument more than once (assuming it's a macro)?

                    I would like a qobject_assert_cast<> :)

                    EDIT: Yes, I see you cannot use Q_ASSERT(whatComboEditor = qobject_cast<>) in non-debug as the code gets removed.

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

                      That's not specific to Q_ASSERT, it's the same for the standard C++ assert. Always test the result of a function and not the function itself.

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

                      1 Reply Last reply
                      1
                      • VRoninV Offline
                        VRoninV Offline
                        VRonin
                        wrote on last edited by
                        #20

                        If you want to use it in code that should still be present in release mode you can use Q_ASSUME

                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                        ~Napoleon Bonaparte

                        On a crusade to banish setIndexWidget() from the holy land of Qt

                        JonBJ 1 Reply Last reply
                        0
                        • VRoninV VRonin

                          If you want to use it in code that should still be present in release mode you can use Q_ASSUME

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #21

                          @VRonin said in setModelData crashes program:

                          If you want to use it in code that should still be present in release mode you can use Q_ASSUME

                          Um, I don't think so are you sure: http://doc.qt.io/qt-5/qtglobal.html#Q_ASSUME states it's a compile-time hint, and you get "undefined behaviour" if the condition is false. We need a runtime check of the return result of qobject_cast<>.

                          EDIT: Unless the docs are misleading, and the true implementation is via https://git.merproject.org/faenil/qtbase/commit/3b0ed624351441a2d7be45cf9582fd36955ae860 , which uses Q_ASSERT_X?

                          1 Reply Last reply
                          0
                          • VRoninV Offline
                            VRoninV Offline
                            VRonin
                            wrote on last edited by VRonin
                            #22

                            Q_ASSUME in debug mode is like Q_ASSERT in release mode, if whatComboEditor is null the program would crash anyway so you can't do much worse.

                            The undefined behaviour comes from when you use the return value: if(Q_ASSUME(false)) is undefined behaviour. if it just wraps an operation you do not check anyway, Q_ASSUME does nothing to your compiled binary in release mode

                            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                            ~Napoleon Bonaparte

                            On a crusade to banish setIndexWidget() from the holy land of Qt

                            JonBJ 1 Reply Last reply
                            0
                            • VRoninV VRonin

                              Q_ASSUME in debug mode is like Q_ASSERT in release mode, if whatComboEditor is null the program would crash anyway so you can't do much worse.

                              The undefined behaviour comes from when you use the return value: if(Q_ASSUME(false)) is undefined behaviour. if it just wraps an operation you do not check anyway, Q_ASSUME does nothing to your compiled binary in release mode

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by
                              #23

                              @VRonin
                              That wasn't quite the point, though. I was talking about writing the single-line statement (if Qt won't offer a qboject_assert_cast<>):

                              Q_ASSERT(whatComboEditor = qobject_cast<>)

                              versus

                              Q_ASSUME(whatComboEditor = qobject_cast<>)

                              The point being that it does the assignment. So we do need the expression to evaluate, just we don't need/care to do the "assertion" part of testing the result in release build. This would not work for Q_ASSERT as (I believe) it's a macro which produces nothing (no code at all) in release build. That was when you suggested Q_ASSUME.

                              VRoninV 1 Reply Last reply
                              0
                              • JonBJ JonB

                                @VRonin
                                That wasn't quite the point, though. I was talking about writing the single-line statement (if Qt won't offer a qboject_assert_cast<>):

                                Q_ASSERT(whatComboEditor = qobject_cast<>)

                                versus

                                Q_ASSUME(whatComboEditor = qobject_cast<>)

                                The point being that it does the assignment. So we do need the expression to evaluate, just we don't need/care to do the "assertion" part of testing the result in release build. This would not work for Q_ASSERT as (I believe) it's a macro which produces nothing (no code at all) in release build. That was when you suggested Q_ASSUME.

                                VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #24
                                • Q_ASSERT(statement);
                                  • Debug: if(!statement) triggerAnAssertion();
                                  • Release: ;
                                • Q_ASSUME(statement);
                                  • Debug: if(!statement) triggerAnAssertion();
                                  • Release: statement;

                                Is the difference clearer now?

                                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                ~Napoleon Bonaparte

                                On a crusade to banish setIndexWidget() from the holy land of Qt

                                G JonBJ 2 Replies Last reply
                                1
                                • VRoninV VRonin
                                  • Q_ASSERT(statement);
                                    • Debug: if(!statement) triggerAnAssertion();
                                    • Release: ;
                                  • Q_ASSUME(statement);
                                    • Debug: if(!statement) triggerAnAssertion();
                                    • Release: statement;

                                  Is the difference clearer now?

                                  G Offline
                                  G Offline
                                  gabor53
                                  wrote on last edited by
                                  #25

                                  @VRonin
                                  I added

                                   Q_ASSERT(whatComboEditor);
                                  

                                  but it behaves the same.

                                  1 Reply Last reply
                                  0
                                  • VRoninV VRonin

                                    @gabor53 said in setModelData crashes program:

                                    What can I add to prevent the data from disappearing?

                                    Sounds like a model bug. What is fixModel?

                                    VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by
                                    #26

                                    @VRonin said in setModelData crashes program:

                                    Sounds like a model bug. What is fixModel?

                                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                    ~Napoleon Bonaparte

                                    On a crusade to banish setIndexWidget() from the holy land of Qt

                                    G 2 Replies Last reply
                                    0
                                    • VRoninV VRonin

                                      @VRonin said in setModelData crashes program:

                                      Sounds like a model bug. What is fixModel?

                                      G Offline
                                      G Offline
                                      gabor53
                                      wrote on last edited by
                                      #27

                                      @VRonin

                                      QSqlTableModel* fixModel = new QSqlTableModel(this);
                                        fixModel->setTable ("Items");
                                        fixModel->setEditStrategy (QSqlTableModel::OnRowChange);
                                        fixModel->setSort (2, Qt::DescendingOrder);
                                      
                                        fixModel->select ();
                                      
                                      1 Reply Last reply
                                      0
                                      • VRoninV VRonin
                                        • Q_ASSERT(statement);
                                          • Debug: if(!statement) triggerAnAssertion();
                                          • Release: ;
                                        • Q_ASSUME(statement);
                                          • Debug: if(!statement) triggerAnAssertion();
                                          • Release: statement;

                                        Is the difference clearer now?

                                        JonBJ Offline
                                        JonBJ Offline
                                        JonB
                                        wrote on last edited by
                                        #28

                                        @VRonin

                                        Is the difference clearer now?

                                        Yep! :) Tx.

                                        1 Reply Last reply
                                        0
                                        • VRoninV VRonin

                                          @VRonin said in setModelData crashes program:

                                          Sounds like a model bug. What is fixModel?

                                          G Offline
                                          G Offline
                                          gabor53
                                          wrote on last edited by gabor53
                                          #29

                                          @VRonin
                                          Any way to go around the problem?
                                          Would it be possible to just redraw the row in which the field was changed?

                                          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