trangan
trangan

Reputation: 361

How to access another index inside paint() function of delegate?

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 );
        }
     }
  }
}

Upvotes: 2

Views: 442

Answers (1)

eyllanesc
eyllanesc

Reputation: 244033

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

Upvotes: 1

Related Questions