PDA

View Full Version : Display data from XML file in TableView



neda
24th February 2016, 08:56
Hi,
I want to display data in TableView which I am getting from XML file.
I wrote this code, but I have some error like this:
'QObject::QObject' : cannot access private member declared in class 'QObject' => error of dataobject.h
my code is correct?
main.cpp:

MyModel mymodel;
engine.rootContext()->setContextProperty("mymodel", &mymodel);

main.qml:

TableView {
id: tablemodel
MyTableViewColumn {
role: "pro1"
title: "pro1"
width: 70
}
...
...
MyTableViewColumn {
role: "pro11"
title: "pro11"
width: 60
}
MyTableViewColumn {
role: "index"
title: " "
width: 30
}
model: ListModel {
id: myModel
source:myModel.mydata
}
}


dataobject.h:

#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
class DataObject: public QObject
{
Q_OBJECT
Q_PROPERTY(QString newIndex READ getIndex WRITE setIndex NOTIFY indexChanged)
Q_PROPERTY(QString newpro1 READ getpro1 WRITE setpro1 NOTIFY pro1Changed)
...
...
Q_PROPERTY(QString newpro11 READ getpro11 WRITE setpro11 NOTIFY pro11Changed)
Q_PROPERTY(QByteArray newImage READ getImage WRITE setImage NOTIFY imageChanged)


public:
DataObject();
DataObject(QString,QString,QString,QString,QString ,QString,QString,QString,QString,QString,QString);

Q_INVOKABLE QString getIndex() const;
Q_INVOKABLE QString getpro1() const;
...
...
Q_INVOKABLE QString getpro11() const;
Q_INVOKABLE QByteArray getImage() const;

public slots:

void setIndex(QString index);
void setpro1(QString pro1);
..
...
void setpro11(QString pro11);
void setImage(QByteArray image);

signals:
void indexChanged(QString);
void pro1Changed(QString);
...
...
void pro11Changed(QString);
void imageChanged(QByteArray);

private:

QString newIndex;
QString newpro1;
...
...
QString newpro11
QByteArray newImage;
};

#endif // DATAOBJECT_H



dataobject.cpp:


#include "dataobject.h"

DataObject::DataObject()
{
}
DataObject::DataObject(QString index,QString pro1,.......,QString pro11)
{
newpro1=pro1;
...
...
newpro11=pro11;
}

QString DataObject::getpro1() const
{
return newpro1;
}
void DataObject::setpro1(QString pro1)
{
if (pro1 != newpro1)
{
newpro1= pro1;
emit pro11Changed(pro1);
}
}

...
...

QString DataObject::getpro11() const
{
return newpro11;
}
void DataObject::setpro11(QString pro11)
{
if (pro11 != newpro11)
{
newpro11= pro11;
emit pro11Changed(pro11);
}
}

QByteArray DataObject::getImage() const
{
return newImage;
}
void DataObject::setImage(QByteArray image)
{
if (image != newImage)
{
newImage= image;
emit imageChanged(image);
}
}


mymodel.h:

#ifndef MYMODEL_H
#define MYMODEL_H

#include <QAbstractListModel>
#include <dataobject.h>

class MyModel : public QAbstractTableModel
{
Q_OBJECT
std::vector<DataObject> mydata;
public:
typedef std::vector<DataObject>::const_iterator const_iterator;
explicit MyModel(QObject *parent = 0);
enum {index,hardness,fromFirst,avgDiam,omgheAsar,firstD iam,secondDiam,timeNiro,niro,method,zoom,MAX_COLS} ;

int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
void addData(DataObject data);
void removeData(int row);
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags(const QModelIndex &index) const;
DataObject& getData(size_t index);
const_iterator begin()const{return mydata.begin();}
const_iterator end()const{return mydata.end();}
};


#endif // MYMODEL_H


mymodel.cpp



#include "mymodel.h"

QVariant MyModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return QVariant();

if(index.row() >= mydata.size() || index.row() < 0)
return QVariant();

