Hi there,

I'm implementing editing functionality for a column in a QTableView that contains a color setting. The table in question contains a column that displays a color value. It looks as follows:

PenColor before Edit.PNG

This value should be made editable. After searching the internet for possible ways to accomplish that I decided for a solution that uses a QColorDialog. My current implementation looks as follows:

In the constructor of the class that contains the QTableView (ui->graphsTbl) I added a connect statement that activates a slot method editGraphColor(QModelIndex) upon double click on an instance of the color column:

Qt Code:
  1. connect(ui->graphsTbl, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editGraphColor(QModelIndex)));
To copy to clipboard, switch view to plain text mode 

The slot method looks as follows:


Qt Code:
  1. void MainWindow::editGraphColor(QModelIndex modelIx) {
  2. if (modelIx.column() != GraphsTableModel::COLUMNS::PEN_COLOR)
  3. return;
  4. QColor currColor = modelIx.model()->data(modelIx, Qt::BackgroundRole).value<QColor>();
  5. QColor color = QColorDialog::getColor(currColor, this, "Pick a color",
  6. QColorDialog::DontUseNativeDialog);
  7. if (color.isValid() && color != currColor)
  8. ui->graphsTbl->model()->setData(modelIx, color, Qt::BackgroundRole);
  9. }
To copy to clipboard, switch view to plain text mode 

First I filter out a double click on another column than the PEN_COLOR column. Then I retrieve the current color from the target color cell and pass it to the QColorDialog. After execution of the QColorDialog I pass the new color (in case it differs from the previous color) back to the model.

In the table's model class (named GraphsTableModel and inheriting from QAbstractTableModel) I implemented the Qt::BackgroundRole for the "PEN_COLOR" column in the data(...) as well as setData(...) methods:


Qt Code:
  1. QVariant GraphsTableModel::data(const QModelIndex &index, int role) const {
  2. if (!isIndexValid(index))
  3. return QVariant();
  4.  
  5. const Graph &graph(*mGraphs.at(index.row()));
  6. if (role == Qt::DisplayRole) {
  7. switch (index.column()) {
  8. case LEGEND:
  9. return graph.legend();
  10. case PEN_COLOR:
  11. return QString("Double Click to Change");
  12. [...]
  13. default:
  14. return QVariant();
  15. }
  16. } else if (role == Qt::EditRole) {
  17. switch (index.column()) {
  18. case LEGEND:
  19. return graph.legend();
  20. [...]
  21. default:
  22. return QVariant();
  23. }
  24. } else if (role == Qt::BackgroundRole) {
  25. if (index.column() == PEN_COLOR)
  26. return graph.penColor();
  27. else
  28. return QVariant();
  29. } else
  30. return QVariant();
  31. }
  32.  
  33. bool GraphsTableModel::setData(const QModelIndex& index, const QVariant& value, int role) {
  34. if (!isIndexValid(index))
  35. return false;
  36.  
  37. Graph &graph(*mGraphs.at(index.row()));
  38. if (role == Qt::EditRole) {
  39. switch(index.column()) {
  40. case LEGEND:
  41. graph.setLegend(value.toString());
  42. break;
  43. [...]
  44. default:
  45. return false;
  46. }
  47. } else if (role == Qt::BackgroundRole) {
  48. if (index.column() == PEN_COLOR)
  49. graph.setPenColor(value.value<QColor>());
  50. } else
  51. return false;
  52.  
  53. emit dataChanged(index, index);
  54. return true;
  55. }
To copy to clipboard, switch view to plain text mode 

There is some strange behavior with this code:

1. After a double click on a cell in the "Pen Color" column the QColorDialog is shown. After having selected another color and clicked on the "OK" button the QColorDialog vanishes but immediately shows up again. Only after a click on the "OK" button in the reappeared dialog it is closed and does not show up again.

2. The color cell for which I changed the color shows a white background and a text cursor (looks as if it were to store textual data and be in edit mode). After a mouse click on a position outside that cell it shows the new color and no text cursor anymore.

I have no idea what I did wrong. I'd expect that after changing the color using the QColorDialog and having passed the new color value into the model the QTableView would update its display (triggered by the dataChanged(...) signal emitted at the end of the model's setData(...) method.

And I'm a bit confused of the roles concept in Qt. I tried out what happens when I implement the Qt::EditRole for the PEN_COLOR column in the setData(...) method:

Qt Code:
  1. [...]
  2. Graph &graph(*mGraphs.at(index.row()));
  3. if (role == Qt::EditRole) {
  4. switch(index.column()) {
  5. case LEGEND:
  6. graph.setLegend(value.toString());
  7. break;
  8. case PEN_COLOR:
  9. graph.setPenColor(value.value<QColor>());
  10. break;
  11. [...] default:
  12. return false;
  13. }
  14. } else if (role == Qt::BackgroundRole) {
  15. if (index.column() == PEN_COLOR)
  16. graph.setPenColor(value.value<QColor>());
  17. } else
  18. return false;
  19.  
  20. emit dataChanged(index, index);
  21. return true;
  22. }
To copy to clipboard, switch view to plain text mode 

but this did not change the behavior.
Any helful hint on what I'm doing wrong would be highly appreciated.