"setItemDelegateForColumn" problem.



  • Hello, everyone.

    Has been studying the of models in Qt 5.4 and encountered a strange behavior of the method "setItemDelegateForColumn". I use QTreeViev performance and QAbstrastitemModel  to implement elements of the tree with delegates of QComboBox.

    Here is code of my delegate:
    @
    #ifndef COMBOBOXDELEGATE_H
    #define COMBOBOXDELEGATE_H
    #include <QItemDelegate>
    #include <QComboBox>

    class ComboBoxDelegate : public QItemDelegate
    {
    public:
    Q_OBJECT
    public:

          ComboBoxDelegate(QObject *parent = 0);
          QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
          void setEditorData(QWidget *editor, const QModelIndex &index) const;
          void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
          void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
          ~ComboBoxDelegate();
    

    };

    #endif // COMBOBOXDELEGATE_H
    @

    And cpp:
    @
    #include "comboboxdelegate.h"

    ComboBoxDelegate::ComboBoxDelegate(QObject *parent): QItemDelegate(parent)
    {
    //createEditor(parent);
    }
    ComboBoxDelegate::~ComboBoxDelegate()
    {

    }

    QWidget *ComboBoxDelegate::createEditor(QWidget parent, const QStyleOptionViewItem &/ option /, const QModelIndex &/ index */) const
    {
    QComboBox *editor = new QComboBox(parent);
    QStringList list ;
    list << "Non" << "WithUpdates" << "WithInners";
    editor->addItems(list);
    return editor;
    }

    void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
    QString value = index.model()->data(index, Qt::DisplayRole).toString();
    QComboBox comboBox = static_cast<QComboBox>(editor);
    comboBox->addItem(value);
    }

    void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
    QComboBox comboBox = static_cast<QComboBox>(editor);
    QString value = comboBox->currentText();
    model->setData(index, value);
    }

    void ComboBoxDelegate::updateEditorGeometry(QWidget editor, const QStyleOptionViewItem &option, const QModelIndex &/ index */) const
    {
    editor->setGeometry(option.rect);
    }
    @

    In the process executing code of my program, setting the delegate in column 0:
    @
    Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();
    ...
    comboDelegate = new ComboBoxDelegate(ui->treeView);
    ...
    ui->treeView->setItemDelegateForColumn(0, comboDelegate);
    ui->treeView->setModel(treeModel);
    @

    The problem is that if you set a delegate similarly (which is, I mean, is not correct), the application is going to run, but in the column where there should be a delegate is not what I need.

    However, methods of assembly editor in my delegate already redefined. If I include them in the program code _ and installed editor  using model indexes already added elements, I get my delegate, but only in one line, rather than in the entire column, as we would like:
    @
    Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();

    comboDelegate = new ComboBoxDelegate(ui->treeView);
    comboDelegate->createEditor(ui->treeView,QStyleOptionViewItem(),QModelIndex());
    
    ui->treeView->setItemDelegateForColumn(0, comboDelegate);
    ui->treeView->setModel(treeModel);
    
    QModelIndex index = ui->treeView->currentIndex();
    treeModel->insertRows(0,3,index);
    ...
    

    @

    If I just make out the code as documentation tells me, that the program will abort with an error "Segmentation error".
    @
    Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();
    ui->treeView->setItemDelegateForColumn(0, comboDelegate);
    ui->treeView->setModel(treeModel);
    QModelIndex index = ui->treeView->currentIndex();
    treeModel->insertRows(0,3,index);
    ....
    @

    However, the work of this application fails "Segmentation error." Can you tell me anything prompt?

    Thanks in advance.



  • I saw only last code snippet. I don't see your delegate object is not created. This may be reason for crash ?



  • bI saw only last code snippet. I don’t see your delegate object is not created. This may be reason for crash ?q.

    For crash - maybe. This code is working (ie. Does not fall), but the delegate is not displayed.
    @ Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();

        comboDelegate = new ComboBoxDelegate(ui->treeView);
        comboDelegate->createEditor(ui->treeView,QStyleOptionViewItem(),QModelIndex());
     
        ui->treeView->setItemDelegateForColumn(0, comboDelegate);
        ui->treeView->setModel(treeModel);
     
        QModelIndex index = ui->treeView->currentIndex();
        treeModel->insertRows(0,3,index);
        ...
    

    @


  • Lifetime Qt Champion

    Hi

    [quote author="House15" date="1425312736"]Hello, everyone.
    @
    Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();

    ui->treeView->setItemDelegateForColumn(0, comboDelegate); << comboDelegate is used uninitialized
    
    ui->treeView->setModel(treeModel);
    QModelIndex index = ui->treeView->currentIndex();
    treeModel->insertRows(0,3,index);
    

    @
    [/quote]

    You should also first setup your model on your view and then your delegate.



  • That'S Perfect. Did as you said, but the result is unsatisfactory: the delegate does not appear on the form.

    @Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();

    ui->treeView->setModel(treeModel);
    comboDelegate = new ComboBoxDelegate(ui->treeView);
    ui->treeView->setItemDelegateForColumn(0,  comboDelegate);
    
    QModelIndex index = ui->treeView->currentIndex();
    treeModel->insertRows(0,3,index);
    
    TreeItem* item = treeModel->itemForIndex(index);
    if(item->hasChildren())
    {
        index = treeModel->index(1,0,index);
        QVariant date = 2;
        treeModel->setData(index,date,Qt::CheckStateRole);
        date = "Name";
        treeModel->setData(index,date,Qt::EditRole);
        ui->treeView->update(index);
    }
    

    }@

    !http://hostingkartinok.com/show-image.php?id=67211b3f8729acd3651c75b5d788790a(Current dialog)!

    [URL=http://hostingkartinok.com/show-image.php?id=67211b3f8729acd3651c75b5d788790a][IMG]http://s1.hostingkartinok.com/uploads/thumbs/2015/03/67211b3f8729acd3651c75b5d788790a.png[/IMG][/URL]



  • It may be useful to review the code of my model. Just in case.

    treemodel.h
    @
    #ifndef TREEITEM_H
    #define TREEITEM_H

    #include <QStandardItem>
    #include <QString>
    class TreeItem
    {
    public:
    //TreeItem(QList <QVariant> _m_itemData, TreeItem *parent = 0);
    TreeItem(QString &name, bool update=false, bool inners=false, TreeItem *parent = 0, int state = 0);
    ~TreeItem();
    QString name() const { return m_name; }
    int state() const { return _state; }
    void setName(const QString &name){m_name = name;}
    bool isUpdatable() const {return _update;}
    bool isInlinable() const {return _inners;}
    void setUpdatable(bool upd){ _update = upd; }
    void setInlines(bool inners){ _inners = inners; }

    TreeItem *parent() const {return m_parent;}
    TreeItem *child(int row) const {return m_children.value(row); }
    int rowOfChild(TreeItem *child) const {return m_children.indexOf(child);}
    int countOfChildren() {return m_children.count();}
    bool hasChildren() {return !m_children.empty();}
    QList<TreeItem*> children() const  {return m_children;}
    void insertChild(TreeItem *item, int row) {item->m_parent = this; m_children.insert(row,item);}
    void addChild(TreeItem *item) {item->m_parent = this; m_children<<item;}
    void swapChildren(int oldrow,  int newrow) {m_children.swap(oldrow,newrow);}
    TreeItem* takeChild(int row);
    

    private:
    QList <QVariant> m_itemData;
    QString m_name;
    bool _update;
    bool _inners;
    TreeItem m_parent;
    QList<TreeItem
    > m_children;
    // 0 - Non
    // 1 - Editable
    // 2 - inliable
    int _state;
    };

    #endif // TREEITEM_H
    @



  • treemodel.cpp
    @
    #include "treemodel.h"

    QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
    if(section == State)
    return "Состояние";
    if(section == Name)
    return "Наименование";
    }
    return QVariant();
    }

    Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
    {

    Qt::ItemFlags theFlags = QAbstractItemModel::flags(index);
    if(index.isValid())
    {
        theFlags |= Qt::ItemIsSelectable|Qt::ItemIsEnabled;
       // if(index.column() == State)
           // theFlags |= Qt::ItemIsUserCheckable|Qt::ItemIsTristate;
            //theFlags |= Qt::ItemIsUserCheckable|Qt::ItemIsEditable|Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled;
    }
    
    return theFlags;
    

    }

    QVariant TreeModel::data(const QModelIndex &index, int role) const
    {
    if(!rootItem || !index.isValid() || index.column() > 0 || index.column() >= ColumnCount)
    return QVariant();

    if(TreeItem *Item = itemForIndex(index))
    {
        if(role == Qt::DisplayRole || role == Qt::EditRole)
        {
            switch(index.column())
            {
            case Name: return Item->name();
            case State: return Item->state();
            default: Q_ASSERT(false);
            }
        }
    
        if(role == Qt::CheckStateRole && index.column() == State)
        {
            bool update = false;
            bool iline = false;
    
            update = static_cast<bool>(Item->isUpdatable());
            iline = static_cast<bool>(Item->isInlinable());
            if(!update&&!iline) return 0;
            else if(update) return 1;
            else if (iline) return 2;
            else if(update&&iline) return QVariant();
        }
    }
    return QVariant();
    

    }

    TreeItem* TreeModel::itemForIndex(const QModelIndex &index) const
    {
    if(index.isValid())
    {
    if(TreeItem item = static_cast<TreeItem>(index.internalPointer()))
    {
    return item;
    }
    }
    return rootItem;
    }

    int TreeModel::rowCount(const QModelIndex &parent) const
    {
    if(parent.isValid() && parent.column() != 0)
    return 0;

    TreeItem *parentItem = itemForIndex(parent);
    return parentItem ? parentItem->countOfChildren() : 0;
    

    }

    int TreeModel::columnCount(const QModelIndex &parent) const
    {
    return parent.isValid() && parent.column() != 0? 0:ColumnCount;
    }

    int TreeModel::stateIs(const QModelIndex &index, int role) const
    {
    if(!index.isValid())
    return -1;

    int state = data(index, Qt::CheckStateRole).toInt();
    
    return state;
    

    }

    bool TreeModel::insertRows(int row, int count, const QModelIndex &parent)
    {
    if(!rootItem)
    {
    QString RootName("Root");
    rootItem = new TreeItem(RootName,false,false,(TreeItem*)0,0);
    if(!rootItem)
    {
    return false;
    }
    }

    QString newElem("New elem");
    TreeItem *parentItem = parent.isValid() ? itemForIndex(parent) : rootItem;
    QAbstractItemModel::beginInsertRows(parent,row,row+count-1);
    for(int i=0; i<count;++i)
    {
        TreeItem *item = new TreeItem(newElem,false);
        parentItem->insertChild(item,row);
    }
    endInsertRows();
    return true;
    

    }

    bool TreeModel::addBranchToRoot(TreeItem &items)
    {
    return false;
    }

    bool TreeModel::removeRows(int row, int count, const QModelIndex &parent)
    {
    if(!rootItem)
    return false;

    TreeItem *item = parent.isValid() ? itemForIndex(parent) : rootItem;
    QAbstractItemModel::beginRemoveRows(parent,row,row+count-1);
    for(int i=0; i<count; i++)
        delete item->takeChild(row);
    
    QAbstractItemModel::endRemoveRows();
    return true;
    

    }

    QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
    {
    if(!rootItem || row<0 || column < 0 || column >=ColumnCount || (parent.isValid() && parent.column() !=0))
    return QModelIndex();

    TreeItem *parentItem = itemForIndex(parent);
    Q_ASSERT(parentItem);
    if(TreeItem *item = parentItem->child(row)){
        return createIndex(row,column,item);
    }
    
    return QModelIndex();
    

    }

    QModelIndex TreeModel::parent(const QModelIndex &index) const
    {
    if(!index.isValid())
    return QModelIndex();

    if(TreeItem *childItem = itemForIndex(index))
    {
        if(TreeItem *parentItem = childItem->parent())
        {
            if(parentItem == rootItem)
                return QModelIndex();
    
            if(TreeItem *grandParentItem = parentItem->parent()){
                int row = grandParentItem->rowOfChild(parentItem);
                return createIndex(row,0,parentItem);
            }
        }
    }
    return QModelIndex();
    

    }

    bool TreeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
    {return false;}

    bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if(!index.isValid() || index.column() != State)
    return false;

    if(TreeItem *item =  itemForIndex(index))
    {
        if(role == Qt::EditRole)
            item->setName(value.toString());
        else if(role == Qt::CheckStateRole)
        {
            switch(value.toInt())
            {
            case 0:
            {
                item->setUpdatable(false);
                item->setInlines(false);
            }
                break;
            case 1:
            {
                item->setUpdatable(true);
                item->setInlines(false);
            }
                break;
            case 2:
            {
                item->setUpdatable(false);
                item->setInlines(true);
            }
                break;
            }
        }
        else
            return false;
    
        emit dataChanged(index,index);
        return true;
    }
    return false;
    

    }

    @



  • I also noticed a strange thing. If we define the editor, using the method of the delegate, it will appear in the specified model index position. In this case - in the header. There was a question: Is not the model itself must initialize a delegate in the correct position? In the manual it is also possible to do, but it is not convenient, and contradicts the logic of the method "setItemDelegateForColumn."

    I'm talking about the code on line 10:
    comboDelegate->createEditor(ui->treeView,QStyleOptionViewItem(),QModelIndex());

    @Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel();
    ui->treeView->setModel(treeModel);

    comboDelegate = new ComboBoxDelegate(ui->treeView);
    comboDelegate->createEditor(ui->treeView,QStyleOptionViewItem(),QModelIndex());
    ui->treeView->setItemDelegateForColumn(0,  comboDelegate);
    
    QModelIndex index = ui->treeView->currentIndex();
    treeModel->insertRows(0,3,index);
    
    TreeItem* item = treeModel->itemForIndex(index);
    if(item->hasChildren())
    {
        index = treeModel->index(1,0,index);
        QVariant date = 2;
        treeModel->setData(index,date,Qt::CheckStateRole);
        date = "Name";
        treeModel->setData(index,date,Qt::EditRole);
        ui->treeView->update(index);
    }
    

    }@



  • I am totally confused. Not only that delegates are not displayed, so even when you remove elements of wood, the application crashes. Nothing catch up.

    @
    Tree::Tree(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Tree)
    {
    ui->setupUi(this);
    treeModel = new TreeModel(this);

    comboDelegate = new ComboBoxDelegate(ui->treeView);
    ui->treeView->setItemDelegateForColumn(0,  comboDelegate);
    
    QModelIndex index = ui->treeView->currentIndex();
    ui->treeView->setRootIndex(index);
    ui->treeView->setModel(treeModel);
    

    }
    @

    @void Tree::removeItem()
    {
    QModelIndex currentIndex = ui->treeView->currentIndex();
    if(!currentIndex.isValid())
    return;

    treeModel->removeRows(currentIndex.row(),1,currentIndex.parent());
    ui->treeView->update();
    

    }@


  • Lifetime Qt Champion

    From your model code, your items are not editable so there's no editor that can appear.

    For your crash, are you sure that treeModel points to something valid ?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.