Updating model to Dom using Qt? - c++

I'm using model/view of Qt4.8 to developing an application. It can do such things:
load xml and display. XML looks like this:
<Config>
<Symbol>
<Car_symbol>
<SymbolSize>12</SymbolSize>
<SymbolPath>e:/car.jpg</SymbolPath>
</Car_symbol>
<Ship_symbol>
<SymbolSize>10</SymbolSize>
<SymbolPath>e:/ship.jpg</SymbolPath>
</Ship_symbol>
</Symbol>
<Network>
<Server>192.168.0.2</Server>
<Port>5555</Port>
<Local>192.168.0.1</Local>
</Network>
<Mode>
<SingleMode>1</SingleMode>
</Mode>
</Config>
QDomDocument reads xml and set data to model. TreeView set model and Delegate such like this:
class MyModel : public QAbtractItemModel
{
public:
//data();
//flags();
//headerData();
//index();
//parent();
//rowCount();
//columnCount();
void setData(QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
void setupModelData(QDomDocument& doc); //set doc's tag to model's item
private:
TreeItem item;
}
QDomDocument domDoc("xmlDoc"); //global object
QFile file("config.xml");
//...open file correctly
docDoc.setContent(file);
MyModel model;
model.setModelData(docDoc);
QTreeview treeview;
treeview->setModel(&model);
MyDelegate delegate;
treeview->setItemDelegate(&delegate);
Using delegate to edit model's data.
//click on delegate
delegate.setModelData(editor, model, index);
//index got from delegate, value is input value, role is EditRole
model.setData(index, value, role);
//item is a member of model, it saves the value
item.setData(value);
The changed data of model could be restored in XML(or QDomDocument).
And after step 2, the data of model is changed. But how could I changed the data of QDomDocument or updating data to Dom?

Related

Get QTableView cell text after delegate

I change the text of a column of QTableView by using displaytext function in QStyledItemDelegate class.
QString Msg_NameGIdDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
return Diag_Utility::getMsgNameStr(value.toInt());
}
How I can get the text of each cell in this column after delegate. If I use the following code I get the text before delegation.
for(int i=0; i<ui->msgCount_tableView->model()->rowCount();i++)
qDebug()<<ui->msgCount_tableView->model()->index(i,6).data().toString();
Looks like you change delegate text but not change model data and you are fetching model data and you want delegate data.
QAbstractItemDelegate *QAbstractItemView::itemDelegate(const QModelIndex &index) function will return your delegate so you can get displayText.
If this solution doesn't work you change model's data by model()->setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)function instead of delegate's displayText and you can fetch model->data()

How to set a string property to QTreeWidgetItem?

I have a list of application specific items uniquely identified by an id. Their names are displayed in a QTreeWidget (one item corresponds to a single QTreeWidgetItem). I would like to somehow attach the corresponding ids to these QTreeWidgetItems so that upon selection changed I can access the id of the corresponding item and do some processing.
QTreeWidgetItem does not inherit from QObject so I cannot use its setProperty function. How could I do this?
Just create some user defined roles for the properties...
typedef enum {
id_1_role = Qt::UserRole,
id_2_role,
id_N_role,
} property_id_role;
Then you can use the normal means of getting/setting the data associated with a QTreeWidgetItem.
QTreeWidgetItem *item = ...
/*
* Set the property value.
*/
item->setData(column, property_id_role::id_2_role, id_2_value);
/*
* Get the property value.
*/
auto id_2_value = item->data(column, property_id_role::id_2_role).value<id_2_type>();
Do you know that QTreeWidgetItem has a setData method?
setData(int column, int role, const QVariant &value)
You can use it with your roles. For example:
int your_id = 123;
ui->treeWidget->currentItem()->setData(0,Qt::UserRole,your_id);
qDebug() << ui->treeWidget->currentItem()->data(0,Qt::UserRole);

Qt: model/view - defining format of items holding date

I've a model which has items with QDate as Qt::DisplayRole/Qt::EditRole.
It works fine - view renders those items correctly and provides nice date editor. The only drawback is that I'd like to change date format being displayed.
Is there simpler way than preparing delegate with custom painting + QItemEditorFactory + QItemEditorCreatorBase etc?
It looks for me like the triumph of form over content.
If you need just to display a date in specific cell you should subclass QStyledItemDelegate and override it's QString displayText(const QVariant& value, const QLocale& locale) const;
class DateItemDelegate :
public QStyledItemDelegate
{
public:
DateItemDelegate (QObject* parent) :
QStyledItemDelegate(parent) {};
QString displayText(const QVariant& value, const QLocale& locale) const
{
if (value.type() == QVariant::DateTime)
{
return value.toDateTime().toString(Qt::ISODate);
}
}
};
As for me you should use custom painting in case you want to display multiple data in one cell.
Thx for all comments.
Summing up: there is no way to do it without custom delegate

