QFileSystemModel set item color issue
-
Hi! I want to set the item color or disable item when I cut it from
QListView
.QListView
usesQFileSystemModel
model. For example:ui->listView->model()->setData(ui->listView->currentIndex(), QBrush(Qt::gray), Qt::BackgroundRole);
But this code does not set the gray color as background. Any ideas? Thanks.
-
QAbstractItemView::setData() returns a boolean to indicate if the value was really set. Since you're using a plain QFileSystemModel I doubt it somehow implemented something in the setData() function for the BackgroundRole.
Therefore you have to derive from QFileSystemModel and implement it on your own. -
QAbstractItemView::setData() returns a boolean to indicate if the value was really set. Since you're using a plain QFileSystemModel I doubt it somehow implemented something in the setData() function for the BackgroundRole.
Therefore you have to derive from QFileSystemModel and implement it on your own.Ok. I tried it and it returns false.
bool res = ui->listView->model()->setData(ui->listView->currentIndex(), QBrush(Qt::gray), Qt::BackgroundRole); qDebug() << res;
So, no chance to set the item color by
QFileSystemModel
default behavior/methods? Should I really reimplementQFileSystemModel
model? -
@Cobra91151 said in QFileSystemModel set item color issue:
I tried it and it returns false.
The code I posted the link to shows that QFileSystemModel does not handle Qt::BackgroundRole so anything other than false would be a surprise here.
Should I really reimplement QFileSystemModel model?
No, you should derive from it
-
@Cobra91151 said in QFileSystemModel set item color issue:
I tried it and it returns false.
The code I posted the link to shows that QFileSystemModel does not handle Qt::BackgroundRole so anything other than false would be a surprise here.
Should I really reimplement QFileSystemModel model?
No, you should derive from it
Ok, by derive you mean to inherit
QFileSystemModel
class and reimplement thesetData
method to accept other roles? Because from this code it only acceptsEditRole
.... if (!idx.isValid() || idx.column() != 0 || role != Qt::EditRole || (flags(idx) & Qt::ItemIsEditable) == 0) { return false; }
-
Ok, by derive you mean to inherit
QFileSystemModel
class and reimplement thesetData
method to accept other roles? Because from this code it only acceptsEditRole
.... if (!idx.isValid() || idx.column() != 0 || role != Qt::EditRole || (flags(idx) & Qt::ItemIsEditable) == 0) { return false; }
@Cobra91151
Yes that is exactly what @Christian-Ehrlicher means! Sub-class, overridesetData()
, implement your own logic forQt::BackgroundRole
role, else call the base implementation. -
@Cobra91151
Yes that is exactly what @Christian-Ehrlicher means! Sub-class, overridesetData()
, implement your own logic forQt::BackgroundRole
role, else call the base implementation.Ok. I will try it. Thanks.
-
@Cobra91151
Yes that is exactly what @Christian-Ehrlicher means! Sub-class, overridesetData()
, implement your own logic forQt::BackgroundRole
role, else call the base implementation.Ok. I have tried it, but still it does not change the item background color.
Code:
bool TestModel::setData(const QModelIndex &index, const QVariant &varData, int role) { QStandardItem item(index.row(), index.column()); if (role == Qt::BackgroundRole) { QBrush brush = varData.value<QBrush>(); item.setBackground(brush); qDebug() << "setBackground"; } return QFileSystemModel::setData(index, varData, role); }
-
What should work here? You're creating a local QStandardItem, setting the background color and then it gets destroyed. How should work this at all? How should data() magically return the correct Background role with your code?
-
What should work here? You're creating a local QStandardItem, setting the background color and then it gets destroyed. How should work this at all? How should data() magically return the correct Background role with your code?
So, I changed code to:
bool TestModel::setData(const QModelIndex &index, const QVariant &varData, int role) { QStandardItem *item = new QStandardItem(index.row(), index.column()); if (role == Qt::BackgroundRole) { QBrush brush = varData.value<QBrush>(); item->setBackground(brush); qDebug() << "setBackground"; return item->data(Qt::BackgroundRole).toBool(); } return QFileSystemModel::setData(index, varData, role); }
But the issue still exists. What logic should I implement then? Thanks.
-
You really should take a look at how the ItemModels work... https://doc.qt.io/qt-5/model-view-programming.html
You set data with setData() and you return data with data() - so where did you implement your data() function? What should the (now leaking) item do at all? -
You really should take a look at how the ItemModels work... https://doc.qt.io/qt-5/model-view-programming.html
You set data with setData() and you return data with data() - so where did you implement your data() function? What should the (now leaking) item do at all?Good. I will check it. Thanks.
-
@Cobra91151
So I understand: the user clicks "cut" on yourQListView
, and you want to change item color displayed while it's cut? And you propose to do that via theQFileSystemModel
'ssetData(Qt::BackgroundRole)
? So you're going to store (at least conceptually) an "is this item presently cut" against each item?@Christian-Ehrlicher
Given the code shown forQFileSystemModel::setData()
rejects attempts to setQt::BackgroundRole
, are you going to/can you useQAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
to specify a value for roleQt::BackgroundRole
to "force" theQt::BackgroundRole
into the data, ready to picked up bydata(Qt::BackgroundRole)
? Or does that actually callsetData()
?! In which case, where will you store the "cut" data so thatdata()
retrieves it?A possible alternative approach, avoiding any
setData()
overriding: don't store "cut" status against each item. Just keep a variable for what item(s) is cut. (You could possibly just use the selection model for that, indicating whether it's a "cut" vs a "copy"; then when the selection goes away it's automatically no longer in "cut" state?) Override onlydata()
: when role isQt::BackgroundRole
look up theQModelIndex
in your variable/list of "cut" ones and returnQBrush(Qt::gray)
if there. Comment? -
@Cobra91151
So I understand: the user clicks "cut" on yourQListView
, and you want to change item color displayed while it's cut? And you propose to do that via theQFileSystemModel
'ssetData(Qt::BackgroundRole)
? So you're going to store (at least conceptually) an "is this item presently cut" against each item?@Christian-Ehrlicher
Given the code shown forQFileSystemModel::setData()
rejects attempts to setQt::BackgroundRole
, are you going to/can you useQAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
to specify a value for roleQt::BackgroundRole
to "force" theQt::BackgroundRole
into the data, ready to picked up bydata(Qt::BackgroundRole)
? Or does that actually callsetData()
?! In which case, where will you store the "cut" data so thatdata()
retrieves it?A possible alternative approach, avoiding any
setData()
overriding: don't store "cut" status against each item. Just keep a variable for what item(s) is cut. (You could possibly just use the selection model for that, indicating whether it's a "cut" vs a "copy"; then when the selection goes away it's automatically no longer in "cut" state?) Override onlydata()
: when role isQt::BackgroundRole
look up theQModelIndex
in your variable/list of "cut" ones and returnQBrush(Qt::gray)
if there. Comment?I have cut option via context menu. It works using
QClipboard
and works well. The reason I want to change color of the item is to notify user that such item has been cut. So, basically it is only the style, hence I can do aQMessageBox
orQLabel
to notify. I am still figuring out what should I reimplement to just set the item color. -
I have cut option via context menu. It works using
QClipboard
and works well. The reason I want to change color of the item is to notify user that such item has been cut. So, basically it is only the style, hence I can do aQMessageBox
orQLabel
to notify. I am still figuring out what should I reimplement to just set the item color.-
Override
data()
to unconditionally returnQBrush(Qt::gray)
when role isQt::BackgroundRole
. Check the principle works, and visuals look OK. -
Override
setData()
to store the index (QModelindex
) in some container when you want to mark the item as being "cut". -
Alter the
data()
override code to check whether the index is marked in the "cut" container, and only returnQBrush(Qt::gray)
forQt::BackgroundRole
when it is.
Hint: container should be directly accessible by
QModelIndex
for it (#3) to be fast. -
-
-
Override
data()
to unconditionally returnQBrush(Qt::gray)
when role isQt::BackgroundRole
. Check the principle works, and visuals look OK. -
Override
setData()
to store the index (QModelindex
) in some container when you want to mark the item as being "cut". -
Alter the
data()
override code to check whether the index is marked in the "cut" container, and only returnQBrush(Qt::gray)
forQt::BackgroundRole
when it is.
Hint: container should be directly accessible by
QModelIndex
for it (#3) to be fast.Ok. I figured it out. My code:
TestModel.h
#ifndef TESTMODEL_H #define TESTMODEL_H #include <QObject> #include <QFileSystemModel> #include <QSet> #include <QBrush> class TestModel : public QFileSystemModel { Q_OBJECT public: using QFileSystemModel::QFileSystemModel; QVariant data(const QModelIndex &index, int role) const override; bool setData(const QModelIndex &index, const QVariant &varData, int role) override; private: QSet<QPersistentModelIndex> indexList; }; #endif // TESTMODEL_H
TestModel.cpp
#include "testmodel.h" QVariant TestModel::data(const QModelIndex &index, int role) const { if (role == Qt::BackgroundRole) { return indexList.contains(index) ? QBrush(Qt::gray) : QBrush(Qt::transparent); } return QFileSystemModel::data(index, role); } bool TestModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::BackgroundRole) { if (value == QBrush(Qt::gray)) { indexList.insert(index); } else { indexList.remove(index); } emit dataChanged(index, index, {Qt::BackgroundRole}); return true; } return QFileSystemModel::setData(index, value, role); }
Now it works well. The issue is resolved!
-
-
dataChanged() should pass the modified role -> dataChanged(idx, idx, {Qt::BackgroundRole}) and the two ctors and flags() function is not needed in your class.
In the class definition data() and setData(9 should be marked with 'override' -
dataChanged() should pass the modified role -> dataChanged(idx, idx, {Qt::BackgroundRole}) and the two ctors and flags() function is not needed in your class.
In the class definition data() and setData(9 should be marked with 'override'Ok. I improved
dataChanged
method and markeddata()
andsetData()
withoverride
. Thanks.When I removed constructors I got compiling issues. It is required to have at least one constructor. About
flags
, I think it is also required because I am implementing drag and drop with models and views. -
You don't do anything in your flags() so no need for it
wrt the ctors:
class TestModel : public QFileSystemModel { Q_OBJECT public: using QFileSystemModel::QFileSystemModel; ...
-
You don't do anything in your flags() so no need for it
wrt the ctors:
class TestModel : public QFileSystemModel { Q_OBJECT public: using QFileSystemModel::QFileSystemModel; ...
Good. I changed it. Thanks.