PDA

View Full Version : Need to find a way to save user inputs.



"BumbleBee"
13th October 2011, 14:15
So I am making a kind of large app,which will be used by many people.
In a seperate widget(class) I have put a tablewidget which is empty.
User can use this tool to store data and save it.

What I mean by "save", is that once some text is entered,it will be there next time the user opens the program.
Then he might edit all the fields,add/remove colums/rows etc..

The key part here is to make the fields saveable :D

I have no idea how to do this..maybe there is some text file,so that I save all the data there,then read from it..or something else?

Please help.

wysota
13th October 2011, 14:55
And how does this differ from this thread?
http://www.qtcentre.org/threads/45200-Is-there-a-widget-for-this

"BumbleBee"
13th October 2011, 15:56
Tables are different than lineedits.

wysota
13th October 2011, 16:03
Are they...?

"BumbleBee"
16th October 2011, 09:50
Well,for the Lineedit I do: set.setValue("text1", ui->le1->text()); then ui->le1->setText(set.value("text1").toString());
While the Tablewidget doesn't have those functions( text(),setText() )..

Zlatomir
16th October 2011, 10:17
QTableWidget (http://doc.qt.nokia.com/latest/qtablewidget.html) has lines and columns that can hold QTableWidgetItems (doc.qt.nokia.com/stable/qtablewidgetitem.html) which items have setText (http://doc.qt.nokia.com/stable/qtablewidgetitem.html#setText) member function.

"BumbleBee"
16th October 2011, 10:31
Well,this is what I have so far:

void Victims::save()
{
QSettings set("vic","tims");
set.beginGroup("setting");

int grows = ui->tw->rowCount();
int gcols = ui->tw->columnCount();

for(int i = 0; i < grows ;i++)
{

for(int j = 0; j < gcols ;j++)
{
QTableWidgetItem* widgetItem = ui->tw->item(grows, gcols);
tmp = widgetItem(i,j)->text(); //tmp is a string.
if ( tmp.isEmpty() )
break;
}
set.setValue("victims", tmp); //tmp will be the string that will be put into set.value(),correct?
}
set.endGroup();
}

However it gives me an error: widgetItem cannot be used as a function :/
Am I on the right way?

Zlatomir
16th October 2011, 10:54
widgetItem is already a pointer to the item at i,j index so use it without (i,j), just: widgetItem->setText("blabla");

LE: don't forget to check for null, because, if i remember correctly, if the indexes are out-of range that item function returns null

wysota
16th October 2011, 14:28
I suggest you come up with a universal solution that will work regardless of the item you want to store/restore. Provide classes or functions that will be called depending on the item/widget type you need to store and have some infrastructure that will call those classes/functions. You basically need something similar to QMainWindow::saveState() and QMainWindow::restoreState().

"BumbleBee"
16th October 2011, 15:18
Right now I cannot put a simple table into settings,when you tell me to make a universal functionality..
I suppose I'd better do it seperatly and if I have time I will think of what u said.

So,my thought was to do this:
Loop through the rowcount() and create as many arrays of string.
Then use that nested loop(intthe code I pasted) and after each row,store the text into one array.
Then in restore,I would re-loop(the table) to put the arrays as text..
Is that ok?

wysota
16th October 2011, 17:06
Right now I cannot put a simple table into settings,when you tell me to make a universal functionality..
You are considering the two as different problems whereas it is the same problem, it's just a matter of having a single solution doing all you want today and all you might want tomorrow or having a tightly coupled solution which works for what you want today but will require the same amount of work for each of the things you'll want tomorrow and the day after.

"BumbleBee"
16th October 2011, 18:08
Hmm..I can't really come up with an idea that would work for any widget.
Can you give me a hint?

wysota
16th October 2011, 20:59
I would probably have some kind of handler interface that I would then implement for each type of class I'd want to serialize and I'd have some class for managing the whole process that would take the result from all the implementations and store them in some kind of storage (like QSettings or QIODevice). We actually have that kind of mechanism in our software with the following interface:

#ifndef ISTATE_H
#define ISTATE_H

#include <QObject>

class IState : public QObject {
Q_OBJECT
public:
IState(QObject *parent = 0) : QObject(parent){}
virtual ~IState(){}
virtual QByteArray saveState() const = 0;
virtual void restoreState(const QByteArray &ba) = 0;
virtual QObject *object() const = 0;
};

#endif // ISTATE_H

We call saveState() for each of the objects monitored and transfer the resulting blob over the wire to a backend we have.

tamhanna
17th October 2011, 01:50
A very simple solution is this Prefs class - it uses a file, not QSettings.

/*
* ApplicationPrefs.cpp
*
* Created on: Dec 31, 2009
* Author: TAMHAN
*/

#include "ApplicationPrefs.h"
#include <qDebug>

ApplicationPrefs::ApplicationPrefs()
{
// TODO Auto-generated constructor stub
myPasswordChangedFlag=false;
}

ApplicationPrefs::~ApplicationPrefs()
{
// TODO Auto-generated destructor stub
//CANNOT SAVE HERE, OR THE RED KEY WILL PREVENT DATA SAVAGE
}

void ApplicationPrefs::initPrefs()
{
QFile prefFile(QDir::currentPath() + "/prefs.tmgn");
if(!prefFile.open(QIODevice::ReadOnly))
{
defaultPrefs();
return;
}
QDataStream in(&prefFile);
quint32 version;
in >> version; // not needed for this v
if(version==1)
{
in >> myLongIntCache;
int sampleVal;
in >> sampleVal;
myProtectionType=(QProtectionType)sampleVal;

//Init new values from V2
mySelfLockFlag=false;
mySelfLockTime=60;
myHideEmptyFieldsFlag=false;
mySelfDestructIsArmedFlag=false;
mySelfDestructPassword="";
myMustUpdateSchemesFlag=true;
myOldVersion=1;
goto terminateInit;
}
in >> myLongIntCache;
int sampleVal;
in >> sampleVal;
myProtectionType=(QProtectionType)sampleVal;
//all below is new for V2
in >> mySelfLockFlag;
in >> mySelfLockTime;
in >> myHideEmptyFieldsFlag;
in >> mySelfDestructIsArmedFlag;
in >> mySelfDestructPassword;
in >> myMustUpdateSchemesFlag;
myMustUpdateSchemesFlag=false;
if(version==2)
{//update for Nokia only
myMustUpdateSchemesFlag=true;
}
terminateInit:
prefFile.close();
}

void ApplicationPrefs::savePrefs()
{
QFile prefFile(QDir::currentPath() +"/prefs.tmgn");
if(!prefFile.open(QIODevice::WriteOnly))
{
defaultPrefs();
return;
}
QDataStream out(&prefFile);
quint32 version=3;
out << version; // not needed for this v
out << myLongIntCache;
int sampleVal=myProtectionType;
out << sampleVal;
//all below is new for V2
out << mySelfLockFlag;
out << mySelfLockTime;
out << myHideEmptyFieldsFlag;
out << mySelfDestructIsArmedFlag;
out << mySelfDestructPassword;
out << myMustUpdateSchemesFlag;
prefFile.close();
}

void ApplicationPrefs::defaultPrefs()
{
myLongIntCache=1; //0 is reserved as magic number for XFER to other box

mySelfLockFlag=false;
mySelfLockTime=60;
myHideEmptyFieldsFlag=false;
mySelfDestructIsArmedFlag=false;
mySelfDestructPassword="";

myMustUpdateSchemesFlag=true;
myOldVersion=0;
}

bool ApplicationPrefs::prefsExist()
{
QFile prefFile(QDir::currentPath() +"/prefs.tmgn");
if(prefFile.exists())
{
return true;
}
else
{
return false;
}
}

quint64 ApplicationPrefs::getUniqueID()
{
quint32 retval=myLongIntCache;
myLongIntCache++;
savePrefs();
return retval;
}

wysota
17th October 2011, 09:56
But it doesn't help you in storing settings for different types of objects, you still need to put everything in your ApplicationPrefs class and this class has to know every object it is to work with.

"BumbleBee"
17th October 2011, 16:12
I would probably have some kind of handler interface that I would then implement for each type of class I'd want to serialize and I'd have some class for managing the whole process that would take the result from all the implementations and store them in some kind of storage (like QSettings or QIODevice). We actually have that kind of mechanism in our software with the following interface:

#ifndef ISTATE_H
#define ISTATE_H

#include <QObject>

class IState : public QObject {
Q_OBJECT
public:
IState(QObject *parent = 0) : QObject(parent){}
virtual ~IState(){}
virtual QByteArray saveState() const = 0;
virtual void restoreState(const QByteArray &ba) = 0;
virtual QObject *object() const = 0;
};

#endif // ISTATE_H

We call saveState() for each of the objects monitored and transfer the resulting blob over the wire to a backend we have.

So.The qbytearray works like a generic string type that stores any kind of data and then puts it where needed,right?

wysota
17th October 2011, 16:24
Not a string type. Just a block of data. The IState subclass is responsible for interpretting it and applying to the object it operates on (be it a table widget or a line edit).

"BumbleBee"
17th October 2011, 16:55
But still,to put a table into a ba,I need to loop though the table right?

wysota
17th October 2011, 17:20
Yes. That's what a subclass of IState would be responsible for in my case.

tamhanna
17th October 2011, 23:24
But it doesn't help you in storing settings for different types of objects, you still need to put everything in your ApplicationPrefs class and this class has to know every object it is to work with.

If this is the issue, I would proceed to trying XML. But the core issue always remains: the reading routine needs to know what it will read in.

"BumbleBee"
29th October 2011, 12:22
void Victims::load()
{
int grows = ui->tw->rowCount();
int gcols = ui->tw->columnCount();

QSettings set("victims");
set.beginGroup("setting");

for(int i = 0; i < grows ;i++)
{

for(int j = 0; j < gcols ;j++)
{
QTableWidgetItem* widgetItem = ui->tw->item(grows, gcols);
QString ex = set.value("victims", str).toString();
widgetItem->setText(ex);
}

}

set.endGroup();
}


void Victims::save()
{
int grows = ui->tw->rowCount();
int gcols = ui->tw->columnCount();

QSettings set("victims");
set.beginGroup("setting");

for(int i = 0; i < grows ;i++)
{

for(int j = 0; j < gcols ;j++)
{
QTableWidgetItem* widgetItem = ui->tw->item(grows, gcols);
str = widgetItem->text();
}

}
set.setValue("victims", str);
set.endGroup();
}

Can you tell me what I did wrong here?

wysota
29th October 2011, 14:16
You should iterate over i and j instead of grows and gcols.

Santosh Reddy
30th October 2011, 09:24
You can iterate through the ItemModel (instead of table widget items). Here a some what generic code, with which you can save & restore all item data roles. With a minor modifications and use of recursion this code can also be used to save TreeWidgets


void Victims::load()
{
QAbstractItemModel* model = ui->tw->model();
for(int row = 0; row < model->rowCount(); row++)
{
settings->beginGroup(QString("Row-%1").arg(row));
for(int col = 0; col < model->columnCount(); col++)
{
settings->beginGroup(QString("Column-%1").arg(col));
QModelIndex item = model->index(row, col);
for(int role = 0; role < Qt::UserRole; role++)
{
model->setData(item, settings->value(QString("ItemDataRole-%1").arg(role))); // Restore from file
}
settings->endGroup();
}
settings->endGroup();
}
}


void Victims::save()
{
QAbstractItemModel* model = ui->tw->model();
for(int row = 0; row < model->rowCount(); row++)
{
settings->beginGroup(QString("Row-%1").arg(row));
for(int col = 0; col < model->columnCount(); col++)
{
settings->beginGroup(QString("Column-%1").arg(col));
QModelIndex item = model->index(row, col);
for(int role = 0; role < Qt::UserRole; role++)
{
settings->setValue(QString("ItemDataRole-%1").arg(role), model->data(item, role)); // Save to file
}
settings->endGroup();
}
settings->endGroup();
}
}

"BumbleBee"
4th November 2011, 14:10
You can iterate through the ItemModel (instead of table widget items). Here a some what generic code, with which you can save & restore all item data roles. With a minor modifications and use of recursion this code can also be used to save TreeWidgets


void Victims::load()
{
QAbstractItemModel* model = ui->tw->model();
for(int row = 0; row < model->rowCount(); row++)
{
settings->beginGroup(QString("Row-%1").arg(row));
for(int col = 0; col < model->columnCount(); col++)
{
settings->beginGroup(QString("Column-%1").arg(col));
QModelIndex item = model->index(row, col);
for(int role = 0; role < Qt::UserRole; role++)
{
model->setData(item, settings->value(QString("ItemDataRole-%1").arg(role))); // Restore from file
}
settings->endGroup();
}
settings->endGroup();
}
}


void Victims::save()
{
QAbstractItemModel* model = ui->tw->model();
for(int row = 0; row < model->rowCount(); row++)
{
settings->beginGroup(QString("Row-%1").arg(row));
for(int col = 0; col < model->columnCount(); col++)
{
settings->beginGroup(QString("Column-%1").arg(col));
QModelIndex item = model->index(row, col);
for(int role = 0; role < Qt::UserRole; role++)
{
settings->setValue(QString("ItemDataRole-%1").arg(role), model->data(item, role)); // Save to file
}
settings->endGroup();
}
settings->endGroup();
}
}


Thanks for putting all this code.But the save slot doesn't work..after loading,the table is empty!!!!