Unsolved Change color of a row of a QSqlQueryModel (QTableView)?
-
@c64zottel said in Change color of a row of a QSqlQueryModel (QTableView)?:
@Panoss That was exactly how it works in my application.
Maybe you could post the code from your setData function?
And I will 'translate' it in python. -
@Panoss I don't have a setData function. The code I use for reset is:
void BattlefieldModel::refresh( const QSet< LinearCoordinate > & indices ) { for( int lc : indices ) { QModelIndex a = index( lc ); emit dataChanged( a, a ); } }
But this is only ok because, ... well lets not get into it.
The arguments of index ( row, column) is just the position you want to update. Since I have just rows, I update just rows.
-
First of all, let me start by saying that using a
QStandardItemModel
filled manually from aQSqlQuery
is probably the fastest way to go.having said that you can use this proxy model to make it work:
Sorry for C++
#include <QIdentityProxyModel> class ExtraRolesProxyModel : public QIdentityProxyModel { Q_OBJECT Q_DISABLE_COPY(ExtraRolesProxyModel) public: explicit ExtraRolesProxyModel(QObject* parent=Q_NULLPTR) :QIdentityProxyModel(parent) {} virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE{ const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column()); auto tableIter = m_extraRoles.constFind(hashKey); if(tableIter==m_extraRoles.constEnd()) return QIdentityProxyModel::data(index,role); auto roleIter = tableIter.value().constFind(role); if(roleIter==tableIter.value().constEnd()) return QIdentityProxyModel::data(index,role); return roleIter.value(); } virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE { if(!index.isValid()) return false; Q_ASSERT(index.model()==this); const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column()); if(value.isValid()){ m_extraRoles[hashKey][role] = value; emit dataChanged(index,index,QVector<int>(1,role)); return true; } auto tableIter = m_extraRoles.find(hashKey); if(tableIter==m_extraRoles.end()) return false; auto roleIter = tableIter.value().find(role); if(roleIter==tableIter.value().end()) return false; tableIter.value().erase(roleIter); if(tableIter.value().isEmpty()) m_extraRoles.erase(tableIter); emit dataChanged(index,index,QVector<int>(1,role)); return true; } private: QHash<qint64,QHash<qint32,QVariant> > m_extraRoles; };
-
How can this line be explained in plain english?
const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column());
If index.row() is smaller than 32 thne hashkey = index.row().
Else hashkey = index.column()? -
@Panoss That row means: prepare an integer with 64 bits, the 32 leftmost bits will contain the row, the 32 rightmost the column. The bitshift operator is the same even in python https://wiki.python.org/moin/BitwiseOperators
-
I translated it likes this: (I get no error on this line, seems ok)
hashKey = index.row() << 32 | index.column()
But this one;
auto tableIter = m_extraRoles.constFind(hashKey);
Converted to python:
tableIter = m_extraRoles.constFind(hashKey)
Says variable m_extraRoles 'Unresolved reference'. It has not been declared anywhere.
-
shouldn't it be
this.m_extraRoles.constFind(hashKey)
? -
Yes, you 're right VRonin:
tableIter = self.m_extraRoles.constFind(hashKey)
This shows no underlined code in Pychrm (if there were any errors, it would be underlined. With red color.)
But this look very hard to convert to python:
Q_ASSERT(index.model()==this)
Q_ASSERT?? omg
-
You can actually remove that line altogether, it's just a check that is done only in debug mode
-
Only one (!!) line is left:
emit dataChanged(index,index,QVector<int>(1,role));
Translated to:
self.dataChanged.emit(index,index,QVector(int((1,role)))
But there is no QVector in Python.
(I mean it doesn't exist in any library like PyQt4.QtCore) -
Leave it with just
self.dataChanged.emit(index,index)
then. the last one is an optional parameter and even Qt's native models don't use it -
I set for source of the proxy model (ExtraRolesProxyModel) a QSqlQueryModel.
But I get an error:
'tableIter = self.m_extraRoles.constFind(hashKey)
AttributeError: 'ExtraRolesProxyModel' object has no attribute 'm_extraRoles' -
And this is the whole code (of the class):
class ExtraRolesProxyModel(QIdentityProxyModel ): def __init__(self, dbcursor=None): super(ExtraRolesProxyModel, self).__init__() def data(self, index, role): hashKey = index.row() << 32 | index.column() tableIter = self.m_extraRoles.constFind(hashKey) if tableIter==self.m_extraRoles.constEnd: return QtSql.QSqlQueryModel.data(index,role); roleIter = tableIter.value().constFind(role) if roleIter==tableIter.value().constEnd(): return QtSql.QSqlQueryModel.data(index,role); return roleIter.value() def setData(self, index, value, role=None): if not index.isValid(): return False hashKey = index.row() << 32 | index.column() if value: self.m_extraRoles[hashKey][role] = value self.dataChanged.emit(index,index) return True; tableIter = self.m_extraRoles.find(hashKey) if tableIter== self.m_extraRoles.end(): return False roleIter = tableIter.value().find(role) if roleIter==tableIter.value().end(): return False tableIter.value().erase(roleIter) if tableIter.value().isEmpty(): self.m_extraRoles.erase(tableIter) self.dataChanged.emit(index, index) return True
-
@Panoss said in Change color of a row of a QSqlQueryModel (QTableView)?:
AttributeError: 'ExtraRolesProxyModel' object has no attribute 'm_extraRoles'
You have to declare it in the
__init__
method (not sure how you deal with templates in python though)
@Panoss said in Change color of a row of a QSqlQueryModel (QTableView)?:
if tableIter==self.m_extraRoles.constEnd:
Missing ()
if value:
Does it work?
-
I made the suggested corrections:
if tableIter==self.m_extraRoles.constEnd():
And:
if value.isValid():
But I don't knw how to declare the m_extraRoles, so I declared it as list, which obviously, is incorrect.
class ExtraRolesProxyModel(QIdentityProxyModel ): def __init__(self, dbcursor=None): super(ExtraRolesProxyModel, self).__init__() self.m_extraRoles = []
(the '= []' means 'define it as list' )
-
you probably have to use a dict. Let's try this:
I do not know python so consider this just a guideline
class ExtraRolesProxyModel(QIdentityProxyModel ): def __init__(self, dbcursor=None): super(ExtraRolesProxyModel, self).__init__() self.m_extraRoles=dict() def data(self, index, role): hashKey = QByteArray() keyStream = QDataStream(hashKey,QIODevice::WriteOnly) keyStream.writeInt32(index.row()) keyStream.writeInt32(index.column()) keyStream.writeInt32(role) if self.m_extraRoles.has_key(hashKey): return self.m_extraRoles[hashKey] return QtSql.QSqlQueryModel.data(index,role) def setData(self, index, value, role=None): if not index.isValid(): return False hashKey = QByteArray() keyStream = QDataStream(hashKey,QIODevice::WriteOnly) keyStream.writeInt32(index.row()) keyStream.writeInt32(index.column()) keyStream.writeInt32(role) if value.isValid(): self.m_extraRoles[hashKey]=value self.dataChanged.emit(index,index) return True if self.m_extraRoles.has_key(hashKey): del self.m_extraRoles[hashKey] self.dataChanged.emit(index,index) return True return False
-
if self.m_extraRoles.has_key(hashKey):
AttributeError: 'dict' object has no attribute 'has_key'
But I see that dict does have an attributte named 'has_key'.
EDIT: in fact, it's been removed since python 3.
So I replaced:if self.m_extraRoles.has_key(hashKey):
with:
if hashKey not in self.m_extraRoles:
But now I get another error:
return self.m_extraRoles[hashKey]
KeyError: PyQt4.QtCore.QByteArray(b'\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x08')KeyError? What is this now?
EDIT:
I think hashKey has to be converted from QString to string.
I tried this:hashKey = unicode([PyQt4.QtCore.QString(u'hashKey')])
But this line returns me an error:
AttributeError: 'module' object has no attribute 'QString'