How to display long list in SwiftUI? - swiftui

After noticing that my problem is not a database specific problem, but an UI problem I'm creating this new question here.
I have a SearchBar (source) that is used to filter a dataset from a realm database. This works so far well and fast. But when I want to display the result in a list it's pretty slow.
I've tried different approaches to display the elements. I thought the LazyVGrid could be a good solution for this use case since it doesn't create the view for each element but only when I scroll down and need to display them.
ScrollView {
LazyVGrid{
ForEach(...)
}
}
But this approach was veeeery slow and sometimes my app crashed.
So I switched to the classic approach with List{ ForEach(...){ } }.id(UUID()) that is my current solution. The performance is okay. ~2-3 second for 15.000 elements. Additionally my CPU and memory is increasing extremely for the 2-3 seconds. I'm not using any animations or other stuff. For testing I just used a single line text to represent each element.
I'm looking more for a solution like: Display the first n results immediately. And when I scroll down and really need the other results the view for each element should be created only then.

Related

Column-Packed RowColumn Class for Motif Library (C)?

I recently asked this question: Horizontally-Drawn RowColumn Class for Motif Library (C)?
In my previous question, I was having trouble getting the xmRowColumnWidgetClass to draw horizontally (row-by-row) instead of vertically (column-by-column). After playing around with it, figured out how to switch to horizontal drawing with the following snippet:
XmNorientation, XmHORIZONTAL,
So the code that creates the xmRowColumnWidgetClass instance now looks like this:
rowColumn = XtVaCreateManagedWidget("rowcolumn",
xmRowColumnWidgetClass,
parentWidget,
XmNnumColumns, 3,
XmNorientation, XmHORIZONTAL,
XmNpacking, XmPACK_COLUMN,
XmNspacing, 6,
NULL);
However, my new problem is that for some reason the XmNnumColumns field is now referring to the number of rows, rather than the actual number of columns. Before adding the XmNorientation, XmHORIZONTAL part, the xmRowColumnWidgetClass instance was drawing the objects from left-to-right but it stayed to 3 columns like it was supposed to. Now, it is staying to 3 rows, occasionally creating a horizontal scrollbar which I do not want. I only want vertical scrolling.
So I need the children of the xmRowColumnWidgetClass instance to be drawn horizontally from top to bottom, but I need it to only put a maximum of 3 per row and thus keep it confined within a certain width.
I tried playing around with the XmNnumColumns field, but things that worked with more children did not work for less children, and vice versa. Sometimes it made it 4 or 5 columns rather than 3, and sometimes it made it 2 columns with the 3rd column completely empty. I encountered many issues like this even when experimenting with things like using XmNpacking, XmPACK_TIGHT rather than XmNpacking, XmPACK_COLUMN and other stuff.
If someone is able to find the official documentation of the xmRowColumnWidgetClass and link it, that would be be greatly appreciated.
To anybody familiar with this library:
How do I create a xmRowColumnWidgetClass instance that draws horizontally (row-by-row) while keeping it to a certain number of columns?
It should be able to handle any number of children and add as many rows as it needs to in order to keep it as exactly 3 columns.
Another group of examples of this library:
https://github.com/spartrekus/Motif-C-Examples
https://github.com/spartrekus/Motif-C-Examples/blob/master/rowcol.c
XmRowColumn was designed to implement the top menubar and all the other menu classes... You are searching for a grid like widget, and so you have to use XmForm read the related question for that.
In short: try the WtTable widget
Longer explanation follows:
The behaviour of XmRowColumn regarding "columns" becoming "rows" when you choose a horizontal configuration is very unfortunate. The alternative of using XmForm instead of XmRowColumn for this purpose is feasible, but however it requires manually setting the children constraints, and even then, it's quite possible that you won't be able to achieve the automatic sizing implemented in XmRowColumn.
By searching today, I found the WtTable widget and it works fine for my purposes. It's "almost" as automatic as XmRowColumn and it doesn't require to set any constraints manually. I tried it in my Motif code, and works fine.
Note however that I said "almost" as automatic. The "almost" is because you need to specify the number of columns and rows, and you need to specify the column and row for each child widget. However, all of this can be automated: you can create a convenience function that internally manages counters for columns and rows, so that you pass a widget to such function and it puts it in the cell it belongs automatically: you can even make that function create a new row in the WtTable when it's needed.

QStringList::append() Poor Performance