Storing custom objects in QStandardItemModel

I'd like to store custom objects (let's say instances of MyDataClass) in a tree structure, and linked with a view. So I used QStandardItemModel. I think that MyDataClass should inherit from QStandardItem :
class MyDataClass : public QStandardItem
{
public:
MyDataClass(QString name)
private:
vector<float> someData;
}
But I cannot figure out how to store instances of this class in a QStandardItemModel.
I tried QStandardItem.setChild and then appendRow but it does not work and I think I don't really get the QStandardItemModel thing.
I think that the solution deals woth QStandardItem.setData but I cannot figure out how it works for custom objects.
I have finally make it work using QVariant.
To fill the model with custom data :
MyDataClass *data;
... // adding some data
QVariant variant;
variant.setValue(data);
QStandardItemModel model; // here is your model
QStandardItem *parentItem = model.invisibleRootItem();
QStandardItem *item = new QStandardItem();
item->setData(variant);
parentItem->setChild(0, 0, item); // adding the item to the root
Later, when you want to retrieve your data :
MyDataClass *retrievedData = model.invisibleRootItem()->
child(0, 0)->data().value<MyDataClass*>();
Note that I had to add a line in the class declaration :
class MyDataClass : public QStandardItem
{
public:
MyDataClass(QString name)
private:
vector<float> someData;
}
Q_DECLARE_METATYPE(MyDataClass *) // add this line
Thank you for your help.
You can use QStandardItemModel::setItemPrototype.
http://qt-project.org/doc/qt-4.8/qstandarditemmodel.html#setItemPrototype
Inherit from QStandardItem and reimplement method clone.
Create a new instance of your item and pass it to setItemPrototype.

QTreeView: maintaining mapping between QModelIndex and underlying data

I have problems migrating from QTreeWidget to QtreeView. Things that were obvious and trivial with QTreeWidget seem to be impossible with view. Specifically: I have a main window with a treeview in it. TreeView uses the model I've implemented, but not directly – through QSortFilterProxyModel that is set as a tree's model. Now, the user activates an item in the tree and main windows receives a signal itemActivated(QModelIndex item). How can I tell which item of the underlying data was activated? Data is a vector, so with TreeWidget I could just store an item's vector index in the QTreeWidgetItem, but QModelIndex doesn’t even have setData API.
How can I tell which item of the underlying data was activated?
By inverting the proxy model:
// supposing to connect this to your itemActivated signal
void onItemActivated(const QModelIndex &index)
{
QModelIndex originalIndex = proxyModel->mapToSource(index);
originalModel->doSomething(originalIndex);
}
You can define custom roles in your source model, returning the underlying data or an identifier (if there's one) as variant. This has the advantage it works with any number of proxy models in between, as the data will be passed through the models unaltered and now mapping of indexes is required.
Assuming a model listing contacts, with a value struct/class Contact holding the data.
This requires Contact to be registered via Q_DECLARE_METATYPE.
class ContactModel ... {
...
enum Role {
ContactRole=Qt::UserRole,
ContactIdRole
};
QVariant data(...) const {
...
const Contact& contact = ...get from datastructure...
...
switch (role) {
...
case ContactRole:
return QVariant::fromValue( contact );
case ContactIdRole:
return contact.id;
}
}
...
And in the code receiving the index:
void SomeWidget::indexSelected(const QModelIndex& index)
{
const int id = index.data(ContactModel::ContactIdRole).toInt();
// look up Contact, do something with it
//or:
const Contact contact = index.data(ContactModel::ContactRole).value<Contact>();
// do something with the contact
...
}
The index can be from the contact model itself, or any proxy on top of it - the code here doesn't have to care.
The model to stores your data. The data is no longer owned by items/QModelIndex in the view. QModelIndex is only a unique identifier passed between the view and the model (in this case via QSortFilterProxyModel). The model should inherit QAbstractItemModel which has some pure virtual functions that need to be defined (you can copy boilerplate from http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html). You will e.g. have to define QAbstractItemModel::data( const QModelIndex & index, int role = Qt::DisplayRole) which defines which data that corresponds to a particular QModelIndex.
The QSortFilterProxyModel sits between the view and the model, but does not change the principles for the model. See the other answer on this question for how to deal with the QModelIndex conversion.
To conclude: QAbstractItemModel::data( const QModelIndex & index) will give you the data for a particular QModelIndex once you have defined it.