QTableWidgetItem, emit signal when cell text changed.



  • 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?



  • 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



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



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

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



  • This post is deleted!


  • 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 ?



  • @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



  • 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...



  • @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


Log in to reply
 

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