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. QTableWidgetItem, emit signal when cell text changed.

QTableWidgetItem, emit signal when cell text changed.

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 3 Posters 8.5k Views 1 Watching
  • 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.
  • P Offline
    P Offline
    Patou355
    wrote on last edited by
    #1

    I need to emit a signal when the text of a cell is changed through a double click but not when the format of the cell is changed.

    The problem is that the cellChanged signal is emitted when the font or the background color is changed, what I don't want.

    Do I need to subclass QTableWidget and create a custom signal?

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

      Create an enum, a signal and a slot:

      private:
      enum {CompareRole= Qt::UserRole + 1025};
      signals:
      void cellTextChanged(const QModelIndex& index);
      private slots:
      void cellChanged(const QModelIndex& index){
      if(index.data(Qt::EditRole) == index.data(CompareRole))
      return;
      tableWidget->model()->setData(index,index.data(Qt::EditRole),CompareRole);
      emit cellTextChanged(index);
      }
      

      now connect(tableWidget->model(),SIGNAL(dataChanged(QModelIndex)),this,SLOT(cellChanged(QModelIndex)));

      you can either subclass QTableWidgetItem or implement this directly in the user object


      One would expect to be able to use the last argument of QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) but the default Qt models appear to send just the default empty vector so you have to do so some manual work

      "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

      VRoninV 1 Reply Last reply
      2
      • P Offline
        P Offline
        Patou355
        wrote on last edited by
        #3

        @VRonin, thanks for your answer.
        So, I need to subclass QTableWidget. Isn't it?

        1 Reply Last reply
        0
        • VRoninV VRonin

          Create an enum, a signal and a slot:

          private:
          enum {CompareRole= Qt::UserRole + 1025};
          signals:
          void cellTextChanged(const QModelIndex& index);
          private slots:
          void cellChanged(const QModelIndex& index){
          if(index.data(Qt::EditRole) == index.data(CompareRole))
          return;
          tableWidget->model()->setData(index,index.data(Qt::EditRole),CompareRole);
          emit cellTextChanged(index);
          }
          

          now connect(tableWidget->model(),SIGNAL(dataChanged(QModelIndex)),this,SLOT(cellChanged(QModelIndex)));

          you can either subclass QTableWidgetItem or implement this directly in the user object


          One would expect to be able to use the last argument of QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) but the default Qt models appear to send just the default empty vector so you have to do so some manual work

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @VRonin said in QTableWidgetItem, emit signal when cell text changed.:

          you can either subclass QTableWidgetItem or implement this directly in the user object

          "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

          1 Reply Last reply
          0
          • P Offline
            P Offline
            Patou355
            wrote on last edited by
            #5
            This post is deleted!
            1 Reply Last reply
            0
            • P Offline
              P Offline
              Patou355
              wrote on last edited by
              #6

              I'm implementing your solution and trying to make it work.
              I have a little question: what's is the enum for and what's the use of CompareRole= Qt::UserRole + 1025 ?

              VRoninV 1 Reply Last reply
              0
              • P Patou355

                I'm implementing your solution and trying to make it work.
                I have a little question: what's is the enum for and what's the use of CompareRole= Qt::UserRole + 1025 ?

                VRoninV Offline
                VRoninV Offline
                VRonin
                wrote on last edited by VRonin
                #7

                @Patou355 said in QTableWidgetItem, emit signal when cell text changed.:

                what's is the enum for

                Just to declare a compile time constant

                what's the use of CompareRole= Qt::UserRole + 1025

                It's just a random number greater than Qt::UserRole

                The logic here is to store the data in both Qt::EditRole and another role (CompareRole) when dataChanged is emitted you check those two roles. if they are equal it means that something else changed (font, background color, etc.) if they are different you are sure that the Qt::EditRole is the one that changed

                "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

                1 Reply Last reply
                1
                • P Offline
                  P Offline
                  Patou355
                  wrote on last edited by
                  #8

                  I think I understand where's my mistake. I need to use a QTableView + QAbstractItemModel couple instead of a standalone QTableWidget, and your code must be implemented in the model and not in the table...

                  VRoninV 1 Reply Last reply
                  0
                  • P Patou355

                    I think I understand where's my mistake. I need to use a QTableView + QAbstractItemModel couple instead of a standalone QTableWidget, and your code must be implemented in the model and not in the table...

                    VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on last edited by
                    #9

                    @Patou355 said in QTableWidgetItem, emit signal when cell text changed.:

                    I need to use a QTableView + QAbstractItemModel couple

                    Not necessarily.

                    for example:

                    #include <QWidget>
                    #include <QTableWidget>
                    #include <QVBoxLayout>
                    #include <QPushButton>
                    #include <QLabel>
                    class TestWidget : public QWidget
                    {
                        Q_OBJECT
                        Q_DISABLE_COPY(TestWidget)
                    public:
                    
                        explicit TestWidget(QWidget *parent = Q_NULLPTR)
                            :QWidget(parent)
                            ,m_colorIndex(0)
                        {
                            m_tableWidget=new QTableWidget(this);
                            QVBoxLayout* mainLay=new QVBoxLayout(this);
                            QPushButton* changeColorButton=new QPushButton("Change Color",this);
                            m_lastChangedLabel=new QLabel(this);
                    
                            mainLay->addWidget(m_tableWidget);
                            mainLay->addWidget(changeColorButton);
                            mainLay->addWidget(m_lastChangedLabel);
                    
                    
                            connect(changeColorButton,&QPushButton::clicked,this,&TestWidget::changeColor);
                            connect(m_tableWidget->model(),&QAbstractItemModel::dataChanged,this,&TestWidget::cellChanged);
                            connect(this,&TestWidget::cellTextChanged,this,&TestWidget::setLastChangedLabel);
                    
                            addExampleData();
                            m_lastChangedLabel->clear();
                        }
                    private:
                        enum {CompareRole= Qt::UserRole + 1025};
                    signals:
                        void cellTextChanged(const QModelIndex& index);
                    private slots:
                        void cellChanged(const QModelIndex& index){
                            if(index.data(Qt::EditRole) == index.data(CompareRole))
                                return;
                            m_tableWidget->model()->setData(index,index.data(Qt::EditRole),CompareRole);
                            emit cellTextChanged(index);
                        }
                        void changeColor(){
                            const QColor colors[] = {Qt::blue,Qt::red, Qt::red, Qt::yellow, Qt::green};
                            for(int i=0;i<15;++i){
                                for(int j=0;j<5;++j){
                                    m_tableWidget->model()->setData(m_tableWidget->model()->index(i,j),QBrush(colors[m_colorIndex]),Qt::BackgroundRole);
                                }
                            }
                            if(++m_colorIndex>=std::extent<decltype(colors)>::value)
                                m_colorIndex=0;
                        }
                        void setLastChangedLabel(const QModelIndex& index){
                            m_lastChangedLabel->setText(QStringLiteral("Last changed %1,%2").arg(index.row()).arg(index.column()));
                        }
                    
                    private:
                      QTableWidget *m_tableWidget;
                      int m_colorIndex;
                      QLabel* m_lastChangedLabel;
                      void addExampleData(){
                          m_tableWidget->setRowCount(15);
                          m_tableWidget->setColumnCount(5);
                          for(int i=0;i<15;++i){
                              for(int j=0;j<5;++j){
                                  m_tableWidget->model()->setData(m_tableWidget->model()->index(i,j),QStringLiteral("%1,%2").arg(i).arg(j));
                              }
                          }
                      }
                    };
                    

                    You can change the background color with the button but the label will show the result only if you modify the text of a cell

                    "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

                    1 Reply Last reply
                    2
                    • I Offline
                      I Offline
                      imaqt 0
                      wrote on last edited by imaqt 0
                      #10

                      Hello,
                      I managed to do it using the last argument in

                      QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
                      

                      to fulfill the task. Just wanted to update this in case someone else needs it as it requires less manual work.

                      
                      connect(tableWidget->model(), &QAbstractItemModel::dataChanged, 
                      [this](const QModelIndex& index, const QModelIndex&, const QVector<int>& roles){
                      if (std::find(roles.begin(), roles.end(), Qt::EditRole) == roles.end())//wasn't caused by entering cell
                            return;
                      //rest of code
                      
                      1 Reply Last reply
                      0

                      • Login

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