QItemDelegate with QTableWidget, access problem



  • Hello,
    lets say you have a QTableWidget with two colums and you would like to have custom behaviour on cell click implemented - in this case it would be combo box popup BUT the second column content depends on first column choice.
    Example:
    first column combo box content -> { letter, number}
    second column combo box content -> { a,b,c, 1, 2, 3}
    So if you pick {letter} in first colum the second column available choices would be {a,b,c} (analogical behaviour with number)
    I assume you have to reimplement QItemDelegate::createEditor(...) function however i dont know how to achive specified behaviour.
    NOTE:

    1. I dont want to paste tons of code here so for an example of custom QItemDelegates i provide this link:
      http://programmingexamples.net/wiki/Qt/Delegates/ComboBoxDelegate
      or you can try checking out Qt Example of StarDelegate here:
      http://doc.qt.io/qt-5/qtwidgets-itemviews-stardelegate-example.html
    2. I was trying to retrive specified (first column choice) from the parent pointer which is passed to createEditor function but it seems that my parent is not exactly QTableWidget


  • For anyone who is interested in solution i found:
    parent of the parent pointer passed to QItemDelegate::createEditor(...) is the QTableWidget we were looking for so

    QTableWidget *tbl = static_cast<QTableWidget*>(parent->parent());
    tbl->item(0,0)->text(); 
    

    solves the problem (for me at least).


  • Lifetime Qt Champion

    Hi,

    Using static_cast is a bad idea here, there's absolutely no checks done. For QObject derived classes, you should use qobject_cast and check that you have a valid pointer returned.

    Anyway, back for your problem, what you are doing is not clean at all. You should rather re-implement the setEditorData function to populate your QComboBox. You'll get an QModelIndex which will give you access to the QTableWidget's model and from there you can access the data you need without resorting to tricks like retrieving the parent of the parent of the delegate.



  • @SGaist Thanks for your reply! I thought there may be some, as you said, "cleaner" solution so i will definetly try to rewrite my code with the tips you gave. However have an eye on this thread because i will probably paste my work here and mayby then you can add some final pieces of advice to make it clean and correctly written.



  • @SGaist here is what i created, it is working correctly and i hope it is written correctly as well :)

    // reimplemented createEditor(...) func
    QWidget *CustomDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        // colum 0 - populate combobox with predeterminated data
        if(index.column() == 0)
        {
            QComboBox* editor = new QComboBox(parent);
            Q_FOREACH(QString str, predeterminatedData) //predeterminatedData === QStringList in my case
                editor->addItem(str);
            return editor;
        }
        // column 1 - content is column-zero dependent, i deal with it in setEditorData
        if(index.column() == 1)
        {
            QComboBox* editor = new QComboBox(parent);
            return editor;
        }
       // default editor elsewhere
        return QItemDelegate::createEditor(parent, option, index);
    }
    
    // reimplemented setEditorData(...) func
    void CustomDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        const QAbstractItemModel *model = index.model();
        QComboBox *comboBox = static_cast<QComboBox*>(editor);
        // editing 1st column?
        if(index.column() == 1)
        {
            // in my case there can be 2 options in the first column so i  check if its first option
            if(model->data(model->index(index.row(), 0),Qt::DisplayRole).toString().contains("FIRST"))
            {
                Q_FOREACH(QString str, itemsForFirstOption) // itemsForFirstOption === QStringList 
                    comboBox->addItem(str,Qt::DisplayRole);
            }
            else // second option
            {
                Q_FOREACH(QString str, itemsForSecondOption) // itemsForSecondOption === QStringList
                    comboBox->addItem(str,Qt::DisplayRole);
            }
        }
    }

  • Lifetime Qt Champion

    QComboBox has a addItems where you can directly use your QStringList, so no need for the loops. And again, you should not use static_cast like that, use object_cast.

    You're lucky it's not crashing because you only handle column 1 where you know you create a QComboBox. You should move these two lines under the if protection.


Log in to reply
 

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