PDA

View Full Version : 'Best' Qt strategy for loading/saving user settings (esp. for QTreeView)



agarny
21st February 2011, 11:50
Hi,

When the user starts my application for the first time, I load some default settings. Then, upon exiting, I save the user settings which I reload the next time round.

Now, I was wondering what is the best way to do this in a Qt application. I currently save the user settings by overriding closeEvent(). The idea is that the GUI is still visible at that stage which allows me to properly save the user settings.

I am, however, facing problems with the loading of the user settings, especially with those related to a QTreeView-based widget. Basically, I have some kind of a file browser within my application and the first time the user starts my application, I would like my QTreeView-based widget to have its columns resized to their contents, but then allow the user to resize them manually if s/he so desires (and save that information in the user settings). At the same time, I want to keep track of the folder/file that is currently selected and, the next time, the user starts my application have my QTreeView-based widget point to that folder/file.

My understanding is that in order to do this, I would need my QTreeView-based widget to be visible. This means that I clearly can't do that in the constructor of my GUI class, or even QTreeView-based widget class. I therefore thought that I could do something similar to overriding closeEvent(), i.e. override showEvent() and have a static boolean that would be used to handle the loading of the user settings. Unfortunately, that approach doesn't work with my QTreeView-based widget. I just can't get the headers to autoresize or the folder/file to be scrolled to properly. In fact, this is not quite true, I have got things to work by displaying a dialog box just before doing to the autoresizing or scrolling, and it was fine, but I clearly don't want to have to display a dialog box to get things to work. So, it seems to me that my problem is that the GUI takes some time to become visible which means that I can't properly load the user settings.

So... what is the 'best' strategy to load/save user settings that require the GUI to be fully visible? I wish there was some kind of startEvent() method (i.e. the exact opposite of closeEvent()) which I could override...

Cheers, Alan.

schnitzel
21st February 2011, 21:40
have you looked at QSettings?

agarny
21st February 2011, 23:33
have you looked at QSettings?Yes, I am already using it and finds it very convenient indeed. This is not the issue though. My issue is that there are settings which I want to keep track of and restore, and some of those settings require my application to be fully visible. To store the settings, it's simple, I just override closeEvent(), but to load them I have yet to find something that works properly. I tried showEvent(), but that doesn't work for things I need to do with QTreeView for example. So... what could work?...

totem
22nd February 2011, 09:03
I tried showEvent(), but that doesn't work for things I need to do with QTreeView for example.

Why not ?
Is your tree built after app reached showeEvent() ?

agarny
22nd February 2011, 09:14
Why not ?Good question and question to which I would very much like to get an answer!


Is your tree built after app reached showeEvent() ?Well, clearly not, since for example scrollTo() doesn't work as expected when called from within showEvent(). It seems to me that QTreeView needs a bit more time to fully initialise itself which might explain why showing a dialog box just before calling scrollTo() makes scrollTo() to work...

stampede
22nd February 2011, 09:39
I have got things to work by displaying a dialog box just before doing to the autoresizing or scrolling, and it was fine
Have you tried to qApp->processEvents(); instead of displaying dialog box ?

agarny
22nd February 2011, 10:14
Have you tried to qApp->processEvents(); instead of displaying dialog box ?Yes, I did at the time, but to no avail. I am going to revisit all of that today though and will see how it goes.

wysota
22nd February 2011, 10:35
Please provide a test case where scrollTo() doesn't work as expected.

agarny
22nd February 2011, 10:40
Please provide a test case where scrollTo() doesn't work as expected.Ok, I am busy with a couple of other things right now, but will try to come up with a test case as soon as possible. Who knows, it might actually help me figuring out what is wrong with my code, if anything...

totem
22nd February 2011, 11:40
It seems to me that QTreeView needs a bit more time to fully initialise

Then try to detect the end of this loading process, and load you settings right after ?

agarny
22nd February 2011, 11:51
Then try to detect the end of this loading process, and load you settings right after ?I have tried that too (by having a while loop with qApp->processEvents(); in it -- yes, it was a quick and dirty way of testing things at that stage), but to no avail. What I did, if I recall correctly was to test for QTreeView to be visible, but that didn't quite work as I expected (I seem to remember that things were hanging up, but I might have something wrong back then, can't remember for certain).

totem
22nd February 2011, 13:25
Indeed a loop on processEvents() does not seem clean :)
If you have a treeview, you must have an associated model (or you meant treewidget?)
Try to catch a signal from this model, indicating it finished to load its data; if you don't find such signal, try to implement something equivalent. Then you read treeview settings, after its data has been updated

agarny
22nd February 2011, 13:32
Indeed a loop on processEvents() does not seem clean :)Well, I did warn you... :)


If you have a treeview, you must have an associated model (or you meant treewidget?)I do indeed have an associated model (a QFileSystemModel object).


Try to catch a signal from this model, indicating it finished to load its data; if you don't find such signal, try to implement something equivalent. Then you read treeview settings, after its data has been updatedI am not aware of any such signal. I did, however, try to 'play' with the expanded() signal, but again to no avail.

Anyway, I am nearly done with what I needed to do, so I should soon be able to resume that aspect of my work.