In my project, I have a function that recursively iterates over the model of a QTreeView. At certain points, I append values to a QStringList that is stored in each item's Qt::UserRole.
Here's the issue... the recursive scanning does a ton of checking, reading from JSON file, importing icons from disk, etc etc HOWEVER, all of that is miles faster than simply appending 1 or 2 strings to the QStringList for about 5% of the items in the model.
I did some basic profiling and found that if I comment out all calls to QStringList::append() but LEAVE IN all the crazy JSON reading, icon setting, color changing, etc, it is 3 times faster than if I left them in. And it is noticeably slower... frustratingly slower.
So I decided to narrow it down to only 1 call to QStringList::append() on about 5% of the items. Here is the example of code:
QStringList rightClickList = mainItem->data(Qt::UserRole+8).toStringList();
rightClickList.append("customName");//comment this out and it runs 3x faster
//than allllll the recursive scanning combined!
mainItem->setData(rightClickList, Qt::UserRole+8);
I would estimate about 5% of all the items in a given model have any QStringList changes at all. The rest are left alone. Are QStringList types really that slow? If so, what alternative would you recommend?
Thanks for your time!
It could be memory pressure: as array-based storage grows, the runtime stops and allocates storage to keep up.
It could also be a side-effect of recursion; if the problem persists, try a stack-based recursion.

How to make Qt navigate tree items fast?

I developed a Qt tree with 1,000,000 items under a node. The code is similar to its simple tree model example at http://qt-project.org/doc/qt-5.0/qtwidgets/itemviews-simpletreemodel.html .
When I click key "End", it takes 15 seconds to go to the last item. Any way to make it faster?
Set uniformRowHeights to true. Then the row height is calculated only once, instead of million times, making the QTreeView much faster.

QListWidget::addItem() gives flickering when i call it 40 times per second

What is the choise better than QListWidget to display a lot of log lines in GUI that are coming from backend at average speed 40 lines per second?
QListWidget gives a flickering and even white box instead of a widget for a long time when a lot of strings are already placed into ListWidget.
Is there any better solution to dynamically display log lines to a user?
update:
Changed architecture. Adding new QStrings to std::deque< QString* >. Using QTimer i add that strings every 1/10 of second to QPlainTextEdit, deleting from deque. boost::mutex is used to protect std::deque (log lines are coming from different threads).
Would be nice to have a time to implement my own QListView and keep strings in big chunks of pre-allocated memory.
Are you sure you need the functionalities of a QListWidget? If you just want to display log lines, I think a simple read-only QPlainTextEdit would be more appropriate.
You might try to use QListView and you own implementation of QAbstractItemModel. Then you can store your lines as you wish and append new lines in big groups (about every second should be ok). Then view is not refreshed at adding every line but only in groups, which should highly improve performace.
I would suggest setting a refresh rate and append all gathered items at once. You will avoid repaint of widget every line you append.
Long story short:
QTimer with refresh rate (~1-3 seconds would be enough), QListWidget::addItems instead of QListWidget::addItem

multiple CComboBox sharing the same data

I have a MFC dialog with 32 CComboBoxes on it that all have the same data in the listbox. Its taking a while to come up, and it looks like part of the delay is the time I need to spend using InsertString() to add all the data to the 32 controls. How can I subclass CComboBox so that the 32 instances share the same data?
Turn off window redrawing when filling the combos. e.g.:
m_wndCombo.SetRedraw(FALSE);
// Fill combo here
...
m_wndCombo.SetRedraw(TRUE);
m_wndCombo.Invalidate();
This might help.
The first thing I would try is calling "InitStorage" to preallocate the internal memory for the strings.
From MSDN:
// Initialize the storage of the combo box to be 256 strings with
// about 10 characters per string, performance improvement.
int n = pmyComboBox->InitStorage(256, 10);
In addition to what has already been said, you might also turn off sorting in your combo box and presort the data before you insert it.
One way along the lines of your request would be to go owner drawn - you will be writing a fair chunk of code, but you won't have to add the data to all of them.
"CComboBox::DrawItem"
Support.microsoft have this article on subclassing a Combo box which might also be of interest
"How to subclass CListBox and Cedit inside of CComboBox"
Really one has to ask if it is worth the effort, and alot of that depends things like
number of entries in the list
number of times the dialog will show
variability of the combo content
optomising elsewhere
not drawing until the screen is complete
only building the dialog once and re showing it.
using the one combo but showing it in different locations at different times