if(role == Qt::DisplayRole || role == Qt::EditRole)
{
switch(index.column())
{
case prop1:
return mydata[index.row()].getprop1();
...
...
case prop11:
return mydata[index.row()].getprop11();
}
}
return QVariant();
}
QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role != Qt::DisplayRole)
return QVariant();

if (orientation == Qt::Horizontal)
{
switch (section)
{

case 1:
return tr("pro1");
...
...
case 9:
return tr("pro11");
}
}
return QVariant();
}
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole && !(index.row() >= mydata.size() || index.row() < 0))
{
int row = index.row();

switch(index.column())
{
case 0:
mydata[row].setIndex(value.toString());
break;
case 1:
mydata[row].setpro1(value.toString());
break;
...
...
case 11:
mydata[row].setprop11(value.toString());
break;
default:
return false;
}
emit dataChanged(index, index);
return true;
}
return false;
}
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
void MyModel::addData(DataObject data)
{
if(std::find(mydata.begin(),mydata.end(),data)!=my data.end())
return;
beginInsertRows(QModelIndex(),mydata.size(),mydata .size());
/*BOOST_SCOPE_EXIT(this_){
this_->endInsertRows();
}BOOST_SCOPE_EXIT_END*/
mydata.push_back(std::move(data));
endInsertRows();
}
void MyModel::removeData(int row)
{
beginRemoveRows(QModelIndex(),row,row);
/*BOOST_SCOPE_EXIT(this_){
this_->endRemoveRows();
}BOOST_SCOPE_EXIT_END//*/
mydata.erase(std::next(mydata.begin(),row));
//endRemoveRows();
}




myxml.xpp:

void MyXML::saveXMLFile()
{
QFile file(newFileName);
file.open(QIODevice::WriteOnly);

QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();

xmlWriter.writeStartElement("NewDataSet");

xmlWriter.writeStartElement("header");
...
...
xmlWriter.writeEndElement();

MyModel model;
MyModel::const_iterator it = model.begin(),end = model.end();
for(;it != end;++it)
{
xmlWriter.writeStartElement("record");

// QFile fileImg(newImage);
// fileImg.open(QIODevice::ReadOnly);

// QByteArray imageData = fileImg.readAll();
// QByteArray imageData_Base64 = imageData.toBase64();

// xmlWriter.writeAttribute("image",imageData_Base64);

xmlWriter.writeTextElement("index",it->getIndex());
xmlWriter.writeTextElement("prop1",it->getprop1());
...
...
xmlWriter.writeTextElement("prop11",it->getprop11());

xmlWriter.writeEndElement();
}

xmlWriter.writeEndElement();

file.close();
}

void MyXML::readXMLFile()
{
QFile file(newFileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
//qDebug() << "Error: Cannot read file ";
return;
}
QXmlStreamReader reader(file.readAll());
file.close();

while(!reader.atEnd()) {
reader.readNext();
if (reader.isStartElement()) {
if (reader.name() == "header") {

foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
...
...
}
}
else if (reader.name() == "recorde") {

QString prop1,...,prop11;

foreach(const QXmlStreamAttribute &attr, reader.attributes()){
if(attr.name().toString() == QLatin1String("index")){
index=attr.value().toString();
}
else if(attr.name().toString() == QLatin1String("prop1")){
prop1=attr.value().toString();
}

...
...

else if(attr.name().toString() == QLatin1String("prop11")){
prop11=attr.value().toString();
}

}
MyModel model;
model.addData(DataObject(index,prop1,....,prop11)) ;
}
}
}
}

anda_skoa
24th February 2016, 10:33
Here


std::vector<DataObject> mydata;

you are using DataObject as a value type, meaning you are working with copies when adding to or reading from the vector.

But DataObject is a QObject dervied class, instances of QObject cannot be copied.
You don't need the model's data clas to be derived from QObject, it is never directly exposed to QML.

