1

When mouse is over a cell of a table, I need to create an effect for the whole row of that cell. That means I need to access to another index.

In this case I made a for loop, run from the first column to last column of the table and set effect for it. But it does not work. Off course because the command drawText does not have any input parameter as index. How can I set the effect for another index in this case?

Another solution is also welcomed. Thanks!

void TableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  qDebug() << index.row() << index.column();
  TableDataRow::Type type = static_cast<TableDataRow::Type>( index.data( Qt::UserRole ).toInt() );

  QString text = index.data( Qt::DisplayRole ).toString();
  int row = index.row();

  if ( option.state & QStyle::State_MouseOver )
  {
     if ( type == TableDataRow::Type::Data )
     {
        painter->fillRect( QRect( 0, option.rect.topLeft().y(), option.rect.width()*numberOfColumns, option.rect.height() ), QColor( 249, 126, 18 ) );
        for ( int i = 0; i < numberOfColumns; i++ )
        {
           QModelIndex indexOfRow = index.sibling( row, i );
           painter->setPen( Qt::white );
           painter->drawText( option.rect, Qt::AlignVCenter | Qt::TextWordWrap, text );
        }
     }
  }
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
trangan
  • 341
  • 8
  • 22
  • @eyllanesc: numberOfColumns is actually the columnCount of the table. Yeah you are right, I want to use drawText for each indexOfRow but it is impossible until now. – trangan Aug 09 '18 at 06:19

1 Answers1

1

I understand that you want to create the effect of changing the color of the row text if the mouse is on any item in the row, I think that for this it is not necessary to use the delegate, just enable mouseTracking and overwrite the mouseMoveEvent method.

#include <QApplication>
#include <QMouseEvent>
#include <QStandardItemModel>
#include <QTableView>

class TableView: public QTableView{
public:
    TableView(QWidget *parent = nullptr):
        QTableView(parent)
    {
        setMouseTracking(true);
    }
protected:
    void mouseMoveEvent(QMouseEvent *event)
    {
        QModelIndex ix = indexAt(event->pos());
        if(mRow != ix.row()){
            changeRowColor(mRow);
            if(ix.isValid())
                changeRowColor(ix.row(), Qt::green, Qt::blue);
            mRow = ix.row();
        }
        QTableView::mouseMoveEvent(event);
    }

    void leaveEvent(QEvent *event)
    {
        changeRowColor(mRow);
        QTableView::leaveEvent(event);
    }
private:
    void changeRowColor(int row, const QColor & textColor=Qt::black, const QColor &backgroundColor=Qt::white){
        if(!model())
            return;
        for(int i=0; i< model()->columnCount(); i++){
            model()->setData(model()->index(row, i), textColor, Qt::ForegroundRole);
            model()->setData(model()->index(row, i), backgroundColor, Qt::BackgroundRole);
        }
    }
    int mRow = -1;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TableView w;

    QStandardItemModel model(5, 5);
    for(int i=0; i < model.rowCount(); i++){
        for(int j=0; j < model.columnCount(); j++){
            model.setItem(i, j, new QStandardItem(QString("%1-%2").arg(i).arg(j)));
        }
    }
    w.setModel(&model);
    w.show();
    return a.exec();
}

Update:

Since you have created your own model using QAbstractTableModel then you must implement the setData() and data() methods to handle the Qt::ForegroundRole and Qt::BackgroundRole roles.

In my example, each item has the following structure:

struct Item{
    QString text="";
    QBrush textColor=Qt::black;
    QBrush bgColor=Qt::white;
};

Then the model must save the data in a QList<QList<Item>> m_items;, assuming the above the methods should be as follows:

QVariant TableModel::data(const QModelIndex &index, int role) const{
    if (!index.isValid())
        return QVariant();
    const Item & item = m_items[index.row()][index.column()];
    if (role == Qt::DisplayRole)
        return item.text;
    else if (role == Qt::ForegroundRole) {
        return item.textColor;
    }
    else if (role == Qt::BackgroundRole) {
        return item.bgColor;
    }
    else
        return QVariant();
}

bool TableModel::setData(const QModelIndex &index,
                         const QVariant &value, int role)
{
    if (!index.isValid())
        return false;
    Item & item = m_items[index.row()][index.column()];
    if(role == Qt::EditRole || role == Qt::DisplayRole){
        item.text = value.toString();
    }
    else if (role == Qt::ForegroundRole) {
        if(value.canConvert<QBrush>())
            item.textColor = value.value<QBrush>();
    }
    else if (role == Qt::BackgroundRole) {
        if(value.canConvert<QBrush>())
            item.bgColor = value.value<QBrush>();
    }
    else
        return false;
    emit dataChanged(index, index);
    return true;
}

The complete example can be found in the following link

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • oops, thanks for your help. Sorry I miss a big thing in my requirement here. My problem is: when the mouse is over a cell of the table, I need to `change the background of that row AND the color of the text in the whole row`. How can I do it? – trangan Aug 09 '18 at 06:30
  • ok i am reading your solution and trying with it. Let's see how it looks :) Thanks again! – trangan Aug 09 '18 at 06:53
  • Hi, it tooks me a while to try with your solution. It did not work and I found out that setData can not be implemented succesfully because the model I used here is QAbtractTableModel which is not editable model. :((( – trangan Aug 09 '18 at 09:45
  • Yeah, but when i set `bool result = model()->setData(model()->index(row, i), textColor, Qt::ForegroundRole);` then I see in debug `result = false`, which means this command was not set successfully :D – trangan Aug 09 '18 at 09:49
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/177711/discussion-between-htmlamateur-and-eyllanesc). – trangan Aug 09 '18 at 09:50