QTableView + QStandardItemModel + custom delegate = strange behaviour
-
Good evening.
I am in the need of making small and task oriented audio player.Usually I would not fuss around and make it using QTableView and QSqlTableModel however user convenience would suffer due to selection being lost on every "select" call. So I decided to use QStandardItemModel (please note - this is the first time I am using this class and since approach I use was always working with Sql models - I assume I do something not quite right).
All is nice and well but I came to the moment where selector for the track being currently played (QPixmap in column 0) is misbehaving.I have a model with 10 columns. The model is populated and managed just fine. For column zero I use
>
character to indicate where the icon should be. That I am doing with a delegate. The methods that set and clear the character are working fine but I will post them for context:To set the currently played track:
QStandardItemModel *model = //here we get the model pointer, it is correct for (auto x=0;x<model->rowCount();++x) { if (model->data(model->index(x,9)).toString()==item) { //column 9 is where the file path is, item is path to currently played file model->setItem(x,0,new QStandardItem(">")); qDebug() << "set" << x; //all is well according to the debug break; } }
To clear any indicator of the track being played:
QStandardItemModel *model = //as above, here we get the model pointer for (auto x=0;x<model->rowCount();++x) { //since the playlists rarely have more than 100 items I allow for iterating over if (!model->data(model->index(x,0)).toString().isEmpty()) { model->setItem(x,0,new QStandardItem()); qDebug() << "cleared" << x; //according to the debug output that works fine break; } }
Now, the dubious part - custom delegate of QStyledItemDelegate. For simple pixmap render only paint() is needed - am I right?
void PDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; initStyleOption(&opt,index); if (index.data(Qt::DisplayRole).toString()==">") { painter->save(); QPixmap px(":/img/play-7-512.png"); painter->drawPixmap(QPoint(opt.rect.width()/2,opt.rect.height()/3),px.scaled(opt.rect.width(),opt.rect.height()/2,Qt::KeepAspectRatio,Qt::SmoothTransformation)); painter->restore(); } else { QStyledItemDelegate::paint(painter, option, index); } }
Now it works well and paints what's needed if I play row 0 of the model.
For other rows, the pixmap is also displayed in the row 0 - HOWEVER if I play for example row 11 and start scrolling, the icon will remain in row 0 until the row 11 is out of view. So I am doing something silly here, right?As for the stack - Qt 6.2.2, macOS.
Thanks in advance,
Artur -
Hi,
From far old memories, I remember there was a need to calculate the position of the rectangle. Did you check that ?
-
@SGaist You are, as usual, right and I am the absolute moron :D
I forgot to take into the account starting point of the cell in paint... Too much time has passed since I had to write the delegate it seems.
The solution of the problem was correcting thedrawPixamp
starting point (add opt.rec.x() and opt.rect.y() respectively):painter-drawPixmap(QPoint(opt.rect.x()+opt.rect.width()/2,opt.rect.y()+opt.rect.height()/3),px.scaled(opt.rect.width(),opt.rect.height()/2,Qt::KeepAspectRatio,Qt::SmoothTransformation));
Thank you for this quick reminder!
Cheers,
A.