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. Using setData(Qt::EditRole, xxx) with QTableWidgetItem

Using setData(Qt::EditRole, xxx) with QTableWidgetItem

Scheduled Pinned Locked Moved Solved General and Desktop
19 Posts 3 Posters 10.3k 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.
  • divergerD Offline
    divergerD Offline
    diverger
    wrote on last edited by
    #1

    I'm using a QTableWidget and add items like this:

    item = new QTableWidgetItem;
    item->setData(Qt::EditRole, xx);
    ui.testTableWidget->setItem(row, 0, item);
    
    

    "xx" is a double variable. The result is almost perfect for me. When I click the cell, a double spinbox appear, and I can change the value, but after I move the focus out, it only keep two decimals for me. I wonder how can I set the decimal count that cell hold???

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      You are opening the pandora vase.

      The solution is create a class:

      class PeciseDoubleFactory : public QItemEditorFactory{
      public:
      PeciseDoubleFactory() = default;
      virtual ~PeciseDoubleFactory() = default;
      virtual QWidget* createEditor(int userType, QWidget *parent) const override{
      if(userType == QVariant::Double){
              QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
              sb->setFrame(false);
              sb->setMinimum(-DBL_MAX);
              sb->setMaximum(DBL_MAX);
              sb->setDecimals(6); // This is the maximum number of decimals you want
              return sb;
      }
      return QItemEditorFactory::(userType,parent);
      }
      };
      

      then you have to set the delegate like this:

      // PeciseDoubleFactory m_factory; is a private member
      QStyledItemDelegate* preciseDoubleDelegate=new QStyledItemDelegate(ui.testTableWidget);
      preciseDoubleDelegate->setItemEditorFactory(&m_factory);
      ui.testTableWidget->setItemDelegate(preciseDoubleDelegate);
      

      If you want to know what is happening here is the long story:

      • QTableWidget uses the default QStyledItemDelegate
      • QStyledItemDelegate, when you try to edit a value, will call the editor from the default QItemEditorFactory
      • QItemEditorFactory if the value you are editing is a double will create a default QDoubleSpinBox
      • QDoubleSpinBox has 2 decimals by default
      • When editing is finished the QDoubleSpinBox::value is used to determine the new value that goes into the model and, as stated in QDoubleSpinBox documentation, it will round the returned value to the set number of decimals. Here is when you have a problem
      • The delegate will then convert the double in the model to string

      "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

      T 1 Reply Last reply
      5
      • divergerD Offline
        divergerD Offline
        diverger
        wrote on last edited by
        #3

        Thanks.

        More further, it seems the entire widget use only one editor factory, what if I want to give different cells with different decimal count? Can I implement that base on your solution?

        Sure, I can create dozens of QDoublespinbox, and give them needed decimal count and bind them to each cell, but that seems so ugly. That will be my last choice.

        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #4

          This allows you to chose the number of decimals:

          class PeciseDoubleFactory : public QItemEditorFactory{
          private:
          int m_decimals;
          public:
          void setDecimals(int val){
          if(val<=0)
          m_decimals=2;
          else
          m_decimals=val;
          }
          int decimals() const { return m_decimals;}
          PeciseDoubleFactory() :m_decimals(2) {}
          virtual ~PeciseDoubleFactory() = default;
          virtual QWidget* createEditor(int userType, QWidget *parent) const override{
          QWidget* result = QItemEditorFactory::(userType,parent);
          if(userType == QMetaType::Double){
                 Q_ASSERT(qobject_cast<QDoubleSpinBox*>(result));
                  qobject_cast<QDoubleSpinBox*>(result)->setDecimals(m_decimals);
          }
          return result;
          }
          };
          

          To have different decimals across the model just create different QStyledItemDelegate with different PeciseDoubleFactory and use setItemDelegateForColumn or setItemDelegateForRow

          "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

          divergerD 1 Reply Last reply
          2
          • VRoninV VRonin

            This allows you to chose the number of decimals:

            class PeciseDoubleFactory : public QItemEditorFactory{
            private:
            int m_decimals;
            public:
            void setDecimals(int val){
            if(val<=0)
            m_decimals=2;
            else
            m_decimals=val;
            }
            int decimals() const { return m_decimals;}
            PeciseDoubleFactory() :m_decimals(2) {}
            virtual ~PeciseDoubleFactory() = default;
            virtual QWidget* createEditor(int userType, QWidget *parent) const override{
            QWidget* result = QItemEditorFactory::(userType,parent);
            if(userType == QMetaType::Double){
                   Q_ASSERT(qobject_cast<QDoubleSpinBox*>(result));
                    qobject_cast<QDoubleSpinBox*>(result)->setDecimals(m_decimals);
            }
            return result;
            }
            };
            

            To have different decimals across the model just create different QStyledItemDelegate with different PeciseDoubleFactory and use setItemDelegateForColumn or setItemDelegateForRow

            divergerD Offline
            divergerD Offline
            diverger
            wrote on last edited by diverger
            #5

            @VRonin Thanks for your help. Now I have another problem. Assume I double press one cell, and a spinbox appear and I change it's value to 2.00, but after the editing, the text showed in the cell change to "2", it abandoned the trailing zeros. How to make it preserve the trailing zeros?

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6
              class DecimalsDelegate : public QStyledItemDelegate{
              Q_OBJECT
              Q_PROPERTY(unsigned int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged)
              public:
              explicit DecimalsDelegate(QObject* parent = nullptr)
              :QStyledItemDelegate(parent)
              ,m_decimals(2U)
              {}
              virtual ~DecimalsDelegate() = default;
              DecimalsDelegate(const DecimalsDelegate&) = delete;
              DecimalsDelegate& operator=(const DecimalsDelegate&) = delete;
              void setDecimals(unsigned int dec){
              if(m_decimals!=dec){
              m_decimals=dec;
              emit decimalsChanged();
              }
              }
              unsigned int decimals() const { return m_decimals;}
              virtual QString displayText(const QVariant &value, const QLocale &locale) const override{
              switch(value.type()){
              case QMetaType::Double:
              case QMetaType::Float:
              return locale.toString(value.toDouble(),'f',m_decimals);
              default:
              return QStyledItemDelegate::displayText(value,locale);
              }
              }
              signals:
              void decimalsChanged();
              private:
              unsigned int m_decimals;
              }
              

              then use this class instead of the plain QStyledItemDelegate using setDecimals() to decide how many decimals you want to show

              "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

              divergerD 1 Reply Last reply
              4
              • VRoninV VRonin
                class DecimalsDelegate : public QStyledItemDelegate{
                Q_OBJECT
                Q_PROPERTY(unsigned int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged)
                public:
                explicit DecimalsDelegate(QObject* parent = nullptr)
                :QStyledItemDelegate(parent)
                ,m_decimals(2U)
                {}
                virtual ~DecimalsDelegate() = default;
                DecimalsDelegate(const DecimalsDelegate&) = delete;
                DecimalsDelegate& operator=(const DecimalsDelegate&) = delete;
                void setDecimals(unsigned int dec){
                if(m_decimals!=dec){
                m_decimals=dec;
                emit decimalsChanged();
                }
                }
                unsigned int decimals() const { return m_decimals;}
                virtual QString displayText(const QVariant &value, const QLocale &locale) const override{
                switch(value.type()){
                case QMetaType::Double:
                case QMetaType::Float:
                return locale.toString(value.toDouble(),'f',m_decimals);
                default:
                return QStyledItemDelegate::displayText(value,locale);
                }
                }
                signals:
                void decimalsChanged();
                private:
                unsigned int m_decimals;
                }
                

                then use this class instead of the plain QStyledItemDelegate using setDecimals() to decide how many decimals you want to show

                divergerD Offline
                divergerD Offline
                diverger
                wrote on last edited by
                #7

                @VRonin Great. This almost achieve my goal. I can set the decimals by column or row now. But any way to set them by cell. Now I have to show nums with different decimals in one column :(.

                BTW, anyway to know which cell the 'value' from in the displayText() function? If I can get the cell position from displayText(), then I can format the text with different decimals by the cell.

                1 Reply Last reply
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  There are different approaches here. Do you need a deterministic number of decimals or do you need as many decimals as the number has?
                  e.g.
                  data: 12.34500

                  do you have a 4 digits fixed so 12.3450 or as little digits as necessary to represent the number in full 12.345?

                  "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

                  divergerD 1 Reply Last reply
                  0
                  • VRoninV VRonin

                    There are different approaches here. Do you need a deterministic number of decimals or do you need as many decimals as the number has?
                    e.g.
                    data: 12.34500

                    do you have a 4 digits fixed so 12.3450 or as little digits as necessary to represent the number in full 12.345?

                    divergerD Offline
                    divergerD Offline
                    diverger
                    wrote on last edited by diverger
                    #9

                    @VRonin I set the data with Qt::EditRole, it's double. When I set the data, the needed decimal count is determined, too. If the data is 12.345, and I need 4 decimal, it should displayed as '12.3450'. If I only need 2 decimal, then it should displayed as '12.35'.

                    Them problem now is, I want some cells show 4, some cells show 3, and some cells show 2, etc.

                    1 Reply Last reply
                    0
                    • VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by VRonin
                      #10

                      Just use a role

                      class DecimalsDelegate : public QStyledItemDelegate{
                      Q_OBJECT
                      public:
                      enum { NumOfDecimalsRole = Qt::UserRole + 888 }; /* 888 is just a random number, you can use whatever you want if it conflicts */
                      explicit DecimalsDelegate(QObject* parent = nullptr)
                      :QStyledItemDelegate(parent)
                      {}
                      virtual ~DecimalsDelegate() = default;
                      DecimalsDelegate(const DecimalsDelegate&) = delete;
                      DecimalsDelegate& operator=(const DecimalsDelegate&) = delete;
                      virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
                      {
                          Q_ASSERT(index.isValid());
                      
                          QStyleOptionViewItem opt = option;
                          initStyleOption(&opt, index);
                      const QVariant numOfDecimals = index.data(NumOfDecimalsRole );
                          if (numOfDecimals.isValid() && !numOfDecimals.isNull() && numOfDecimals.canConvert(QMetaType::Int)  && ( opt.features & QStyleOptionViewItem::HasDisplay) ) {
                      const QVariant value = index.data(Qt::DisplayRole);
                      if(value.canConvert(QMetaType::Double))
                              opt.text = opt.locale.toString(value.toDouble(),'f',numOfDecimals.toInt());
                          }
                          const QWidget *widget = option.widget;
                          const QStyle* const style = widget ? widget->style() : QApplication::style();
                          style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                      }
                      
                      }
                      

                      now after you set the Qt::EditRole just set NumOfDecimalsRole to the number of decimals you need

                      Edit: fixed copy/paste error

                      "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

                      divergerD 2 Replies Last reply
                      4
                      • VRoninV VRonin

                        Just use a role

                        class DecimalsDelegate : public QStyledItemDelegate{
                        Q_OBJECT
                        public:
                        enum { NumOfDecimalsRole = Qt::UserRole + 888 }; /* 888 is just a random number, you can use whatever you want if it conflicts */
                        explicit DecimalsDelegate(QObject* parent = nullptr)
                        :QStyledItemDelegate(parent)
                        {}
                        virtual ~DecimalsDelegate() = default;
                        DecimalsDelegate(const DecimalsDelegate&) = delete;
                        DecimalsDelegate& operator=(const DecimalsDelegate&) = delete;
                        virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
                        {
                            Q_ASSERT(index.isValid());
                        
                            QStyleOptionViewItem opt = option;
                            initStyleOption(&opt, index);
                        const QVariant numOfDecimals = index.data(NumOfDecimalsRole );
                            if (numOfDecimals.isValid() && !numOfDecimals.isNull() && numOfDecimals.canConvert(QMetaType::Int)  && ( opt.features & QStyleOptionViewItem::HasDisplay) ) {
                        const QVariant value = index.data(Qt::DisplayRole);
                        if(value.canConvert(QMetaType::Double))
                                opt.text = opt.locale.toString(value.toDouble(),'f',numOfDecimals.toInt());
                            }
                            const QWidget *widget = option.widget;
                            const QStyle* const style = widget ? widget->style() : QApplication::style();
                            style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                        }
                        
                        }
                        

                        now after you set the Qt::EditRole just set NumOfDecimalsRole to the number of decimals you need

                        Edit: fixed copy/paste error

                        divergerD Offline
                        divergerD Offline
                        diverger
                        wrote on last edited by
                        #11

                        @VRonin Great, it work.

                        I have another idea. Because I can't know the current index of the model in the displayText function. So, I can't change the decimal count by the 'value' 's 'index'. But in 'setEditorData' and 'setModelData', and 'createEditor', I can know the 'index'. So, when I set the widget item, I use '

                        item->setData(Qt::EditRole, QString::number(ratio_error * 1000, 'f', 2));
                        ui.testTableWidget->setItem(row, 7, item);
                        
                        

                        And my derived class is as below:

                        virtual QWidget *createEditor(QWidget *parent, QStyleOptionViewItem const &option, QModelIndex const &index) const override
                        	{
                        		if (index.data(Qt::EditRole).isValid() && ((index.column() == 6) || (index.column() == 7)))
                        		{
                        			QDoubleSpinBox *spinbox = new QDoubleSpinBox(parent);
                        			QTableWidget *table = qobject_cast<QTableWidget *>(this->parent());
                        
                        			if (index.column() == 6)
                        			{
                        				spinbox->setDecimals(2);
                        			}
                        			else if (index.column() == 7)
                        			{
                        				spinbox->setDecimals(3);
                        			}
                        			
                        			return spinbox;
                        		}
                        		else
                        		{
                        			return QStyledItemDelegate::createEditor(parent, option, index);
                        		}
                        	}
                        
                        	virtual void iStyledItemDelegate::updateEditorGeometry(QWidget *editor,	QStyleOptionViewItem const &option,
                        		QModelIndex const &index) const override
                        	{
                        		editor->setGeometry(option.rect);
                        	}
                        
                        	virtual void iStyledItemDelegate::setEditorData(QWidget *editor, QModelIndex const &index) const override
                        	{
                        		if (index.data(Qt::EditRole).isValid() && ((index.column() == 6) || (index.column() == 7)))
                        		{
                        			double value = index.model()->data(index, Qt::EditRole).toString().toDouble();
                        			QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(editor);
                        			spinBox->setValue(value);
                        		}
                        		else
                        		{
                        			QStyledItemDelegate::setEditorData(editor, index);
                        		}
                        	}
                        
                        	virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
                        	{
                        		if (index.data(Qt::EditRole).isValid() && ((index.column() == 6) || (index.column() == 7)))
                        		{
                        			QDoubleSpinBox *spin = qobject_cast<QDoubleSpinBox *>(editor);
                        			spin->interpretText();
                        			double value = spin->value();
                        			int decimals = spin->decimals();
                        			QString text = QString::number(value, 'f', decimals);
                        			model->setData(index, text, Qt::EditRole);
                        		}
                        		else
                        		{
                        			QStyledItemDelegate::setModelData(editor, model, index);
                        		}
                        	}
                        

                        For the column 7 (the last column), it works as expected, but for column 6, when I double click the cell, the value goes to "0.00", and I debuged it, find for column 6, the invoke sequence is:

                        createEditor -> setEditorData -> setModelData, when invoke the 'setData' in this function, it invoke 'setEditorData' once more. It's right?

                        1 Reply Last reply
                        0
                        • VRoninV VRonin

                          Just use a role

                          class DecimalsDelegate : public QStyledItemDelegate{
                          Q_OBJECT
                          public:
                          enum { NumOfDecimalsRole = Qt::UserRole + 888 }; /* 888 is just a random number, you can use whatever you want if it conflicts */
                          explicit DecimalsDelegate(QObject* parent = nullptr)
                          :QStyledItemDelegate(parent)
                          {}
                          virtual ~DecimalsDelegate() = default;
                          DecimalsDelegate(const DecimalsDelegate&) = delete;
                          DecimalsDelegate& operator=(const DecimalsDelegate&) = delete;
                          virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
                          {
                              Q_ASSERT(index.isValid());
                          
                              QStyleOptionViewItem opt = option;
                              initStyleOption(&opt, index);
                          const QVariant numOfDecimals = index.data(NumOfDecimalsRole );
                              if (numOfDecimals.isValid() && !numOfDecimals.isNull() && numOfDecimals.canConvert(QMetaType::Int)  && ( opt.features & QStyleOptionViewItem::HasDisplay) ) {
                          const QVariant value = index.data(Qt::DisplayRole);
                          if(value.canConvert(QMetaType::Double))
                                  opt.text = opt.locale.toString(value.toDouble(),'f',numOfDecimals.toInt());
                              }
                              const QWidget *widget = option.widget;
                              const QStyle* const style = widget ? widget->style() : QApplication::style();
                              style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                          }
                          
                          }
                          

                          now after you set the Qt::EditRole just set NumOfDecimalsRole to the number of decimals you need

                          Edit: fixed copy/paste error

                          divergerD Offline
                          divergerD Offline
                          diverger
                          wrote on last edited by
                          #12

                          @VRonin Finally, I found the reason, I forgot set the minimum and maximum of the spinbox, it seem it's default minimum value is "0", and I just need show a minus float number in column 6. So it is "rounded" to zero.

                          Can you check my code below, if it's a 'right' usage case?

                          class iStyledItemDelegate : public QStyledItemDelegate
                          {
                          public:
                          	explicit iStyledItemDelegate(QObject *parent = nullptr)
                          		: QStyledItemDelegate(parent)
                          	{}
                          
                          	virtual ~iStyledItemDelegate() = default;
                          
                          	virtual QWidget *createEditor(QWidget *parent, QStyleOptionViewItem const &option, QModelIndex const &index) const override
                          	{
                          		if ((index.column() == 6) || (index.column() == 7))
                          		{
                          			QDoubleSpinBox *spinbox = new QDoubleSpinBox(parent);
                          			spinbox->installEventFilter(const_cast<iStyledItemDelegate*>(this));
                          			
                          			QTableWidget *table = qobject_cast<QTableWidget *>(this->parent());
                          			spinbox->setFrame(false);
                          			spinbox->setMinimum(-DBL_MAX);
                          			spinbox->setMaximum(DBL_MAX);
                          
                          			if (index.column() == 6)
                          			{
                          				spinbox->setDecimals(2);
                          			}
                          			else if (index.column() == 7)
                          			{
                          				spinbox->setDecimals(3);
                          			}
                          		
                          			return spinbox;
                          		}
                          		else
                          		{
                          			return QStyledItemDelegate::createEditor(parent, option, index);
                          		}
                          	}
                          
                          	virtual void updateEditorGeometry(QWidget *editor,	QStyleOptionViewItem const &option,
                          		QModelIndex const &index) const override
                          	{
                          		editor->setGeometry(option.rect);
                          	}
                          
                          	virtual void setEditorData(QWidget *editor, QModelIndex const &index) const override
                          	{
                          		QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(editor);
                          		
                          		if (spinBox && ((index.column() == 6) || (index.column() == 7)))
                          		{
                          			double value = index.data(Qt::EditRole).toString().toDouble();
                          			spinBox->setValue(value);
                          		}
                          		else
                          		{
                          			QStyledItemDelegate::setEditorData(editor, index);
                          		}
                          	}
                          
                          	virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
                          	{
                          		QDoubleSpinBox *spin = qobject_cast<QDoubleSpinBox *>(editor);
                          	
                          		if (spin && ((index.column() == 6) || (index.column() == 7)))
                          		{
                          			spin->interpretText();
                          			model->setData(index, spin->text(), Qt::EditRole);
                          		}
                          		else
                          		{
                          			QStyledItemDelegate::setModelData(editor, model, index);
                          		}
                          	}
                          };
                          
                          
                          VRoninV 1 Reply Last reply
                          0
                          • divergerD diverger

                            @VRonin Finally, I found the reason, I forgot set the minimum and maximum of the spinbox, it seem it's default minimum value is "0", and I just need show a minus float number in column 6. So it is "rounded" to zero.

                            Can you check my code below, if it's a 'right' usage case?

                            class iStyledItemDelegate : public QStyledItemDelegate
                            {
                            public:
                            	explicit iStyledItemDelegate(QObject *parent = nullptr)
                            		: QStyledItemDelegate(parent)
                            	{}
                            
                            	virtual ~iStyledItemDelegate() = default;
                            
                            	virtual QWidget *createEditor(QWidget *parent, QStyleOptionViewItem const &option, QModelIndex const &index) const override
                            	{
                            		if ((index.column() == 6) || (index.column() == 7))
                            		{
                            			QDoubleSpinBox *spinbox = new QDoubleSpinBox(parent);
                            			spinbox->installEventFilter(const_cast<iStyledItemDelegate*>(this));
                            			
                            			QTableWidget *table = qobject_cast<QTableWidget *>(this->parent());
                            			spinbox->setFrame(false);
                            			spinbox->setMinimum(-DBL_MAX);
                            			spinbox->setMaximum(DBL_MAX);
                            
                            			if (index.column() == 6)
                            			{
                            				spinbox->setDecimals(2);
                            			}
                            			else if (index.column() == 7)
                            			{
                            				spinbox->setDecimals(3);
                            			}
                            		
                            			return spinbox;
                            		}
                            		else
                            		{
                            			return QStyledItemDelegate::createEditor(parent, option, index);
                            		}
                            	}
                            
                            	virtual void updateEditorGeometry(QWidget *editor,	QStyleOptionViewItem const &option,
                            		QModelIndex const &index) const override
                            	{
                            		editor->setGeometry(option.rect);
                            	}
                            
                            	virtual void setEditorData(QWidget *editor, QModelIndex const &index) const override
                            	{
                            		QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(editor);
                            		
                            		if (spinBox && ((index.column() == 6) || (index.column() == 7)))
                            		{
                            			double value = index.data(Qt::EditRole).toString().toDouble();
                            			spinBox->setValue(value);
                            		}
                            		else
                            		{
                            			QStyledItemDelegate::setEditorData(editor, index);
                            		}
                            	}
                            
                            	virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
                            	{
                            		QDoubleSpinBox *spin = qobject_cast<QDoubleSpinBox *>(editor);
                            	
                            		if (spin && ((index.column() == 6) || (index.column() == 7)))
                            		{
                            			spin->interpretText();
                            			model->setData(index, spin->text(), Qt::EditRole);
                            		}
                            		else
                            		{
                            			QStyledItemDelegate::setModelData(editor, model, index);
                            		}
                            	}
                            };
                            
                            
                            VRoninV Offline
                            VRoninV Offline
                            VRonin
                            wrote on last edited by
                            #13

                            @diverger said in Using setData(Qt::EditRole, xxx) with QTableWidgetItem:

                            if it's a 'right' usage case

                            The delegate should never depend on the model or view structure so if (index.column() == is never the right usage case

                            "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

                            divergerD 1 Reply Last reply
                            1
                            • VRoninV VRonin

                              @diverger said in Using setData(Qt::EditRole, xxx) with QTableWidgetItem:

                              if it's a 'right' usage case

                              The delegate should never depend on the model or view structure so if (index.column() == is never the right usage case

                              divergerD Offline
                              divergerD Offline
                              diverger
                              wrote on last edited by diverger
                              #14

                              @VRonin Yes, I know it's not 'good' for 're-use'. But I can't find a method to set delegate to individual cells. In my case, take for example column 6. Some rows may need show 3, some rows may need show 2 decimals, depending on the column 2's contents. So I make this class dedicated to this. Any suggestions to implement my goal but no depending to 'index' in the derived class?

                              1 Reply Last reply
                              0
                              • VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #15

                                https://forum.qt.io/topic/71692/using-setdata-qt-editrole-xxx-with-qtablewidgetitem/10

                                Then set the NumOfDecimalsRole in a slot connected to the dataChanged of the model

                                Btw, looking at the code above it looks like you need 2 decimals in column 6 and 3 decimals in column 7 and this can be achieved with 2 delegates set on 2 columns with setItemDelegeateForColumn

                                P.S.

                                model->setData(index, spin->text(), Qt::EditRole);

                                this will set a string, not a number so the decimals in a string are meaningless

                                "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

                                divergerD 1 Reply Last reply
                                0
                                • VRoninV VRonin

                                  https://forum.qt.io/topic/71692/using-setdata-qt-editrole-xxx-with-qtablewidgetitem/10

                                  Then set the NumOfDecimalsRole in a slot connected to the dataChanged of the model

                                  Btw, looking at the code above it looks like you need 2 decimals in column 6 and 3 decimals in column 7 and this can be achieved with 2 delegates set on 2 columns with setItemDelegeateForColumn

                                  P.S.

                                  model->setData(index, spin->text(), Qt::EditRole);

                                  this will set a string, not a number so the decimals in a string are meaningless

                                  divergerD Offline
                                  divergerD Offline
                                  diverger
                                  wrote on last edited by diverger
                                  #16

                                  @VRonin :),

                                  1. In my previous example, I simplified my usage case.
                                  2. I use strings instead of numbers, because the displayText function won't abandon the trailing zeros of the number strings. I think if I use 'model->setData(index, spin->value(), Qt::EditRole);' , then the displayText() will format the numbers for me, and I can't access 'index' in it, so it will always abandon the trailing zeros.
                                  3. So, my solution is actually avoid using numbers, but use text, and when create editor, I format the text to number, when user finish the editing, I format the values back to text and store it in the model.
                                  1 Reply Last reply
                                  0
                                  • VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by
                                    #17

                                    This is a display problem so it should not be handled at the model level. as shown above, the solution is to reimplement paint() in the delegate

                                    "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

                                    divergerD 1 Reply Last reply
                                    2
                                    • VRoninV VRonin

                                      This is a display problem so it should not be handled at the model level. as shown above, the solution is to reimplement paint() in the delegate

                                      divergerD Offline
                                      divergerD Offline
                                      diverger
                                      wrote on last edited by
                                      #18

                                      @VRonin You are right. Thanks again. :)

                                      1 Reply Last reply
                                      0
                                      • VRoninV VRonin

                                        You are opening the pandora vase.

                                        The solution is create a class:

                                        class PeciseDoubleFactory : public QItemEditorFactory{
                                        public:
                                        PeciseDoubleFactory() = default;
                                        virtual ~PeciseDoubleFactory() = default;
                                        virtual QWidget* createEditor(int userType, QWidget *parent) const override{
                                        if(userType == QVariant::Double){
                                                QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
                                                sb->setFrame(false);
                                                sb->setMinimum(-DBL_MAX);
                                                sb->setMaximum(DBL_MAX);
                                                sb->setDecimals(6); // This is the maximum number of decimals you want
                                                return sb;
                                        }
                                        return QItemEditorFactory::(userType,parent);
                                        }
                                        };
                                        

                                        then you have to set the delegate like this:

                                        // PeciseDoubleFactory m_factory; is a private member
                                        QStyledItemDelegate* preciseDoubleDelegate=new QStyledItemDelegate(ui.testTableWidget);
                                        preciseDoubleDelegate->setItemEditorFactory(&m_factory);
                                        ui.testTableWidget->setItemDelegate(preciseDoubleDelegate);
                                        

                                        If you want to know what is happening here is the long story:

                                        • QTableWidget uses the default QStyledItemDelegate
                                        • QStyledItemDelegate, when you try to edit a value, will call the editor from the default QItemEditorFactory
                                        • QItemEditorFactory if the value you are editing is a double will create a default QDoubleSpinBox
                                        • QDoubleSpinBox has 2 decimals by default
                                        • When editing is finished the QDoubleSpinBox::value is used to determine the new value that goes into the model and, as stated in QDoubleSpinBox documentation, it will round the returned value to the set number of decimals. Here is when you have a problem
                                        • The delegate will then convert the double in the model to string
                                        T Offline
                                        T Offline
                                        Teddy van Jerry
                                        wrote on last edited by
                                        #19

                                        It turns out to be a very good method which I seeks for a really long time. But now I use Qt 6.0.0, so the last return statement does not work well. So it needs to be changed into:

                                        return QItemEditorFactory::createEditor(userType, parent);
                                        

                                        And it is done!

                                        1 Reply Last reply
                                        1

                                        • Login

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