Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QStyledItemDelegate, QTableView, QDateEdit - Problems with my homies.



  • I've narrowed down a very specific problem when trying to edit a date from within a QTableView linked to a MS SQL date.
    When tabbing through the QTableView... everything is fine and submits properly on fieldchange, but on manual submit and on row change... if the same field is selected twice before moving to the next row... a crash occurs. Setdata line for the date field (fields 11/12) is the line it crashes at. I notice also that before the crash on the 2nd selection, the date edit auto value reads the null that was set and it populates the field with a default value 01/01/2000... which is another problem I'm trying to avoid... both with dates and QSpinBoxes. This is only specific to the QDateEdit fields... not any other. Columns 11/12 in FilmLineItemSqlTableModel. I'd also like to try to get the QSpinBox to not display a value when the editor is open either if at all possible.

    I originally subclassed the delegate because I did not want an autovalue of 01/01/1900 to submit to the database and ran across this problem in the meanwhile.

    Here is the itemfactory & delegate code.

    #ifndef ITEMDELEGATE_H
    #define ITEMDELEGATE_H
    
    #include <QStyledItemDelegate>
    #include <QItemEditorFactory>
    #include <QDoubleSpinBox>
    #include <QDateTimeEdit>
    #include <cfloat>
    
    class PreciseFactory : public QItemEditorFactory
    {
    
    public:
        PreciseFactory() = default;
        virtual ~PreciseFactory() = default;
    
        virtual QWidget* createEditor(int userType, QWidget *parent) const override{
            if(userType == QVariant::Int){
                QSpinBox *sb = new QSpinBox(parent);
    
                sb->setFrame(false);
                sb->setMinimum(-1);
                sb->setMaximum(INT_MAX);
                sb->setSpecialValueText("");
                sb->setValue(-1);
                return sb;
            }else if(userType == QVariant::Date)
            {
                QDateEdit *te = new QDateEdit(parent);
    
                te->setMinimumDate(QDate(1, 1, 1));
                te->setMaximumDate(QDate(9999,12,31));
                te->setSpecialValueText("");
                return te;
            }
            return QItemEditorFactory::createEditor(userType,parent);
        }
    };
    
    class ItemDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
    
    signals:
    
    public:
        ItemDelegate(QWidget* parent = nullptr) : QStyledItemDelegate(parent) {
            setItemEditorFactory(&fact);
        }
    
        void setModelData(QWidget* editor, QAbstractItemModel* model,
                          const QModelIndex& index) const override;
    
    private:
        PreciseFactory fact;
    };
    #endif // ITEMDELEGATE_H
    
    
    #include "ItemDelegate.h"
    #include <QLineEdit>
    #include <QSpinBox>
    #include <QDateEdit>
    #include <QEvent>
    #include <QDebug>
    #include <QKeyEvent>
    
    void ItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,
                      const QModelIndex& index) const
    {
        //qDebug() << editor << editor->metaObject()->className();
        if(model->metaObject()->className() == QString::fromStdString("CustomerSqlTableModel")) {
            QLineEdit* edit = qobject_cast<QLineEdit*>(editor);
            if(edit->text().isEmpty() || edit->text().isNull()) {
                if(index.column() == 1 || index.column() == 8) {
                    model->setData(index, QVariant(QVariant::Int));
                    return;
                }else if (index.column() == 10) {
                    model->setData(index, QVariant(QVariant::DateTime));
                    return;
                }
            }
        }else if(model->metaObject()->className() == QString::fromStdString("FilmLineItemSqlTableModel")) {
            if(index.column() == 1 || index.column() == 3 || index.column() == 9 || index.column() == 10) {
                QSpinBox* spin = qobject_cast<QSpinBox*>(editor);
                if(spin->text().isEmpty() || spin->text().isNull()) {
                    model->setData(index, QVariant(QVariant::Int));
                    return;
                }
            } else if (index.column() == 11 || index.column() == 12) {
                QLineEdit* edit = qobject_cast<QLineEdit*>(editor);
                if(edit->text().isEmpty() || edit->text().isNull()) {
                    model->setData(index, QVariant(QVariant::DateTime));
                    return;
                }
            }
        }else if(model->metaObject()->className() == QString::fromStdString("FilmSqlTableModel")) {
            if(index.column() == 0) {
                QLineEdit* edit = qobject_cast<QLineEdit*>(editor);
    
                if(edit->text().isEmpty() || edit->text().isNull()) {
                    model->setData(index, QVariant());
                    return;
                }
            }
        }
    
        return QStyledItemDelegate::setModelData(editor, model, index);
    }
    
    

  • Lifetime Qt Champion

    Hi,

    Can you also post the stack trace from your crash ?



  • @SGaist said in QStyledItemDelegate, QTableView, QDateEdit - Problems with my homies.:

    trace from your crash ?

    well I figured out a few things... I will post the dump anyways but... by removing edit->text.isEmpty() from the situation it resolves itself but then auto adds the 01/01/1900 default value on commit to the database (setdata). I really realized the two main problems I'm having, basically reading/setting nulls to the database... is causing the majority of my headaches. After a lot of reading, QDateEdit & NULLs do not mix well without a lot of sassyness.

    I'm at a point to where I don't care about the auto submit value of 01/01/1900... and I understand why the 01/01/2000 appeared (QDateEdit autovalue for null)... I'd rather just show the user all the 01/01/1900 values as an empty text... and the 0's in a QPSpinBox as 'empty text' as well... which I don't know whether to do from the model side, or view/delegate side.

    Also, that leads me to a question that I kind of asked before... which database fields types / or qvariant types correlate to which editing widgets in a qtableview? I still don't understand how it all works... I ran around putting a bunch of qdebugs in my code and saw qexpandinglinewidget... qdoublespinbox... and other things I've never heard of before... which lead me off on a nice reading adventure.

    Is it possible to input a "QDate" that isn't a string into a qtableview? or does it just convert from strings and I don't need to cast the editor to a QDateEdit... I'm so lost. The more I feel like I understand the less I really know...

    0_1534977704546_1.PNG


  • Qt Champions 2019

    @JahJerMar Well, when using pointers you should ALWAYS make sure they are valid.
    Also please post your code as TEXT not screen-shot!

    if (edit && (edit->text().isEmpty() || edit->text().isNull())
    


  • @jsulm
    I will do that but in answer to my code...
    The original post is text... using the code tag. It's the same code as in the picture.

    //your code here
    

Log in to reply