QTableView -> optimize performance
-
Hi,
before getting into the business of thinking about a more efficient way to handle the data used in the QAbstractTablemodel in a little QTableView centered project, although there's certainly room for improvement, i'd like to ask, if there are any obvious options for rendering or similar that should be set, because i noticed the following:
If the number of rows to be displayed is greater than approx. 20 moving the columns is getting very, very slow. If the number of rows is under 20, while the others are hidden, performance is reasonable. This led me to believe, that the underlying data structure doesn't necessarily cause the slow performance of QTableView.
Maybe I should look after an alternative for QTableView? I wouldn't have thought that a few text fields in combination with some generic text boxes and fields for numbers, would cause such a slow performance on a rather recent computer.
Kind regards,
Andreas
-
Hi,
What is a bit worrying here is the "text field", "text box" and "number field". That makes it sound like you are using widgets within the table. Are you ?
-
No, there are no widgets, although i was thinking about implementing the delegate technique for the numbers. But after i saw the performance being so low, i decided to solve that issue first. At the maximum I'd have 10 tableviews spread over 10 tabs of a tabwidget with a maximum of about 70 rows, 16 columns, while 6 of them are hidden by default.
-
There must be something wrong on your side. Do you update the data very often? What OS und Qt version do you use?
Can you provide a minimal, compilable example of your model + view to reproduce the problem? -
The performance should not be so bad with such a small table. I would start be checking the performance of data loading from the model. It's queried quite a lot so if you have a bottleneck there, it will have consequences on the UI side.
-
There must be something wrong on your side. Do you update the data very often? What OS und Qt version do you use?
Can you provide a minimal, compilable example of your model + view to reproduce the problem?@Christian-Ehrlicher Well, i noticed that data() is called very often, that's why i have an idea, what to change. It's all under Gentoo Linux, qt version 5.15.2.
-
You should not do any calculations in data() - just return the values.
-
@Christian-Ehrlicher Well, i noticed that data() is called very often, that's why i have an idea, what to change. It's all under Gentoo Linux, qt version 5.15.2.
-
Ok, i managed to increase the performance of my QTableView instances significantly by putting some variables into private data fields via the constructor, which have been determined on the fly in data().
Anyway, it could be faster still, i guess, if i could find a way to avoid iterating in data(). I still need to do it, because as data source i'm using a list of json objects (i.e.: {key0 : value0, key1 : value1, ...}, {key0 : value0, key1 : value1, ...}), which should be displayed per row, each key being the head of one column, without knowing exactly how many key-value-pairs are in the object and of which data type. At least i'd like to have the possibility to remove or add some key value pairs without having to rewrite the code of the project.
-
@andi456 said in QTableView -> optimize performance:
way to avoid iterating in data()
Your really should avoid this - use a proper structure... simply put your data in a vector and you don't have any problems anymore.
-
I found this YouTube video from KDAB on how to write a Qt model very helpful when I implemented my first model
-
Ok, i managed to increase the performance of my QTableView instances significantly by putting some variables into private data fields via the constructor, which have been determined on the fly in data().
Anyway, it could be faster still, i guess, if i could find a way to avoid iterating in data(). I still need to do it, because as data source i'm using a list of json objects (i.e.: {key0 : value0, key1 : value1, ...}, {key0 : value0, key1 : value1, ...}), which should be displayed per row, each key being the head of one column, without knowing exactly how many key-value-pairs are in the object and of which data type. At least i'd like to have the possibility to remove or add some key value pairs without having to rewrite the code of the project.
@andi456
If from what you are saying you have JSON objects and you seem to be iterating stuff like keys in them in order to satisfydata()
requests, perhaps you should "unpack" them into C++ (if that's what you're using, you don't say) objects for faster access. You can wait until needed and cache results for performance. Or sometimes it pays to do processing work initially when new data arrives rather than each time upon retrieval. -
@andi456
If from what you are saying you have JSON objects and you seem to be iterating stuff like keys in them in order to satisfydata()
requests, perhaps you should "unpack" them into C++ (if that's what you're using, you don't say) objects for faster access. You can wait until needed and cache results for performance. Or sometimes it pays to do processing work initially when new data arrives rather than each time upon retrieval.@JonB Yes, that's what I essentially did in order to have a usable program: I copied the json object (I use nlohmann::json, because I did not know about QJson), into a two-dimensional std::vector of a custom struct and store it in a member of the model:
struct value_struct { bool string_set; std::string s; bool number_set; int n; bool flag_set; bool flag; };
The ..._set boolean values indicate which data type should be displayed in the data() method, which seems to work a lot better than my approach before. Anyway, running it in debug mode is still a little bit too slow. One obvious improvement would be to store QString values instead of std::string, but i don't know if that makes a huge difference.
-
Lifesaver when writing a model: https://wiki.qt.io/Model_Test
-
Lifesaver when writing a model: https://wiki.qt.io/Model_Test
@VRonin Ok, but it doesn't do performance checking, does it?
I did not know before, that the data() function is called in such high frequency. That's why I did not pay too much attention avoiding any unnecessary calculations, but was focused on getting it to work. Strangely enough, the performance improvement i noticed by moving some of the variables into the model's constructor and storing them in members was much bigger than my last step of copying the whole json object into a member of the model class.
-
Just a few furhter notes on observations that i made regarding QTableView performance:
1.) It is terribly slow in qtcreator default debug mode even if the cells do not contain any data at all, although i wouldn't have thought that a maximum of 70 rows x 16 columns with - I repeat - no data in it could be a problem for a modern computer even in debug mode. (I incidentally put !isValid() at the beginning of the data() method that accordingly it did not even try to put out data into the cells.)
2.) In the release mode offered by qtcreator after correcting my above error it seems to be quite snappy. The application uses a number of QTabWidget instances which are determined reading a json file via nlohmann::json for displaying the corresponding number of QTableView instances. The tables seem to appear immediately, when clicking on a tab. But making use of the "horizontalHeader()->setSectionsMovable()" feature slows down the creation of a table quite a bit.
3.) Given the above points, I wonder, Giuseppe D'Angelo in the video linked to above by DerReisende could be so confident that even much larger data sets would pose no problem?
-
As we already said - we've no problems with 10k of rows in a QTableView. Provide a minimal, compilable example to reproduce the problem.
-
As we already said - we've no problems with 10k of rows in a QTableView. Provide a minimal, compilable example to reproduce the problem.
@Christian-Ehrlicher Well, the program works much better than before. Anyway, I'll start from scratch with only one table and see what happens and will thus provide a minimal example.
My guess right now is that deciding which data type (number, boolean, string) to use in data() is the bottleneck. Could I just put the json values into a QVariant?