13
void MyWindow::initializeModelBySQL(QSqlQueryModel *model,QTableView *table,QString sql){
        model = new QSqlQueryModel(this);
        model->setQuery(sql);
}

With this method i can set a QSQlQueryModels to my QTableviews.

But How i can set color to a row based on a cell value?

Tineo
  • 519
  • 1
  • 4
  • 19

2 Answers2

30

The view draws the background based on the Qt::BackgroundRole role of the cell which is the QBrush value returned by QAbstractItemModel::data(index, role) for that role.

You can subclass the QSqlQueryModel to redefine data() to return your calculated color, or if you have Qt > 4.8, you can use a QIdentityProxyModel:

class MyModel : public QIdentityProxyModel
{
    QColor calculateColorForRow(int row) const {
        ...
    }

    QVariant data(const QModelIndex &index, int role)
    {
        if (role == Qt::BackgroundRole) {
           int row = index.row();
           QColor color = calculateColorForRow(row);           
           return QBrush(color);
        }
        return QIdentityProxyModel::data(index, role);
    }
};

And use that model in the view, with the sql model set as source with QIdentityProxyModel::setSourceModel.

OR

You can keep the model unchanged and modify the background with a delegate set on the view with QAbstractItemView::setItemDelegate:

class BackgroundColorDelegate : public QStyledItemDelegate {

public:
    BackgroundColorDelegate(QObject *parent = 0)
        : QStyledItemDelegate(parent)
    {
    }
    QColor calculateColorForRow(int row) const;

    void initStyleOption(QStyleOptionViewItem *option,
                         const QModelIndex &index) const
    {
        QStyledItemDelegate::initStyleOption(option, index);

        QStyleOptionViewItemV4 *optionV4 =
                qstyleoption_cast<QStyleOptionViewItemV4*>(option);

        optionV4->backgroundBrush = QBrush(calculateColorForRow(index.row()));
    }
};

As the last method is not always obvious to translate from C++ code, here is the equivalent in python:

def initStyleOption(self, option, index):
    super(BackgroundColorDelegate,self).initStyleOption(option, index)
    option.backgroundBrush = calculateColorForRow(index.row())
alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • 1
    +1 for the reference to the solution with a delegate. I forgot about it. – dschulz Apr 19 '12 at 00:48
  • i need to set a color for each value of a table colmun (SELECT name, status FROM users) in this case "status" Can you edit this code. – Tineo Apr 19 '12 at 02:57
  • optionV4->backgroundBrush = QBrush(calculateColorForRow(index.row())); it generates error – Tineo Apr 19 '12 at 14:27
  • 1
    @Tineo I forgot the calculateColor... function had to be `const`. To get the status from the model, you can use `index->sibling(index->row(), 1 /* the column # for status */)`, so, you might need to pass `const QModelIndex & index` instead of `int row` to the function. – alexisdm Apr 19 '12 at 14:54
  • After changing any cell colors, the cells are not updated / redrawn automatically. An update can be forced by calling `update (index)` on the QTableView, or by emitting or calling `dataChanged (index, index)` from a subclass of QTableView. (Thanks [to](http://www.qtforum.org/article/36026/some-cells-in-qtableview-are-not-repainted-automatically-after-a-clicking-on-a-table-cell.html) ) – gregn3 Jul 12 '16 at 08:47
4

Your best bet is to define a custom model (QAbstractTableModel subclass). You probably want to have a QSqlQueryModel as a member in this custom class.

If it's a read-only model, you need to implement at least these methods:

 int rowCount(const QModelIndex &parent) const;
 int columnCount(const QModelIndex &parent) const;
 QVariant data(const QModelIndex &index, int role) const;

and for well behaved models also

 QVariant headerData(int section, Qt::Orientation orientation, int role) const;

If you need the model to be able to edit/submit data, things get a bit more involved and you will also need to implement these methods:

 Qt::ItemFlags flags(const QModelIndex &index) const;
 bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
 bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex());
 bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex()); 

What will actually change a row appearance lies in the return value of this method:

 QVariant data(const QModelIndex &index, int role) const;

A dumb example:

 QVariant MyCustomModel::data(const QModelIndex &index, int role) const
 {
     if ( !index.isValid() )
         return QVariant();

     int row = index.row();
     int col = index.column();


     switch ( role )
     {

        case Qt::BackgroundRole:
        {
            if(somecondition){
               // background for this row,col is blue
               return QVariant(QBrush (QColor(Qt::blue)));
            }
            // otherwise background is white
            return QVariant(QBrush (QColor(Qt::white)));
        }

        case Qt::DisplayRole:
        {
           // return actual content for row,col here, ie. text, numbers

        }

        case Qt::TextAlignmentRole:
        {

           if (1==col)
              return QVariant ( Qt::AlignVCenter | Qt::AlignLeft );

           if (2==col)
              return QVariant ( Qt::AlignVCenter | Qt::AlignTrailing );

           return QVariant ( Qt::AlignVCenter | Qt::AlignHCenter );

        }
     }

  }
dschulz
  • 4,666
  • 1
  • 31
  • 31