I have a simple logic, that basically goes like this: a few entries are filtered from source model (my custom QAbstractTableModel) and presented to the user using QSortFilterProxyModel, which does have only modified filterAcceptsRow function. This presentation is done using simple dialog. User selects desired entries from filtered ones and those selected entries from model must be updated (actually two fields have to be modified). So simplified code goes like this:
QModelIndexList selectedRows = myProxyModel->selectionModel()->selectedRows();
for (int i = 0; i < selectedRows.count(); i++) {
myProxyModel->setData(myProxyModel->index(selectedRows.at(i).row(), (int) LoanStatusCol, QModelIndex()), (int) ReturnedLoan, Qt::EditRole);
myProxyModel->setData(myProxyModel->index(selectedRows.at(i).row(), (int) LoanRetEntriesCol, QModelIndex()), (lastEntryNo + 1), Qt::EditRole);
}
However, this does not work. And each time behavour is quite weird. What I noticed is that, when it gets to second selected row in this cycle and when it reaches setData() code in the model:
bool TransactionModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (!index.isValid()) {
return false;
}
it returns invalid index. However, when I swaped these two setData() code lines, one row was updated, but second row was not - due to invalid index. I do not know, whether I explained that correctly, but probably this should be my silly mistake, because I am new at this.
UPDATE:
Since model consists of QList data, where Transaction is a custom class that defines fields of entry, I created a function, that updated underlying entry by column number (so to say...). I use function setValueByColumnNo. I just could not find a better way to do that, when working with lists of custom classes.
bool TransactionModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (!index.isValid()) {
return false;
}
if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
transactionData[index.row()].setValueByColumnNo(index.column(), value);
emit dataChanged(index, index);
return true;
}
return false;
}
Any ideas?
Thanks.
Related
I want to inform the user of the process of filtering points on a QML map by a progress bar. This process takes place in three phases:
filterAcceptsRow call rowCount and then call data. The values returned by data are compared with the filter and validate or not.
here is the filterAcceptsRow() :
bool NavaidsFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if(!m_boundaryZone.isValid()){
return false;
}
QModelIndex ix = sourceModel()->index(sourceRow, 0, sourceParent);
QGeoCoordinate pos = ix.data(NavaidsModel::PositionRole).value<QGeoCoordinate>();
return m_boundaryZone.contains(pos);
}
Here is the rowCount() :
Q_INVOKABLE int rowCount(const QModelIndex & parent = QModelIndex()) const{
Q_UNUSED(parent)
return mPoints.count();
}
And here is the data(), with a faulty QProgressDialog implemented :
QVariant data(const QModelIndex & index, int role=Qt::DisplayRole) const {
QProgressDialog filterDialog;
filterDialog.setMinimum(0);
filterDialog.setMaximum(mPoints.count());
filterDialog.show();
filterDialog.setValue(index.row());
const NavaidsPoint &point = mPoints[index.row()];
if (role == PositionRole){
return QVariant::fromValue(point.position());}
else if (role == OACICodeRole){
return point.oaciCode();}
else if (role == CountryCodeRole){
return point.countryCode();}
return QVariant();
}
Data seems to me the good part of the code in which we know the index of the current value via index.row() and the total of values via rowCount().
Knowing the progress by comparing the two numbers is obvious, but displaying it in a progress bar does not work as I coded it.
I tried to implement a QFutureWatcher to do this job, but unsuccessfully.
Do you have an idea about the solution to implement.
Thanks in advance
If you want to monitor the progress, you have to implement an async worker. It has to complete one step, pause, notify the GUI, give it time to reflect the change, and only then do the next step, and so until finished.
If you do it in a tight loop, this will absolutely massacre your performance, so you have to take care that it is not too finely grained. Something like a progress bar should not get more than 10 updates a second.
The reason it doesn't work for you is that the tread is blocked while the work is being done, so the progress bar cannot update until it all the work is finished.
I have spent the last week struggling to create a QModelIndex given a row and a column.
Alternatively, I would settle for changing the value of row() in an already existing QModelIndex.
Any help would be appreciated.
Edit:
QModelIndex nIndex = QAbstractItemModel::createIndex(1, 2);
int b = nIndex.row();
qInfo() << "b" << b;
Fails with error:
cannot call member function ‘QModelIndex QAbstractItemModel::createIndex(int, int, void*) const’ without object
QModelIndex nIndex = QAbstractItemModel::createIndex(1, 2);
^
The goal at hand is this:
I have a function:
void MyClass::doStuff(QModelIndex index)
Inside that class, I essentially do the following:
if (index.column() != 1)
{
int a=index.row();
}
So my goal is to call that function from a different class and pass it a QModelIndex, but for that index to have been created with a row/column I specify.
I'm not sure this is what you want, but you can just create a QModelIndex with the method QAbstractItemModel::index(row, column) ( http://doc.qt.io/qt-5/qabstractitemmodel.html#index )!? On the other hand that seems to be to simple for you to struggle with it for so long, maybe explain a little bit more.
Example:
QAbstractTableModel *model = ...;
// then you can do something like
QModelIndex nIndex = model->index(1,2);
int b = nIndex.row();
qInfo() << "b" << b;
You can get a new index from the appropriate model, using its index() method.
If you already have an index from the model, with the same parent as your desired index, then you can get another index using the sibling() method of that index:
void MyClass::doStuff(const QModelIndex& index)
{
// get the value at row zero, same column
const QModelIndex header = index.sibling(0, index.column());
}
The index itself is immutable once created - you can't change its row, column or parent (other than by invalidating it with changes to the model behind its back).
I want to create same kind of QTreeView (not QTreeWidget) structure as shown in attached figure.. This is Property Editor of QT.
I am using QT-4.6
On 2nd column, depending on different condition, I can have either a spin box, or a drop down or a checkbox or text edit... and so on...
Please guide me on how to set different delegates in different cells of a particular column.
From docs, it is evident that there is no straight away API for setting delegate on a cell (rather is available for full widget or a row or a column).
All QAbstractItemDelegate methods, like createEditor or paint, have a model index as one of their parameters. You can access model data using that index and create an appropriate delegate widget. When you create your model you should set some value to every item that will be used to distinguish its type.
An example:
enum DelegateType
{
DT_Text,
DT_Checkbox,
DT_Combo
}
const int MyTypeRole = Qt::UserRole + 1;
QStandardItemModel* createModel()
{
QStandardItemModel *model = new QStandardItemModel;
QStandardItem *item = new QStandardItem;
item->setText("Hello!");
item->setData(DT_Checkbox, MyTypeRole);
model->appendRow(item);
return model;
}
QWidget* MyDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
int type = index.data(MyTypeRole).toInt();
// this is a simplified example
switch (type)
{
case DT_Text:
return new QLinedEdit;
case DT_Checkbox:
return new QCheckBox;
case DT_Combo:
return new QComboBox;
default:
return QItemDelegate::createEditor(parent, option, index);
}
}
#hank This is in response to your last comment... Do you see any flaw in it ?
MyItem* item2 = new MyItem(second);
item2->setData(delType, **MyTypeRole**);
if(delType == DT_Combo)
{
QString str1, str2, str3;
QStringList abc ;
abc << ("1" + str1.setNum(counter) ) << ("2" + str2.setNum(counter) )<< ( "3" + str3.setNum(counter) );
item2->setData(abc, MyTypeRole1);
}
QWidget* MyDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
int type = index.data(MyTypeRole).toInt();
// this is a simplified example
switch (type)
{
case DT_Text:
return new QLinedEdit;
case DT_Combo:
{
QComboBox* cb = new QComboBox(parent);
QStringList entries - index.data(MyTypeRole1).toStringList();
cb->addItems(entries)
return cb;
}
On different item2, I dynamically create entries with a counter variable that is different everytime it comes here...
Here, different combo boxes display different entries.
Does the approach looks fine to you ?
How can I hide / exclude entire rows from a QStandardItemModel without removing them physically from the model?
Rational: I want to not display entities which are shown in another view. I already have a working highlight logic for that in the data function. Could I turn it(easily) in a "not display logic", so such rows are skipped?
QVariant CMyModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::BackgroundRole) { return CModelBase::data(index, role); }
.......
if (model.hasSomeCondition())
{
static const QBrush b(Qt::green);
return b;
}
return QVariant();
}
I am using QFileSystemModel to represent file structure through the QTreView. Everything works fine, but I need to add an additional row at some level of the tree. For example for now is:
-root
--row1
--row2
--row3
All these rows mapping folders/files from file system.
I need:
-root
--row1
--row2
--row3
--custom row
So custom row is not representing any data from file system. I just need to add here my own data.
I have read a lot of stuff from the internet and people advice to use proxy model and reimplement rowCount(), data() and flags() functions. I tried to do that(used class derived from QSortFilterProxyModel), but I never get my row in data() and flags() functions. Seems like it takes count from source model.
QVariant AddonFilterModel::data (const QModelIndex & index, int role) const
{
if(role == Qt::DisplayRole && index.row() == FilterModel::rowCount(index))
{
return QString("Add-Ons");
}
return FilterModel::data(index, role);
}
Qt::ItemFlags AddonFilterModel::flags(const QModelIndex & index) const
{
if (!index.isValid())
return 0;
if (index.row() == FilterModel::rowCount(index))
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
return FilterModel::flags(index);
}
int AddonFilterModel::rowCount(const QModelIndex &parent) const
{
int count = FilterModel::rowCount(parent);
if(parent == this->getRootIndex())
{
return count+1;
}
return count;
}
Using class derived from QAbstractProxyModel is not acceptable because I need filtering functions of QSortFilterProxyModel().
Also I have tried to reimplement rowCount() of QFileSystemModel to make changes directly in model but I am getting "array out of range" error from QT code.
I have tried insertRow() method but it is not working. I think because QFileSystemModel is read only.
Did anyone face this problem? Any ideas?
Late answer. You have to subclass Qabstractitemmodel.