Aside from that:
- you need a list model not a table model, as QtQuick only works on list models
- you need to overwrite the model's rolesNames() method to provide a mapping from QML role names to your role enum values.
- your MyXML method will want to work on the model that you expose to QML, not on newly created instances that get deleted at the end of the method

Cheers,
_

neda
27th February 2016, 05:34
I changed the code
But I do not see any record in the TableView.
main.qml:

TableView {
id: tablemodel
anchors.fill: parent
TableViewColumn {
role: "col1"
title: " "
width: 30
}
model: myXML.newDataList
// model: ListModel {
// id: myModel
// }
}
myxml.h:

class MyXML: public QObject
{
Q_OBJECT
//...
Q_PROPERTY(QList<QObject*> newDataList READ getDataList WRITE setDataList NOTIFY dataListChanged)
public:
MyXML();
MyXML(QString);
//...
Q_INVOKABLE QList<QObject*> getDataList() const;
public slots:
//...
void setDataList(QList<QObject*> dataList);
void saveXMLFile();
void readXMLFile();

signals:
//...
void dataListChanged(QList<QObject*>);
private:
//...
QList<QObject*> newDataList;
};
myxml.cpp:

void MyXML::readXMLFile()
{
//...
while(!reader.atEnd()) {
reader.readNext();
if (reader.isStartElement()) {
//...
if (reader.name() == "record") {
foreach(const QXmlStreamAttribute &attr, reader.attributes()){
newDataList.append(new DataObject("col1", attr.value().toString()));
}
}
}
}
}
void MyXML::saveXMLFile()
{

}
I must write and open a XML file Like this:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<record prop1=".." prop10="..." />
.......
<record prop1=".." prop10="..."/>
</NewDataSet>
dataobject.h:

class DataObject:public QObject
{
Q_OBJECT
Q_PROPERTY(QString newName READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString newValue READ value WRITE setValue NOTIFY ValueChanged)
public:
DataObject();
DataObject(QString,QString);
Q_INVOKABLE QString name() const;
Q_INVOKABLE QString value() const;
public slots:
void setName(QString name);
void setValue(QString value);
signals:
void nameChanged(QString);
void valueChanged(QString);
private:
QString newName;
QString newValue;
};
dataobject.cpp:

#include "dataobject.h"
DataObject::DataObject()
{
}
DataObject::DataObject(QString name,QString value)
{
newName=name;
newValue=value;
}
QString DataObject::name() const
{
return newName;
}
void DataObject::setName(QString name)
{
if (name != newName)
{
newName =name;
emit nameChanged(newName);
}
}
QString DataObject::value() const
{
return newValue;
}
void DataObject::setValue(QString value)
{
if (value!= newValue)
{
newValue = value;
emit valueChanged(newValue);
}
}

anda_skoa
27th February 2016, 10:52
I changed the code

Any specific reason you did not just fix the model but went for a totally different approac



But I do not see any record in the TableView.

I am not sure what you expect to see.
You tell the TableViewColumn to use "col1" as the role, yet your data has no "col1", it has "newName" and "newValue".

So, from your point of view, which of these tw comparions should be true?


"col1" == "newName"
"col1" == "newValue"

As far as I know neither C++ nor JavaScript would evaluate either of these two as true.

Cheers,
_

neda
27th February 2016, 12:13
Thank you for your answer.



I am not sure what you expect to see.
You tell the TableViewColumn to use "col1" as the role, yet your data has no "col1", it has "newName" and "newValue".

_

I have this XML file:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<record prop1=".." prop10="..." />
.......
<record prop1=".." prop10="..."/>
</NewDataSet>

And I have a TableView with this columns:
prop1, .... , prop10

I want to use newName for name of columns(name=prop1 , .. , prop10) and newValue for value of attributes in XML file.
I do not see any record in tableview.




So, from your point of view, which of these tw comparions should be true?


"col1" == "newName"
"col1" == "newValue"


_

Excuse me, you are right. I mistake to write code here. I put "newDataList.append(new DataObject("name of column ==for example prop1", attr.value().toString())); " for test.

