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. Changes in table with combo boxes

Changes in table with combo boxes

Scheduled Pinned Locked Moved Solved General and Desktop
23 Posts 3 Posters 7.9k 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.
  • K Offline
    K Offline
    koahnig
    wrote on 31 Aug 2017, 08:45 last edited by
    #1

    I require some sort of a table with editable combo boxes. The combo boxes have to be editable because the content is not always known beforehand and in most cases it has to be adjusted or added. After completion of a new text entry, I want to have the identical choices for all combo boxes in a column.

    My decision was to use a QTableWidget with placing QComboBox in the columns. I have a routine pulling all entries from the QComboBox and homogenizing the entries within a column. I am expecting about ten QComboBox to be homogenized and therefore do not really expect performance issues.

    However, a problem arises with the choice of the proper signals. QTableWidget's cellChanged is not triggered when changing the QComboBox for any cell. Left with the signals of QComboBox only, I found that there are only signals for editTextChanged and currentTextChanged. Both are not helpful, since they are triggered by each letter typed. I expected to find a signal like focusLost or editFinished or whatever signalling the of activities in the line ewdit of QComboBox, but there is none.

    Any suggestions for solving the problem?

    Vote the answer(s) that helped you to solve your issue(s)

    1 Reply Last reply
    0
    • V Offline
      V Offline
      VRonin
      wrote on 31 Aug 2017, 09:51 last edited by VRonin
      #2

      Use a delegate.
      Works for every combination of view and (editable) model.

      • subclass QStyledItemDelegate
      • add a QAbstractItemModel* m_comboModel; as member of that class (you can use QStringListModel if you don't need multiple roles or QStandardItemModel if you want the full power).
      • reimplement createEditor to return a QComboBox that uses m_comboModel
      • reimplement setEditorData, setModelData and the trivial updateEditorGeometry
      • call setItemDelegateForColumn from the view to apply your new delegate to the column you want.

      It's pretty easy to implement but I'm happy to post code if you get stuck

      "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

      K 1 Reply Last reply 31 Aug 2017, 10:18
      4
      • V VRonin
        31 Aug 2017, 09:51

        Use a delegate.
        Works for every combination of view and (editable) model.

        • subclass QStyledItemDelegate
        • add a QAbstractItemModel* m_comboModel; as member of that class (you can use QStringListModel if you don't need multiple roles or QStandardItemModel if you want the full power).
        • reimplement createEditor to return a QComboBox that uses m_comboModel
        • reimplement setEditorData, setModelData and the trivial updateEditorGeometry
        • call setItemDelegateForColumn from the view to apply your new delegate to the column you want.

        It's pretty easy to implement but I'm happy to post code if you get stuck

        K Offline
        K Offline
        koahnig
        wrote on 31 Aug 2017, 10:18 last edited by
        #3

        @VRonin

        Thanks for help

        You are listing a number of classes, I have not used before. Therefore, it is easy to get lost.

        Do you have a small example?

        Vote the answer(s) that helped you to solve your issue(s)

        M 1 Reply Last reply 31 Aug 2017, 10:25
        0
        • K koahnig
          31 Aug 2017, 10:18

          @VRonin

          Thanks for help

          You are listing a number of classes, I have not used before. Therefore, it is easy to get lost.

          Do you have a small example?

          M Offline
          M Offline
          mrjj
          Lifetime Qt Champion
          wrote on 31 Aug 2017, 10:25 last edited by mrjj
          #4

          @koahnig
          Hi
          I think this could be good ?
          https://wiki.qt.io/Combo_Boxes_in_Item_Views

          Note that is does
          if (index.column() != 1) checks which is not super design.
          Much better with setItemDelegateForColumn than check internally on col as it
          breaks so easy with sorting etc and ties the delegate to the model.

          K 1 Reply Last reply 31 Aug 2017, 10:37
          2
          • M mrjj
            31 Aug 2017, 10:25

            @koahnig
            Hi
            I think this could be good ?
            https://wiki.qt.io/Combo_Boxes_in_Item_Views

            Note that is does
            if (index.column() != 1) checks which is not super design.
            Much better with setItemDelegateForColumn than check internally on col as it
            breaks so easy with sorting etc and ties the delegate to the model.

            K Offline
            K Offline
            koahnig
            wrote on 31 Aug 2017, 10:37 last edited by
            #5

            @mrjj

            I am playing already with the example code and found that it does add a combo box only in second col. Was a lucky shot to start there ;)

            This is certainly a very good start.

            PS: I will leave the thread open, if there are follow up questions. I am pretty sure that someone is going tokick me, if I forget to mark as solved ;)

            Vote the answer(s) that helped you to solve your issue(s)

            M 1 Reply Last reply 31 Aug 2017, 10:42
            0
            • K koahnig
              31 Aug 2017, 10:37

              @mrjj

              I am playing already with the example code and found that it does add a combo box only in second col. Was a lucky shot to start there ;)

              This is certainly a very good start.

              PS: I will leave the thread open, if there are follow up questions. I am pretty sure that someone is going tokick me, if I forget to mark as solved ;)

              M Offline
              M Offline
              mrjj
              Lifetime Qt Champion
              wrote on 31 Aug 2017, 10:42 last edited by
              #6

              @koahnig

              Hi, ok super !
              If you have not played with delegates before, there will be questions.
              Or at least i had many :)

              1 Reply Last reply
              0
              • V Offline
                V Offline
                VRonin
                wrote on 31 Aug 2017, 10:44 last edited by VRonin
                #7

                This is a small class from one of my projects. It supports Qt::EditRole and Qt::UserRole. It also automatically sorts the entries (which I'm unsure if it's something you want). You'll just have to change createEditor slightly to allow the combobox to be typed into

                header

                #ifndef COMBOBOXDELEGATE_H
                #define COMBOBOXDELEGATE_H
                
                #include <QStyledItemDelegate>
                #include <QString>
                class QComboBox;
                class QStandardItemModel;
                class QSortFilterProxyModel;
                class ComboBoxDelegate : public QStyledItemDelegate
                {
                    Q_OBJECT
                    Q_DISABLE_COPY(ComboBoxDelegate)
                public:
                    explicit ComboBoxDelegate(QObject *parent = Q_NULLPTR);
                    virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
                    virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
                    virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
                    virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
                    virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index)  const override;
                    virtual void clear();
                    virtual void addItem(const QString& txt, const QVariant& val);
                    virtual void addItem(const QString& txt);
                    virtual QString textForData(const QVariant& val);
                    virtual void setItemData(int index, const QVariant& data, int role=256);
                    virtual QVariant itemData(int index, int role = 256);
                    virtual void removeItem(int index);
                    virtual int findText(const QString & text) const;
                    virtual int findData(const QVariant & data, int role = Qt::UserRole) const;
                protected:
                    QStandardItemModel* m_comboModel;
                    QSortFilterProxyModel* m_comboProxy;
                };
                
                #endif // COMBOBOXDELEGATE_H
                

                source

                #include "ComboBoxDelegate.h"
                #include <QComboBox>
                #include <QStandardItemModel>
                #include <QApplication>
                #include <QSortFilterProxyModel>
                ComboBoxDelegate::ComboBoxDelegate(QObject *parent)
                    : QStyledItemDelegate(parent)
                {
                    m_comboModel = new QStandardItemModel(this);
                    m_comboModel->insertColumn(0);
                    m_comboProxy = new QSortFilterProxyModel(this);
                    m_comboProxy->setSourceModel(m_comboModel);
                }
                
                QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
                {
                    QComboBox* result = new QComboBox(parent);
                    m_comboProxy->sort(0);
                    result->setModel(m_comboProxy);
                    return result;
                }
                
                void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
                {
                    if (index.data(Qt::EditRole).isNull())
                        qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1);
                    else
                        qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString());
                }
                
                void ComboBoxDelegate::clear()
                {
                    m_comboModel->removeRows(0,m_comboModel->rowCount());
                }
                
                void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val)
                {
                    m_comboModel->insertRow(m_comboModel->rowCount());
                    m_comboModel->setData(m_comboModel->index(m_comboModel->rowCount()-1,0),txt);
                    m_comboModel->setData(m_comboModel->index(m_comboModel->rowCount() - 1, 0), val,Qt::UserRole);
                }
                
                void ComboBoxDelegate::addItem(const QString& txt)
                {
                    addItem(txt, QVariant());
                }
                
                QString ComboBoxDelegate::textForData(const QVariant& val)
                {
                    for (int i = 0; i < m_comboModel->rowCount();++i){
                        if (m_comboModel->index(i, 0).data(Qt::UserRole) == val)
                            return m_comboModel->index(i, 0).data().toString();
                    }
                    return QString();
                }
                
                void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role)
                {
                    if (index < 0 || index >= m_comboProxy->rowCount())
                        return;
                    m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role);
                }
                
                QVariant ComboBoxDelegate::itemData(int index, int role)
                {
                    if (index < 0 || index >= m_comboProxy->rowCount())
                        return QVariant();
                    return m_comboProxy->index(index, 0).data(role);
                }
                
                void ComboBoxDelegate::removeItem(int index)
                {
                    if (index < 0 || index >= m_comboProxy->rowCount())
                        return;
                    m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row());
                }
                
                int ComboBoxDelegate::findText(const QString & text) const
                {
                    for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                        if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0)
                            return i;
                    }
                    return -1;
                }
                
                int ComboBoxDelegate::findData(const QVariant & data, int role /*= Qt::UserRole*/) const
                {
                    for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                        if (m_comboProxy->index(i, 0).data(role) == data)
                            return i;
                    }
                    return -1;
                }
                
                void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
                {
                    auto combo = qobject_cast<QComboBox*>(editor);
                    if (combo->currentIndex() < 0) {
                        model->setData(index, QVariant(), Qt::EditRole);
                        model->setData(index, QVariant(), Qt::UserRole);
                    }
                    else {
                        model->setData(index, combo->currentText(), Qt::EditRole);
                        model->setData(index, combo->currentData(), Qt::UserRole);
                    }
                }
                void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
                {
                    editor->setGeometry(option.rect);
                }
                
                QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const
                {
                    int MaxWid = 0;
                    for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                        const int optWid = option.fontMetrics.width(displayText(m_comboProxy->index(i, 0).data(),QLocale()));
                        if (optWid>MaxWid)
                            MaxWid = optWid;
                    }
                    return qApp->style()->sizeFromContents(
                        QStyle::CT_ComboBox,
                        &option,
                        QSize(MaxWid, option.fontMetrics.height())
                        );
                }
                

                "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

                K 1 Reply Last reply 31 Aug 2017, 15:32
                4
                • V VRonin
                  31 Aug 2017, 10:44

                  This is a small class from one of my projects. It supports Qt::EditRole and Qt::UserRole. It also automatically sorts the entries (which I'm unsure if it's something you want). You'll just have to change createEditor slightly to allow the combobox to be typed into

                  header

                  #ifndef COMBOBOXDELEGATE_H
                  #define COMBOBOXDELEGATE_H
                  
                  #include <QStyledItemDelegate>
                  #include <QString>
                  class QComboBox;
                  class QStandardItemModel;
                  class QSortFilterProxyModel;
                  class ComboBoxDelegate : public QStyledItemDelegate
                  {
                      Q_OBJECT
                      Q_DISABLE_COPY(ComboBoxDelegate)
                  public:
                      explicit ComboBoxDelegate(QObject *parent = Q_NULLPTR);
                      virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
                      virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
                      virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
                      virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
                      virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index)  const override;
                      virtual void clear();
                      virtual void addItem(const QString& txt, const QVariant& val);
                      virtual void addItem(const QString& txt);
                      virtual QString textForData(const QVariant& val);
                      virtual void setItemData(int index, const QVariant& data, int role=256);
                      virtual QVariant itemData(int index, int role = 256);
                      virtual void removeItem(int index);
                      virtual int findText(const QString & text) const;
                      virtual int findData(const QVariant & data, int role = Qt::UserRole) const;
                  protected:
                      QStandardItemModel* m_comboModel;
                      QSortFilterProxyModel* m_comboProxy;
                  };
                  
                  #endif // COMBOBOXDELEGATE_H
                  

                  source

                  #include "ComboBoxDelegate.h"
                  #include <QComboBox>
                  #include <QStandardItemModel>
                  #include <QApplication>
                  #include <QSortFilterProxyModel>
                  ComboBoxDelegate::ComboBoxDelegate(QObject *parent)
                      : QStyledItemDelegate(parent)
                  {
                      m_comboModel = new QStandardItemModel(this);
                      m_comboModel->insertColumn(0);
                      m_comboProxy = new QSortFilterProxyModel(this);
                      m_comboProxy->setSourceModel(m_comboModel);
                  }
                  
                  QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
                  {
                      QComboBox* result = new QComboBox(parent);
                      m_comboProxy->sort(0);
                      result->setModel(m_comboProxy);
                      return result;
                  }
                  
                  void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
                  {
                      if (index.data(Qt::EditRole).isNull())
                          qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1);
                      else
                          qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString());
                  }
                  
                  void ComboBoxDelegate::clear()
                  {
                      m_comboModel->removeRows(0,m_comboModel->rowCount());
                  }
                  
                  void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val)
                  {
                      m_comboModel->insertRow(m_comboModel->rowCount());
                      m_comboModel->setData(m_comboModel->index(m_comboModel->rowCount()-1,0),txt);
                      m_comboModel->setData(m_comboModel->index(m_comboModel->rowCount() - 1, 0), val,Qt::UserRole);
                  }
                  
                  void ComboBoxDelegate::addItem(const QString& txt)
                  {
                      addItem(txt, QVariant());
                  }
                  
                  QString ComboBoxDelegate::textForData(const QVariant& val)
                  {
                      for (int i = 0; i < m_comboModel->rowCount();++i){
                          if (m_comboModel->index(i, 0).data(Qt::UserRole) == val)
                              return m_comboModel->index(i, 0).data().toString();
                      }
                      return QString();
                  }
                  
                  void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role)
                  {
                      if (index < 0 || index >= m_comboProxy->rowCount())
                          return;
                      m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role);
                  }
                  
                  QVariant ComboBoxDelegate::itemData(int index, int role)
                  {
                      if (index < 0 || index >= m_comboProxy->rowCount())
                          return QVariant();
                      return m_comboProxy->index(index, 0).data(role);
                  }
                  
                  void ComboBoxDelegate::removeItem(int index)
                  {
                      if (index < 0 || index >= m_comboProxy->rowCount())
                          return;
                      m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row());
                  }
                  
                  int ComboBoxDelegate::findText(const QString & text) const
                  {
                      for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                          if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0)
                              return i;
                      }
                      return -1;
                  }
                  
                  int ComboBoxDelegate::findData(const QVariant & data, int role /*= Qt::UserRole*/) const
                  {
                      for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                          if (m_comboProxy->index(i, 0).data(role) == data)
                              return i;
                      }
                      return -1;
                  }
                  
                  void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
                  {
                      auto combo = qobject_cast<QComboBox*>(editor);
                      if (combo->currentIndex() < 0) {
                          model->setData(index, QVariant(), Qt::EditRole);
                          model->setData(index, QVariant(), Qt::UserRole);
                      }
                      else {
                          model->setData(index, combo->currentText(), Qt::EditRole);
                          model->setData(index, combo->currentData(), Qt::UserRole);
                      }
                  }
                  void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
                  {
                      editor->setGeometry(option.rect);
                  }
                  
                  QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const
                  {
                      int MaxWid = 0;
                      for (int i = 0; i < m_comboProxy->rowCount(); ++i) {
                          const int optWid = option.fontMetrics.width(displayText(m_comboProxy->index(i, 0).data(),QLocale()));
                          if (optWid>MaxWid)
                              MaxWid = optWid;
                      }
                      return qApp->style()->sizeFromContents(
                          QStyle::CT_ComboBox,
                          &option,
                          QSize(MaxWid, option.fontMetrics.height())
                          );
                  }
                  
                  K Offline
                  K Offline
                  koahnig
                  wrote on 31 Aug 2017, 15:32 last edited by
                  #8

                  @VRonin

                  Thanks for your code.

                  I have played, probably better to say messed around, a bit and seem to semi-understand what you are doing there.
                  For my trial I have basically used the wiki example and added your ComboBoxDelegate.

                  The wiki example starts out with an empty 4 by 10 table.

                  When simply adding a line

                  results->setEditable(true);
                  

                  in createEditor I got something to work.
                  The only problem was the line

                  m_comboProxy->sort(0);
                  

                  The behaviour of the QComboBox was not as expected. It basically showed only a blank line and last value entered. When choosing a different column, it showed the performance as expected, but that should be wrong, since the number of columns stays at 1. I guess it has to do with the incomplete use of the whole model.

                  The moment I will bypass the QSortFilterProxyModel and use directly the instance of the QStandardItemModel instead.

                  When I am using your source mostly as is, it provides an increasing list of entries of the whole table already done. Since I need the same basically for column-wise different entries, the solution will be a couple of instances of QStandardItemModel.

                  Can you offer an explanation why the sort does not work?

                  Vote the answer(s) that helped you to solve your issue(s)

                  V 1 Reply Last reply 31 Aug 2017, 15:40
                  0
                  • K koahnig
                    31 Aug 2017, 15:32

                    @VRonin

                    Thanks for your code.

                    I have played, probably better to say messed around, a bit and seem to semi-understand what you are doing there.
                    For my trial I have basically used the wiki example and added your ComboBoxDelegate.

                    The wiki example starts out with an empty 4 by 10 table.

                    When simply adding a line

                    results->setEditable(true);
                    

                    in createEditor I got something to work.
                    The only problem was the line

                    m_comboProxy->sort(0);
                    

                    The behaviour of the QComboBox was not as expected. It basically showed only a blank line and last value entered. When choosing a different column, it showed the performance as expected, but that should be wrong, since the number of columns stays at 1. I guess it has to do with the incomplete use of the whole model.

                    The moment I will bypass the QSortFilterProxyModel and use directly the instance of the QStandardItemModel instead.

                    When I am using your source mostly as is, it provides an increasing list of entries of the whole table already done. Since I need the same basically for column-wise different entries, the solution will be a couple of instances of QStandardItemModel.

                    Can you offer an explanation why the sort does not work?

                    V Offline
                    V Offline
                    VRonin
                    wrote on 31 Aug 2017, 15:40 last edited by VRonin
                    #9

                    @koahnig said in Changes in table with combo boxes:

                    Since I need the same basically for column-wise different entries, the solution will be a couple of instances of QStandardItemModel.

                    No, just call setItemDelegateForColumn in the view with a different instance of the delegate for every column. This way is more reusable and scalable

                    @koahnig said in Changes in table with combo boxes:

                    When choosing a different column

                    strange, [this] should take care of the resorting. Otherwise use QComboBox::InsertAlphabetically sort policy on the combobox directly

                    "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

                    K 1 Reply Last reply 31 Aug 2017, 20:43
                    0
                    • V VRonin
                      31 Aug 2017, 15:40

                      @koahnig said in Changes in table with combo boxes:

                      Since I need the same basically for column-wise different entries, the solution will be a couple of instances of QStandardItemModel.

                      No, just call setItemDelegateForColumn in the view with a different instance of the delegate for every column. This way is more reusable and scalable

                      @koahnig said in Changes in table with combo boxes:

                      When choosing a different column

                      strange, [this] should take care of the resorting. Otherwise use QComboBox::InsertAlphabetically sort policy on the combobox directly

                      K Offline
                      K Offline
                      koahnig
                      wrote on 31 Aug 2017, 20:43 last edited by
                      #10

                      @VRonin said in Changes in table with combo boxes:

                      @koahnig said in Changes in table with combo boxes:

                      Since I need the same basically for column-wise different entries, the solution will be a couple of instances of QStandardItemModel.

                      No, just call setItemDelegateForColumn in the view with a different instance of the delegate for every column. This way is more reusable and scalable

                      Yep, found already that I was thinking too complecated ;)

                      @VRonin said in Changes in table with combo boxes:

                      @koahnig said in Changes in table with combo boxes:

                      When choosing a different column

                      strange, [this] should take care of the resorting. Otherwise use QComboBox::InsertAlphabetically sort policy on the combobox directly

                      InsertAlphabetically does the trick.

                      However, I still have to bypass the proxymodel as in here:

                      //#define USE_COMBO_PROXY
                      QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
                      {
                          QComboBox* result = new QComboBox(parent);
                          result->setEditable( true );
                          result->setInsertPolicy( QComboBox::InsertAlphabetically );
                      
                      #ifdef USE_COMBO_PROXY
                          m_comboProxy->sort( 0 );
                          result->setModel(m_comboProxy);
                      #else
                          result->setModel(m_comboModel);
                      #endif 
                      
                          return result;
                      }
                      

                      Vote the answer(s) that helped you to solve your issue(s)

                      1 Reply Last reply
                      0
                      • K Offline
                        K Offline
                        koahnig
                        wrote on 31 Aug 2017, 21:02 last edited by
                        #11

                        Currently I am testing with this class derived from QTablewidget
                        header

                        #ifndef MYTABLEWIDGET_H
                        #define MYTABLEWIDGET_H
                        
                        #include <QTableWidget>
                        
                        class MyTableWidget : public QTableWidget
                        {
                        public:
                            MyTableWidget();
                        
                            void setItem ( int row, int col, const QString & text );
                        };
                        
                        #endif // MYTABLEWIDGET_H
                        

                        Source

                        #include "MyTableWidget.h"
                        
                        #include "ComboBoxDelegate.h"
                        
                        MyTableWidget::MyTableWidget()
                        {
                            ComboBoxDelegate *vr = new ComboBoxDelegate ( this );
                            setColumnCount(4);
                            setItemDelegateForColumn ( 1, vr );
                            setItemDelegateForColumn ( 2, new ComboBoxDelegate ( this ) );
                            setItemDelegateForColumn ( 3, new ComboBoxDelegate ( this ) );
                            setRowCount(10);
                            resize(600,400);
                            setItem ( 1, 0, "test 1 0" );
                            setItem ( 1, 1, "test 1 1" );
                            setItem ( 1, 2, "test 1 2" );
                        
                        }
                        
                        void MyTableWidget::setItem ( int row, int col, const QString & text )
                        {
                            QTableWidget::setItem ( row, col, new QTableWidgetItem ( text ) );
                            ComboBoxDelegate *vr = qobject_cast < ComboBoxDelegate * > ( this->itemDelegateForColumn ( col ) );
                            if ( vr )
                            {
                                vr->addItem ( text, row );
                            }
                        }
                        

                        And a main

                        #include <QApplication>
                        #include "MyTableWidget.h"
                        
                        int main(int argc, char *argv[])
                        {
                            QApplication a(argc, argv);
                        
                            MyTableWidget tw;
                        
                            tw.show();
                        
                            return a.exec();
                        }
                        

                        Vote the answer(s) that helped you to solve your issue(s)

                        1 Reply Last reply
                        0
                        • V Offline
                          V Offline
                          VRonin
                          wrote on 1 Sept 2017, 07:18 last edited by VRonin 9 Jan 2017, 11:47
                          #12

                          You probably need to tweak the setEditorData method. qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); assumes the index.data(Qt::EditRole).toString() is already in the combo box list which might not be the case. change it to:

                          {
                          auto comboEditor =qobject_cast<QComboBox*>(editor);
                          Q_ASSERT(comboEditor);
                          const QString& textToFind = index.data(Qt::EditRole).toString();
                          int itemIdx = comboEditor->findText(textToFind);
                          if(itemIdx<0){
                          comboEditor->addItem(textToFind);
                          itemIdx  = comboEditor->findText(textToFind);
                          }
                          Q_ASSERT(itemIdx>=0);
                          comboEditor->setCurrentIndex(itemIdx);
                          }
                          

                          EDIT fixed compile fail and wrong Q_ASSERT condition

                          "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

                          K 1 Reply Last reply 1 Sept 2017, 10:58
                          1
                          • V VRonin
                            1 Sept 2017, 07:18

                            You probably need to tweak the setEditorData method. qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); assumes the index.data(Qt::EditRole).toString() is already in the combo box list which might not be the case. change it to:

                            {
                            auto comboEditor =qobject_cast<QComboBox*>(editor);
                            Q_ASSERT(comboEditor);
                            const QString& textToFind = index.data(Qt::EditRole).toString();
                            int itemIdx = comboEditor->findText(textToFind);
                            if(itemIdx<0){
                            comboEditor->addItem(textToFind);
                            itemIdx  = comboEditor->findText(textToFind);
                            }
                            Q_ASSERT(itemIdx>=0);
                            comboEditor->setCurrentIndex(itemIdx);
                            }
                            

                            EDIT fixed compile fail and wrong Q_ASSERT condition

                            K Offline
                            K Offline
                            koahnig
                            wrote on 1 Sept 2017, 10:58 last edited by
                            #13

                            @VRonin

                            Thanks for update.

                            Unfortunately, the tweaking does not work. setEditorData is a const method. Therefore, the compiler complains about addItem use.

                            Just for completeness. The main tests on my side are on Win 10 and Qt 5.4.2 with MinGW. I have checked it also with Qt 5.9.1 for MinGW. The use of proxy model is always an issue. However, the behaviour is different for both versions.
                            The major issue is for Qt 5.4.2 that ComboBox entries held are 2 text plus a varying number blank lines at top.
                            For Qt 5.9.1 it is the opposite. Apparently, two blank lines at the end and varying number of entries at top, but also some are missing.
                            I am giving up for testing at the time, since my knowledge is not sound enough, yet. Also is the functionality with by-passing of proxy model sufficient for my current use case.

                            However, it is time give the following statements.
                            Even though I am "complaining" about some deficiencies in your code, I see it more as a feedback in case you need some input.
                            Your assistance helped significantly improving my speed in getting a workable solution.

                            A huge thanks for turbo-teaching!!

                            Vote the answer(s) that helped you to solve your issue(s)

                            V 1 Reply Last reply 1 Sept 2017, 11:42
                            0
                            • K koahnig
                              1 Sept 2017, 10:58

                              @VRonin

                              Thanks for update.

                              Unfortunately, the tweaking does not work. setEditorData is a const method. Therefore, the compiler complains about addItem use.

                              Just for completeness. The main tests on my side are on Win 10 and Qt 5.4.2 with MinGW. I have checked it also with Qt 5.9.1 for MinGW. The use of proxy model is always an issue. However, the behaviour is different for both versions.
                              The major issue is for Qt 5.4.2 that ComboBox entries held are 2 text plus a varying number blank lines at top.
                              For Qt 5.9.1 it is the opposite. Apparently, two blank lines at the end and varying number of entries at top, but also some are missing.
                              I am giving up for testing at the time, since my knowledge is not sound enough, yet. Also is the functionality with by-passing of proxy model sufficient for my current use case.

                              However, it is time give the following statements.
                              Even though I am "complaining" about some deficiencies in your code, I see it more as a feedback in case you need some input.
                              Your assistance helped significantly improving my speed in getting a workable solution.

                              A huge thanks for turbo-teaching!!

                              V Offline
                              V Offline
                              VRonin
                              wrote on 1 Sept 2017, 11:42 last edited by
                              #14

                              @koahnig said in Changes in table with combo boxes:

                              the compiler complains about addItem use.

                              you can still copy the entire content of additem in that block or exploit the combo and call comboEditor->addItem instead. also, probably it's worth preventing empty (or even whitespace only) strings to be added

                              The blank lines are weird. you could check what is going on by inquiring m_comboProxy->rowCount()

                              "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

                              K V 2 Replies Last reply 1 Sept 2017, 14:47
                              0
                              • V VRonin
                                1 Sept 2017, 11:42

                                @koahnig said in Changes in table with combo boxes:

                                the compiler complains about addItem use.

                                you can still copy the entire content of additem in that block or exploit the combo and call comboEditor->addItem instead. also, probably it's worth preventing empty (or even whitespace only) strings to be added

                                The blank lines are weird. you could check what is going on by inquiring m_comboProxy->rowCount()

                                K Offline
                                K Offline
                                koahnig
                                wrote on 1 Sept 2017, 14:47 last edited by
                                #15

                                @VRonin

                                Code of setEditorData

                                {
                                    auto comboEditor =qobject_cast<QComboBox*>(editor);
                                    Q_ASSERT(comboEditor);
                                    const QString& textToFind = index.data(Qt::EditRole).toString();
                                    int itemIdx = comboEditor->findText(textToFind);
                                    if(itemIdx<0){
                                        comboEditor->addItem(textToFind);
                                        itemIdx  = comboEditor->findText(textToFind);
                                        qDebug() << "addItem " << textToFind << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                    }
                                    Q_ASSERT ( itemIdx >= 0 );
                                    comboEditor->setCurrentIndex(itemIdx);
                                    qDebug() << "in combo box " << comboEditor->currentText() << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();;
                                }
                                

                                Double click on 4, 2
                                Typing "Testing" <enter>
                                Double click on 6, 2
                                Typing "erf"
                                Double click 8, 2
                                Typing "Zufall"

                                output window:

                                Starting r:\build-AnotherComboBoxTest-Desktop_Qt_5_9_1_MinGW_32bit-Debug\debug\AnotherComboBoxTest.exe...
                                addItem  ""   0   2   1
                                in combo box  ""   0   2   1
                                in combo box  "testing"   2   3   1
                                in combo box  "testing"   2   3   1
                                in combo box  ""   0   3   1
                                in combo box  "erf"   1   4   1
                                in combo box  "erf"   1   4   1
                                in combo box  ""   0   4   1
                                in combo box  ""   0   5   1
                                in combo box  ""   0   5   1
                                

                                That's the outcome
                                0_1504276956694_b09f76a4-5adb-4721-b3d9-57667fced486-image.png

                                Vote the answer(s) that helped you to solve your issue(s)

                                1 Reply Last reply
                                0
                                • V VRonin
                                  1 Sept 2017, 11:42

                                  @koahnig said in Changes in table with combo boxes:

                                  the compiler complains about addItem use.

                                  you can still copy the entire content of additem in that block or exploit the combo and call comboEditor->addItem instead. also, probably it's worth preventing empty (or even whitespace only) strings to be added

                                  The blank lines are weird. you could check what is going on by inquiring m_comboProxy->rowCount()

                                  V Offline
                                  V Offline
                                  VRonin
                                  wrote on 1 Sept 2017, 15:04 last edited by VRonin 9 Jan 2017, 15:05
                                  #16

                                  Yep, that's what I meant with:

                                  @VRonin said in Changes in table with combo boxes:

                                  also, probably it's worth preventing empty (or even whitespace only) strings

                                  void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
                                  {
                                      if (index.data(Qt::EditRole).isNull())
                                          qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1);
                                      else
                                  {
                                      auto comboEditor =qobject_cast<QComboBox*>(editor);
                                      Q_ASSERT(comboEditor);
                                      const QString& textToFind = index.data(Qt::EditRole).toString();
                                      //make sure you are not just searching whitespace
                                  const QRegularExpression realTextRegExp("\S+");
                                  if(!realTextRegExp.match(textToFind).hasMatch()){
                                  comboEditor->setCurrentIndex(-1);
                                  return;
                                  }
                                  int itemIdx = comboEditor->findText(textToFind);
                                      if(itemIdx<0){
                                          comboEditor->addItem(textToFind);
                                          itemIdx  = comboEditor->findText(textToFind);
                                          qDebug() << "addItem " << textToFind << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                      }
                                      Q_ASSERT ( itemIdx >= 0 );
                                      comboEditor->setCurrentIndex(itemIdx);
                                      qDebug() << "in combo box " << comboEditor->currentText() << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                  }
                                  }
                                  

                                  "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

                                  K 1 Reply Last reply 1 Sept 2017, 16:15
                                  1
                                  • V VRonin
                                    1 Sept 2017, 15:04

                                    Yep, that's what I meant with:

                                    @VRonin said in Changes in table with combo boxes:

                                    also, probably it's worth preventing empty (or even whitespace only) strings

                                    void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
                                    {
                                        if (index.data(Qt::EditRole).isNull())
                                            qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1);
                                        else
                                    {
                                        auto comboEditor =qobject_cast<QComboBox*>(editor);
                                        Q_ASSERT(comboEditor);
                                        const QString& textToFind = index.data(Qt::EditRole).toString();
                                        //make sure you are not just searching whitespace
                                    const QRegularExpression realTextRegExp("\S+");
                                    if(!realTextRegExp.match(textToFind).hasMatch()){
                                    comboEditor->setCurrentIndex(-1);
                                    return;
                                    }
                                    int itemIdx = comboEditor->findText(textToFind);
                                        if(itemIdx<0){
                                            comboEditor->addItem(textToFind);
                                            itemIdx  = comboEditor->findText(textToFind);
                                            qDebug() << "addItem " << textToFind << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                        }
                                        Q_ASSERT ( itemIdx >= 0 );
                                        comboEditor->setCurrentIndex(itemIdx);
                                        qDebug() << "in combo box " << comboEditor->currentText() << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                    }
                                    }
                                    
                                    K Offline
                                    K Offline
                                    koahnig
                                    wrote on 1 Sept 2017, 16:15 last edited by
                                    #17

                                    @VRonin

                                    I am sorry to correct, but it doesn't help either.

                                    The problem is with the index coming into setEditorData

                                    Here is my latest code:

                                    void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
                                    {
                                        if (index.data(Qt::EditRole).isNull())
                                            qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1);
                                        else
                                        {
                                            auto comboEditor =qobject_cast<QComboBox*>(editor);
                                            Q_ASSERT(comboEditor);
                                            qDebug() << " index " << index;
                                            const QString& textToFind = index.data(Qt::EditRole).toString();
                                            qDebug() << "textToFind before reg exp " << textToFind;
                                            //make sure you are not just searching whitespace
                                            const QRegularExpression realTextRegExp("\\S+");
                                            if( ! realTextRegExp.match(textToFind).hasMatch()){
                                                qDebug() << "textToFind " << textToFind;
                                                comboEditor->setCurrentIndex(-1);
                                                return;
                                            }
                                            int itemIdx = comboEditor->findText(textToFind);
                                            if(itemIdx<0){
                                                comboEditor->addItem(textToFind);
                                                itemIdx  = comboEditor->findText(textToFind);
                                                qDebug() << "addItem " << textToFind << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                            }
                                            Q_ASSERT ( itemIdx >= 0 );
                                            comboEditor->setCurrentIndex(itemIdx);
                                            qDebug() << "in combo box " << comboEditor->currentText() << " " << itemIdx << " " << m_comboProxy->rowCount() << " " << m_comboProxy->columnCount();
                                        }
                                    }
                                    

                                    That is the latest output:

                                    Starting r:\build-AnotherComboBoxTest-Desktop_Qt_5_9_1_MinGW_32bit-Debug\debug\AnotherComboBoxTest.exe...
                                    no delegate found
                                    addItem  "test 1 1"   E:\Source\AnotherComboBoxTest\MyTableWidget.cpp 28
                                    addItem  "test 1 2"   E:\Source\AnotherComboBoxTest\MyTableWidget.cpp 28
                                     index  QModelIndex(3,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  "testing"
                                    in combo box  "testing"   1   2   1
                                     index  QModelIndex(3,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  "testing"
                                    in combo box  "testing"   1   2   1
                                     index  QModelIndex(5,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  "erf"
                                    in combo box  "erf"   0   3   1
                                     index  QModelIndex(5,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  "erf"
                                    in combo box  "erf"   0   3   1
                                     index  QModelIndex(7,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  ""
                                    textToFind  ""
                                     index  QModelIndex(7,1,0x0,QTableModel(0x175fb6a8))
                                    textToFind before reg exp  ""
                                    textToFind  ""
                                    

                                    In additiion the update problems there are also the initial input for this test "test 1 1" not covered anymore after some input directly to the table.

                                    Vote the answer(s) that helped you to solve your issue(s)

                                    1 Reply Last reply
                                    0
                                    • V Offline
                                      V Offline
                                      VRonin
                                      wrote on 1 Sept 2017, 16:35 last edited by
                                      #18

                                      Isn't that the correct output? what were you expecting?

                                      "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

                                      K 1 Reply Last reply 1 Sept 2017, 16:55
                                      0
                                      • V VRonin
                                        1 Sept 2017, 16:35

                                        Isn't that the correct output? what were you expecting?

                                        K Offline
                                        K Offline
                                        koahnig
                                        wrote on 1 Sept 2017, 16:55 last edited by
                                        #19

                                        @VRonin

                                        Nope, I did the same as with the previous tests. Only lower case letters this time. The input was:

                                        • Double click on 4, 2
                                        • Typing "testing" <enter>
                                        • Double click on 6, 2
                                        • Typing "erf" <enter>
                                        • Double click 8, 2
                                        • Typing "zufall" <enter>

                                        Vote the answer(s) that helped you to solve your issue(s)

                                        1 Reply Last reply
                                        0
                                        • K Offline
                                          K Offline
                                          koahnig
                                          wrote on 1 Sept 2017, 17:17 last edited by
                                          #20

                                          We are back to the start :(

                                          #define USE_COMBO_PROXY
                                          QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
                                          {
                                              QComboBox* result = new QComboBox(parent);
                                              result->setEditable( true );
                                              result->setInsertPolicy( QComboBox::InsertAlphabetically );
                                          
                                          #ifdef USE_COMBO_PROXY
                                          //    m_comboProxy->sort( 0 );
                                              result->setModel(m_comboProxy);
                                          #else
                                              result->setModel(m_comboModel);
                                          #endif
                                          
                                              return result;
                                          }
                                          

                                          Commenting out m_comboProxy->sort( 0 ) or by-passing the whole proxy model do work correctly.

                                          Vote the answer(s) that helped you to solve your issue(s)

                                          1 Reply Last reply
                                          0

                                          1/23

                                          31 Aug 2017, 08:45

                                          • Login

                                          • Login or register to search.
                                          1 out of 23
                                          • First post
                                            1/23
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved