PDA

View Full Version : store duplicate QStandardItem in model



qsurvae
5th July 2015, 10:46
Is it possible to store a duplicate of a QStandardItem in a QStandardItem model so that when the data of one item is changed the data of the other item or items also changes? (I am not talking about multiple view windows).

If not, what is the best way to store an index (QPersistantModelIndex?) so that I can write my own script to update a QStandardItem on change event using the signal itemChanged (I guess?).

Would I store this index in a column of the model, or would I use a container?

Do I need to store it at all?

cheers




QStandardItemModel

A
|_1(0)(1)(2) <--
|_2(0)(1)(2)

B
|_3(0)(1)(2)
|_4(0)(1)(2)

C
|_1(0)(1)(2) <-- C1(0) or (1) or (2) needs to automatically update when A1(0) or (1) or (2) is changed.
|_5(0)(1)(2)
...

wysota
5th July 2015, 11:07
To do what you want it is best to implement a custom model.

In your case I think it is easiest to subclass QStandardItemModel and reimplement setData(). In this method after calling the base class implementation update items related to the one being changed. You can store the dependent item pointers using custom item roles or by subclassing QStandardItem and providing API to set and query the relationship (which allows you to update them when items get destroyed).

The most correct way (as opposed to the easiest one) is to implement a totally custom model derived from QAbstractItemModel which will embed this whole functionality in its own code.

qsurvae
5th July 2015, 12:59
I am currently using a QItemDelegate using setModelData(). When I create a new row I create a QList of existing items using findItems(). So it is possible to set the duplicate data for a new row where newLineNumber == oldLineNumber.

I think I will just write a loop which will update the entire model using the same method.

This is my third week using Qt so I wouldn't have a clue how to implement a custom model.

But I am interested in item roles, and custom flags. I already have a script which tests Qt::ItemIsEditable and I would like to add another custom flag to this test.

I have attempted to implement the example in my subclassed QStandardItemModel header file.




class myStandardItemModel : public QStandardItemModel
{
Q_OBJECT
public:
.....
enum Option {
NoOptions = 0x0,
myFlag1 = 0x1,
myFlag2 = 0x2,
//SqueezeBlank = 0x4
};
Q_DECLARE_FLAGS(Options, Option)
...
};

Q_DECLARE_OPERATORS_FOR_FLAGS(myStandardItemModel: :Options)



How do I set the flag?


item->setFlags(myStandardItemModel::myFlag2);

Throws a "no matching function call" error.

cheers


C:\dev\standardItemModel\lineeditdelegate.cpp:274: error: no matching function for call to 'QStandardItem::setFlags(myStandardItemModel::Opti on)'
item->setFlags(myStandardItemModel::myFlag2);
^

qsurvae
5th July 2015, 23:37
excuse my terminology if it's not 100% spot on

well actually i have already implemented qflags in my qstandarditemmodel subclass.

Can I just add a custom flag to the Qt::ItemFlags so that it is testable in the existing myStandarditemModel::flags function? That's what I need.



class myStandardItemModel : public QStandardItemModel
{
Q_OBJECT
public:
myStandardItemModel(int rows, int columns, QObject *parent = 0);

~myStandardItemModel();

Qt::ItemFlags flags ( const QModelIndex &index ) const;

....

wysota
6th July 2015, 00:23
I am currently using a QItemDelegate using setModelData(). When I create a new row I create a QList of existing items using findItems(). So it is possible to set the duplicate data for a new row where newLineNumber == oldLineNumber.
What if a row in the model gets deleted? What if that row is referred to in some other item?






class myStandardItemModel : public QStandardItemModel
{
Q_OBJECT
public:
.....
enum Option {
NoOptions = 0x0,
myFlag1 = 0x1,
myFlag2 = 0x2,
//SqueezeBlank = 0x4
};
Q_DECLARE_FLAGS(Options, Option)
...
};

Q_DECLARE_OPERATORS_FOR_FLAGS(myStandardItemModel: :Options)



How do I set the flag?
Eeemm... I don't understand what you want the flag to do and where you want to set it.



item->setFlags(myStandardItemModel::myFlag2);
No, that wouldn't make any sense :)

I meant something along the lines of:


class MyItem : public QStandardItem {
public:
using QStandardItem::QStandardItem; // C++11 (inherited constructor) but you get the picture...

~Myitem() { foreach(QStandardItem *item, relatedToItems()) item->removeRelation(this); }

void addItemRelation(QStandardItem *item) {
m_relatedItems << item;
item->m_relatedToItems << this;
}
void removeRelation(QStandardItem *item) {
m_relatedItems.remove(item);
item->m_relatedToItems.remove(this);
}
const QSet<QStandardItem*> relatedItems() const { return m_relatedItems; }
const QSet<QStandardItem*> relatedToItems() const { return m_relatedToItems; }

private:
QSet<QStandardItem*> m_relatedItems;
QSet<QStandardItem*> m_relatedToItems;
};


class ItemModel : public QStandardItemModel {
// ...
public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) {
if(!QStandardItem::setData(index, value, role)) return false; // do standard stuff

MyItem *thisItem = static_cast<MyItem*>(itemFromIndex(index);
QSet<QStandardItem*> items = thisItem->relatedItems();
foreach(QStandardItem *item) {
MyItem *myItem = static_cast<MyItem*>(item);
myItem->doCustomStuffWith(thisItem);
}
return true;
}
// ...
};

qsurvae
6th July 2015, 06:25
What if a row in the model gets deleted? What if that row is referred to in some other item?

That doesn't matter as I have simply copied the data of the previous row into the new row now.




Eeemm... I don't understand what you want the flag to do and where you want to set it.


yes I'm pretty sure I do not understand how flags work. What I want is just a simple attribute I can set on an item so that I can use a logic to perform an action or not. That is what I have been using the Qt flags for thus far.

Thanks for your help I will look at your code.

wysota
6th July 2015, 06:59
If you just want a true/false value, then the simplest is to do:


item->setData(true, Qt::UserRole+1);
and

item->data(Qt::UserRole+1).toBool();

But I don't know how you are going to determine which other item to update just by using a boolean flag.

qsurvae
6th July 2015, 12:50
I'll have a play with it, thanks.