I can display my XML file using XmlListModel in Tableview, but I can not save all record of Tableview in XML file by using XmlListModel.
I write another code by using QAbstractTableModel, but I do not see any data after open XML file in Tableview.

If you are agree I want to put a another sample program by QAbstractTableModel.

anda_skoa
27th February 2016, 13:10
My recommendation is to re-read comment #2.

Cheers,
_

neda
28th February 2016, 05:58
Here


std::vector<DataObject> mydata;

you are using DataObject as a value type, meaning you are working with copies when adding to or reading from the vector.

But DataObject is a QObject dervied class, instances of QObject cannot be copied.
You don't need the model's data clas to be derived from QObject, it is never directly exposed to QML.

Aside from that:
- you need a list model not a table model, as QtQuick only works on list models
- you need to overwrite the model's rolesNames() method to provide a mapping from QML role names to your role enum values.
- your MyXML method will want to work on the model that you expose to QML, not on newly created instances that get deleted at the end of the method

_

mymodel.h:

#ifndef MYMODEL_H
#define MYMODEL_H

#include <QStandardItemModel>
class MyModel : public QStandardItemModel {

public:
enum Role {
role1=Qt::UserRole,
role2,
role3
};

explicit MyModel(QObject * parent = 0): QStandardItemModel(parent){}
explicit MyModel( int rows, int columns, QObject * parent = 0 )
: QStandardItemModel(rows, columns, parent){}

QHash<int, QByteArray> roleNames() const{
QHash<int, QByteArray> roles;
roles[role1] = "one";
roles[role2] = "two";
roles[role3] = "three";
return roles;
}
};


#endif // MYMODEL_H




void MyXML::saveXMLFile()
{
?????
}


void MyXML::readXMLFile()
{
MyModel model;
foreach(const QXmlStreamAttribute &attr, reader.attributes()){

QStandardItem* it = new QStandardItem();
it->setData(attr.value().toString(), MyModel::role1);// Just for test
it->setData(attr.value().toString(), MyModel::role2);// Just for test
it->setData(attr.value().toString(), MyModel::role3);// Just for test
model.appendRow(it);
}

main.cpp:

MyModel* model = new MyModel;


QStandardItem* it = new QStandardItem();
it->setData("data 1", MyModel::role1);
it->setData("data 2", MyModel::role2);
it->setData("data 3", MyModel::role3);
model->appendRow(it);

it = new QStandardItem();
it->setData("more data 1", MyModel::role1);
it->setData("more data 2", MyModel::role2);
it->setData("more data 3", MyModel::role3);
model->appendRow(it);



engine.rootContext()->setContextProperty("myModel", model);

main.qml:

TableView {

anchors.fill: parent

TableViewColumn {title: "1"; role: "one"; width: 150 }
TableViewColumn {title: "2"; role: "two"; width: 150 }
TableViewColumn {title: "3"; role: "three"; width: 150 }

model: myModel

}

When I run the program, tableview displays 2 row, but when I call "readXMLFile" function, Will not be added any records to the tableview.

anda_skoa
28th February 2016, 11:00
When I run the program, tableview displays 2 row, but when I call "readXMLFile" function, Will not be added any records to the tableview.

Your readXMLFile function does not work on the model you have exposed to QML.

Just have the model as a member of MyXML, then you can access it via property just like the list in comment #3

Cheers,
_

neda
28th February 2016, 11:21
Your readXMLFile function does not work on the model you have exposed to QML.

Just have the model as a member of MyXML, then you can access it via property just like the list in comment #3

Cheers,
_

Thank you.
I got it.
But what should I do to correct the code.
Please guide me with simple code. :(

anda_skoa
28th February 2016, 12:12
I am afraid I don't understand.
You already have all the code, you are just working with two instances of the model instead of one.

So don't create a model instance in main(), just create the MyXML object and let it have the model.
Like you did with the list in comment #3.

Cheers,
_