meyrambek
22nd February 2011, 13:37
As i understand your problem not in settings your problem in show/hide some properties of widgets. You can do save to file (as txt) your needed widgets as boolean or in integers (with specific values) then when your program opens read them from file and show/hide needed widgets.

agarny
22nd February 2011, 13:41
As i understand your problem not in settings your problem in show/hide some properties of widgets. You can do save to file (as txt) your needed widgets as boolean or in integers (with specific values) then when your program opens read them from file and show/hide needed widgets.Sorry meyrambek, but I believe you misunderstood my problem. Also, I wouldn't personally recommend using a text file to save my settings. I much prefer to rely on QSettings for this.

meyrambek
22nd February 2011, 13:53
not as txt as xml is more good way

agarny
22nd February 2011, 14:32
not as txt as xml is more good wayPlease have a look at QSettings (http://doc.qt.nokia.com/stable/qsettings.html) and you will see that there is no point in using a text file or even an XML file.


Please provide a test case where scrollTo() doesn't work as expected.Ok, here goes for a very simple example of what I am trying to do with scrollTo():

QTreeView.pro:
QT += core gui

TARGET = QTreeView
TEMPLATE = app

SOURCES += main.cpp
main.cpp:
#include <QApplication>
#include <QFileSystemModel>
#include <QHeaderView>
#include <QTreeView>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QFileSystemModel fsm;

fsm.setRootPath(""); // I.e. access to the whole file system

QTreeView w;

w.setModel(&fsm);
w.header()->setResizeMode(QHeaderView::ResizeToContents);

w.show();

QModelIndex mi = fsm.index("C:\\Windows\\System32\\zipfldr.dll");

w.setCurrentIndex(mi);
w.scrollTo(mi);

return a.exec();
}The idea behind line 21 is that we point to a file which is out of the field of view and should therefore get scrollTo() to scroll down to that file. Unfortunately, this doesn't work for me, as shown below:

5975

wysota
22nd February 2011, 15:39
I would guess the model index might simply be invalid because the filesystem model takes time to populate itself. Have you tried that with a different model?

agarny
22nd February 2011, 16:40
I would guess the model index might simply be invalid because the filesystem model takes time to populate itself. Have you tried that with a different model?Sorry, are you saying that mi doesn't contain the right information? If so, then no it does contain the right information, since if I manually scroll down, then I will see the right file selected (as a result of w.setCurrentIndex(mi)).

Otherwise, what do you mean trying with another model? Do you mean something else than QFileSystemModel?

wysota
22nd February 2011, 16:43
Do you mean something else than QFileSystemModel?
Yes, that's what I mean.

This works as expected:

#include <QtGui>

int main(int argc, char **argv){
QApplication app(argc, argv);
QListView view;
QStringListModel model;
QStringList list;
for(int i=1;i<=200;++i){
list << QString("Item %1").arg(i);
}
model.setStringList(list);
view.setModel(&model);
view.show();
view.setCurrentIndex(model.index(100,0));
view.scrollTo(model.index(100,0));
return app.exec();
}

agarny
22nd February 2011, 18:01
Yes, I tried with QStandardItemModel and 3 levels of QStandardItem objects and it all works as expected:
#include <QApplication>
#include <QHeaderView>
#include <QMessageBox>
#include <QModelIndex>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QTreeView>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QStandardItemModel sim;

const int nbOfItems = 10;
const int nbOfSubItems = 10;
const int nbOfSubSubItems = 10;

QStandardItem item[nbOfItems];
QStandardItem subItem[nbOfItems][nbOfSubItems];
QStandardItem subSubItem[nbOfItems][nbOfSubItems][nbOfSubSubItems];

for (int i = 0; i < nbOfItems; ++i) {
item.setText(QString("%1").arg(i+1));

for (int j = 0; j < nbOfSubItems; ++j) {
subItem[i][j].setText(QString("%1").arg(j+1));

for (int k = 0; k < nbOfSubSubItems; ++k) {
subSubItem[i][j][k].setText(QString("%1").arg(k+1));

subItem[i][j].setChild(k, &subSubItem[i][j][k]);
}

item[i].setChild(j, &subItem[i][j]);
}

sim.setItem(i, &item[i]);
}

QTreeView w;

w.header()->hide();
w.setModel(&sim);
w.show();

QModelIndex mi = sim.indexFromItem(&subSubItem[7-1][6-1][9-1]);

w.setCurrentIndex(mi);
w.scrollTo(mi);

return a.exec();
}which is clearly good, but very frustrating too, since I can't understand why it doesn't work the same with QFileSystemModel.

---------------------------------------

Finally got it! :D

Thanks wysota for asking me to check with another model. The fact that it worked with another model confirmed to me that my current use of QFileSystemModel was probably not optimal.

So, after going through the QFileSystemModel documentation in a bit more detail (until now, I had assumed that the 'problem' was with QTreeView and had therefore kind of 'ignored' QFileSystemModel until now), I noticed the [I]directoryLoaded(QString) signal. So, I have quickly tested that in my application and, now, everything works as expected. So, yes, RTFM, but read the right section! :)