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. QAbstractItemDelegate and editing
QtWS25 Last Chance

QAbstractItemDelegate and editing

Scheduled Pinned Locked Moved General and Desktop
13 Posts 4 Posters 11.0k 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.
  • A Offline
    A Offline
    Anticross
    wrote on last edited by
    #1

    I wrote a class which based on QItemDelegate. It presents a combo box with some data. When I applying it on QTreeView or QTableView item i can change the value by double clicking on it and choosing the new value, than I must hit Enter key or click on any other item to change the value in item. If I close window, without hitting Enter key, or without clicking on other item, the value in item will not change. Is there any solution to solve this problem ? Here is the code of my delegate:
    @class ComboBoxDelegate : public AItemDelegate { Q_OBJECT
    //--------------------------------------------------------------------------------------------------
    public: ComboBoxDelegate(QObject * parent = 0) : AItemDelegate(parent) {
    }
    public: ComboBoxDelegate(QObject * parent, DescriptionPtr description) : AItemDelegate(parent, description) {
    }
    //--------------------------------------------------------------------------------------------------
    public: virtual ~ComboBoxDelegate() {
    }
    //--------------------------------------------------------------------------------------------------
    public: virtual QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & /option/, const QModelIndex & /index/) const {
    if (m_description == NULL)
    return NULL;

                    QComboBox * cb = new QComboBox(parent);
                    
                    const Choices & choices = m_description->getChoices();
                    int n = choices.getCount();
                    for (int i = 0; i < n; i++) {
                        const Choice & item = choices.getItem(i);
                        cb->addItem(item.getDisplayName(), item.getValue());
                    }
    
                    return cb;
                }
    

    //--------------------------------------------------------------------------------------------------
    public: void setEditorData(QWidget * editor, const QModelIndex & index) const {
    QComboBox * cb = static_cast<QComboBox *>(editor);
    // QVariant value = index.data(Qt::EditRole);
    QString s = index.data(Qt::DisplayRole).toString();
    //int i = cb->findData(value);
    int i = cb->findText(s);
    // if(i == -1)
    // cb->setCurrentIndex(0);
    // else
    cb->setCurrentIndex(i);

                }
    

    //--------------------------------------------------------------------------------------------------
    public: void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const {
    QComboBox * cb = static_cast<QComboBox *>(editor);
    int ndx = cb->currentIndex();
    if (ndx >= 0) {
    QVariant value = cb->itemData(ndx);
    model->setData(index, value, Qt::EditRole);
    }
    }
    //--------------------------------------------------------------------------------------------------
    };@

    AItemDelegate:
    @class AItemDelegate : public QItemDelegate {
    //--------------------------------------------------------------------------------------------------
    protected: DescriptionPtr m_description;
    //--------------------------------------------------------------------------------------------------
    public: AItemDelegate(QObject * parent) : QItemDelegate(parent) {
    m_description = NULL;
    }
    //--------------------------------------------------------------------------------------------------
    public: AItemDelegate(QObject * parent, DescriptionPtr description) : QItemDelegate(parent) {
    m_description = description;
    }
    //--------------------------------------------------------------------------------------------------
    public: virtual ~AItemDelegate() {
    }
    //--------------------------------------------------------------------------------------------------
    public: DescriptionPtr getDescription() {
    return m_description;
    }
    //--------------------------------------------------------------------------------------------------
    public: void setDescription(DescriptionPtr description) {
    m_description = description;
    }
    //--------------------------------------------------------------------------------------------------
    public: virtual void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & /index/) const {
    editor->setGeometry(option.rect);
    }
    //--------------------------------------------------------------------------------------------------
    };@

    1 Reply Last reply
    0
    • G Offline
      G Offline
      goetz
      wrote on last edited by
      #2

      Connect an appropriate signal of the widget containing your item view to a slot endEdit() in you item view subclass:

      @
      void MyItemViewSubclass::endEdit()
      {
      QModelIndex index = currentIndex();
      currentChanged( index, index );
      }
      @

      This simulates clicking on an item and thus ends the editing process of the combobox.

      You should call this slot too, if you are going to commit the data via some save button or the like. It works well and we use it all the time.

      http://www.catb.org/~esr/faqs/smart-questions.html

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Anticross
        wrote on last edited by
        #3

        This delegate is using by more then one item View sub class. I can't even imagine how many times it will be used in project in feature and by how many people, because it not so small. So I need some local solution in my delegate or in AItemDelegate class. Is there any other ideas ?

        1 Reply Last reply
        0
        • G Offline
          G Offline
          goetz
          wrote on last edited by
          #4

          The delegate does not catch widget state changes. So I see no better solution. You might create a central subclass of the needed item view/item widgets and implement endEdit there, to ease the use of the method.

          http://www.catb.org/~esr/faqs/smart-questions.html

          1 Reply Last reply
          0
          • A Offline
            A Offline
            Anticross
            wrote on last edited by
            #5

            Thanks for answer. So this will take a little bit more work than I expect.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Anticross
              wrote on last edited by
              #6

              And one more question: which signal I need to connect ? For example in QTreeView ? I can't find appropriate signal. Or maybe it must be my own signal emitted from one of delegate functions ?

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #7

                I mean some signals or events from the containing widget (hide, close, etc.). maybe focusOut on the item view too. Also, if you have, for example, a save button, it is likely that it is connected to some slot, you should call endEdit there too.

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Anticross
                  wrote on last edited by
                  #8

                  There is one more simple solution that I find. In my delegate I need to add connect @ public: void setEditorData(QWidget * editor, const QModelIndex & index) const {
                  QComboBox * cb = static_cast<QComboBox *>(editor);
                  QString s = index.data(Qt::DisplayRole).toString();
                  int i = cb->findText(s);
                  cb->setCurrentIndex(i);

                                  connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
                              }@
                  

                  And add a slot onCurrentIndexChanged : @public slots: void onCurrentIndexChanged(int index) {
                  QComboBox * cb = static_cast<QComboBox *>(sender());
                  emit commitData(cb);
                  emit closeEditor(cb);
                  }@
                  So it solved locally and works pretty well.

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    goetz
                    wrote on last edited by
                    #9

                    Be aware that this will work with your combo boxes, but not with default generated line edits or the like!

                    http://www.catb.org/~esr/faqs/smart-questions.html

                    1 Reply Last reply
                    0
                    • B Offline
                      B Offline
                      brianz
                      wrote on last edited by
                      #10

                      I had the exact same issue and the currentChanged trick worked very nicely.

                      Thanks for the tip!

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        maximus
                        wrote on last edited by
                        #11

                        Just want to thanks for this trick, I modified it a little bit so it works with every QWidget editor

                        1- In createEditor, connect a custom signal in your QWidget Editor to a custom slot in the Delegate
                        @QWidget *IntervalDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const

                        {
                        else if (index.column() == 3 ) {
                        CadenceEditor *editor = new CadenceEditor(parent);
                        connect (editor, SIGNAL(endEdit()), this, SLOT(closeWidgetEditor()) );
                        return editor;
                        }@

                        2- close the editor in the custom delegate slot :
                        @void IntervalDelegate::closeWidgetEditor() {

                        qDebug() << "CLOSE EDITOR NOW!";
                        QWidget *editor = qobject_cast<QWidget*>(sender());
                        
                        emit commitData(editor);
                        emit closeEditor(editor);
                        

                        }@


                        Free Indoor Cycling Software - https://maximumtrainer.com

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          maximus
                          wrote on last edited by
                          #12

                          I can now close the editor with a custom "OK" button, show in this image:
                          https://www.dropbox.com/s/95agb2c38f9p354/customEditors.png

                          Problem is when I click the OK button, the click get propaged under it and it open another editor, how can I stop the click? I already have setAttribute(Qt::WA_NoMousePropagation); on my custom QWidget editor..

                          Thanks


                          Free Indoor Cycling Software - https://maximumtrainer.com

                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            maximus
                            wrote on last edited by
                            #13

                            I think it is the default behavior in a QTableView, when a cell editing is completed, the editor automatically move to the adjacent(right) cell.

                            Kind of like excel.
                            I need to find how to turn off this feature now :)


                            Free Indoor Cycling Software - https://maximumtrainer.com

                            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