I want to update list's row or grid's cell in wxwidgets using a loop or with a callback function which is called 10 times in a second. But app waits until the last run of the loop and then shows the last value. I tried refresh() and ForceRefresh() but it doesn't work. how can I achieve this?
for(int i=0; i< 30000; i++) {
list->SetItem(itemIndex, 0, wxString::Format(wxT("%i"),i));
//grid->SetCellValue( 0, 0, wxString::Format(wxT("%i"),i));
}
Edit: What I mean is outputting(printing, streaming) data live like a clock counter or printing progress rate. Using virtual style also does not update it often enough.
I'm not sure what is list and grid in your code but in any case, this is not how you should be doing it. There is no chance that 30000 items fit on your screen at once, so why set the values of all of them? Instead, use a "virtual" wxListCtrl, i.e. with wxLC_VIRTUAL style, or (always "virtual") wxGrid or wxDataViewCtrl and just update your data and refresh the items after they change. The GUI control will take care of showing the updated values of visible items only as fast as it can.
Well I got the complete answer from wxWidgets IRC. I should have refreshed before updating.
for(int i=0; i< 30000; i++) {
list->SetItem(itemIndex, 0, wxString::Format(wxT("%i"),i));
//grid->SetCellValue( 0, 0, wxString::Format(wxT("%i"),i));
MyFrame::Refresh();
MyFrame::Update();
}
Related
I am using QChart for an application. The application need to show some data realtime. There will be one chart and 24 series in the chart. The data rate is 400pts for every channel.
I used another thread for receiving and processing received data and emit the processed data to a slot for append datas to update the chart series.
I refered to https://doc.qt.io/qt-5/qtcharts-audio-example.html. In my case, each series is limited to 2000 points, if the number of points in the series is less than 2000, add the new point to the series, if the number of points in the seried is more than 2000, delete first point, move the rest of datas to left and add the new point in the end. This will make the chart look like move from right to left.
For good performance, I also used series->replace() and series->setUseOpenGL(true).
My problem is that the application will get freezed soon when it started. I tried delete the codes of update the chart, everything looked fine. Could anyone help me how to improve the performance of update the chart?
Thanks!
I have the same problem. The main problem I think is, that QLineSeries sends the signal pointAdded() and triggers a repaint. Additionally append() and remove are performance sinks. QtChart does only support QList and no form of a ring buffer as far as I know.
I tried the way putting new data into a QQueue<QPointsF> and copy the data within a timer hanler set to 20 Hz. To avoid updating I disable these:
void
MyGraph::handle_timer_timeout()
{
_chartView->setUpdatesEnabled(false);
// _chart->removeSeries(_series);
while(_buf->count()>0){
_series->append(_buf->dequeue());
_series->remove(0);
}
// _chart->addSeries(_series);
_axisX->setRange( _series->at(0).x(),
_series->at(_seriesSize-1).x());
_axisY->setRange(-1,1);
_chartView->setUpdatesEnabled(true);
}
This results in roughly 20-30% less processor usage.
I also found the hint that temporary removing the series (removeSeries(),addseries()) can result in some improvements but I can't confirm that.
This may be better but not really good enough. I hope someone finds a better solution.
or use QLineSeries::replace(). For that I use a double buffer QVector<QVector<QPointF>> *_lists:
void
MyGraph::handle_timer_timeout()
{
_chartView->setUpdatesEnabled(false);
auto listsother = (_listsCrurrent+1)%2;
auto bufcnt = _buf->count();
//
QVector<QPointF> *newData = &_lists->data()[listsother];
int idx;
for(idx=0; idx<_seriesSize-bufcnt;idx++){
newData->replace(
idx,
_lists->at(_listsCrurrent).at(idx+bufcnt));
}
for(; idx<_seriesSize;idx++){
newData->replace(
idx,
_buf->dequeue());
}
_listsCrurrent = listsother;
_series->replace(_lists->at(_listsCrurrent));
_axisX->setRange( _series->at(0).x(),
_series->at(_seriesSize-1).x());
_axisY->setRange(-1,1);
_chartView->setUpdatesEnabled(true);
}
This is more performant on my computer.
Alternatively you can take a look on QWT.
I have to display a progress bar using wxWidgets. Currently I am doing this :
m_dlgProgress = new wxGenericProgressDialog(wxString("Heading"), wxString("Message"), max, this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH);
for (int i = 0; i <= max; i++)
{
cont = m_dlgProgressConfig->Update(i);
i += max / 7;
wxMilliSleep(200);
}
callingSomeFunctionFromBackend();
//after this function is executed I am updating dialogue with its maximum value
cont = m_dlgProgressConfig->Update(max);
Is this correct way to display progress bar? I have seen some codes which create a thread and use OnWorkerEvent to update progress bar. Why do they create a thread. What I have done is correct or will it cause any problem further?
Your code is mostly fine, although you should really create the dialog on stack and not allocate it on the heap (especially without ever deleting it) and it's not clear why do you use wxGenericProgressDialog instead of wxProgressDialog.
But using a separate thread is preferable because it keeps your program GUI responsive while in your example it will be blocked for 200ms at a time and also for however long "some function from backend" is going to take. If this is acceptable for you, you can keep it like this, but using a background thread often results in a better user experience -- even though it requires more effort from the programmer.
I have a horizontal layout and when user enters a number, I am adding that number of widgets (which contain picture) to that layout.
void MainWindow::on_pushButton_2_clicked()
{
for(int i=0; i<count; i++)
{
ui->horizontalLayout_4->addWidget(label);
}
}
For example, if user enters 100, this function loop 100 times and after the function finishes its execution, it adds 100 widgets at the same time.
But I want function to add widgets step bu step.
For example, when i=0, it adds, when i=1 it adds.. And user should see the adding items step by step.
Is it possible?
In on_pushButton_2_clicked you could start a QTimer, connected to a slot that adds a single widget. Give the timer a reasonable timeout so that you can "see" each widget being added. Then use a counter in your class so that you know when to stop the timer. So, if the user entered 10, set the counter to 10 and subtract one from it each time the timer is fired. Stop the timer when the counter reaches zero.
i would implement a timer , that gives the UI a chance to refresh between each shot
I have a custom widget which displays many items in rows:
void update(){ //this is a SLOT which is connected to a button click
QVBoxLayout *layout = this->layout();
if (layout == NULL){
layout = new QVBoxLayout;
this->setLayout(layout);
} else {
QLayout_clear(layout); //this is a function that I wrote that deletes all of the items from a layout
}
ArrayList *results = generateData(); //this generates the data that I load from
for (int i = 0; i < results->count; i++){
layout->addWidget(new subWidget(results->array[i]));
}
}
The problem is that there are about 900 items and a profile reveals that simply adding the child object to the layout takes 50% of the time (constructing takes the other 50%). Overall it takes about 3 seconds to load all of the items.
When I click on the button to load more data, the entire UI freezes for the 3 seconds and then all of the items appear together when everything is done. Is there a way to progressively load more items as they are being created?
The first trick is, as Pavel Zdenek said, to process only some of the results. You want to process as many together so that the overhead (of what we're going to do in the next step) is low, but you don't want to do anything that would make the system seem unresponsive. Based on extensive research, Jakob Nielsen says that "0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously", so as a rough estimate you should cut your work into roughly 0.05 second chunks (leaving another 0.05 seconds for the system to actually react to the user's interactions).
The second trick is to use a QTimer with a timeout of 0. As the QTimer documentation says:
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface.
So that means that a timer with a timeout of 0 will be executed next, unless there is something else in the event queue (for instance, a mouse click). Here's the code:
void update() {
i = 0; // warning, this is causes a bug, see below
updateChunk();
}
void updateChunk() {
const int CHUNK_THRESHOLD = /* the number of things you can do before the user notices that you're doing something */;
for (; i < results->count() && i < CHUNK_THRESHOLD; i++) {
// add widget
}
// If there's more work to do, put it in the event queue.
if (i < results->count()) {
// This isn't true recursion, because this method will return before
// it is called again.
QTimer::singleShot(0, this, SLOT(updateChunk()));
}
}
Finally, test this a little bit because there's a gotcha: now the user can interact with the system in the "middle" of your loop. For instance, the user can click the update button while you're still processing results (which in the above example means that you would reset the index to 0 and reprocess the first elements of the array). So a more robust solution would be to use a list instead of an array and pop each element off the front of the list as you process it. Then whatever adds results would just append to the list.
#Adri is generally right, the twist is that the "another thread" must be the UI thread again. The point is to allow UI thread's event loop to keep spinning. The fast and dirty way is to put QCoreApplication::processEvents() in your for() cycle. Dirty because, as the doc says, it should be called "ocassionally". It might have some overhead even if there are no UI events, and you are messing Qt's performance optimization as to when and how often spin the loop. Slightly less dirty would be to call it only ocassionally, after chunks of result.
Cleaner and proper way is to create a private slot, which pops one result element (or chunk, to speed up), adds to the layout and increments index. Then it will recall itself until end of results. The gotcha is to define connect() with forced connection type Qt::QueuedConnection, so it will get deferred after already queued UI events (if any).
And because you run in only one thread, you don't need any locking over results.
Adding example per OP's request:
While #TomPanning solution is correct, it kind of hides the real solution behind QTimer which you don't need - you don't need any timing, you just need a specific non-timer behavior upon specific parameter value. This solution does the same thing, minus the QTimer layer. On the other hand, #TomPanning has a very good point about the plain ArrayList not being very good data storage, when interaction can happen in between.
something.h
signals: void subWidgetAdded();
private slots: void addNextWidget();
ArrayList* m_results;
int m_indexPriv;
something.cpp
connect(this,SIGNAL(subWidgetAdded()),
this,SLOT(addNextWidget(),
Qt::QueuedConnection);
void addWidget() {
// additional chunking logic here as you need
layout->addWidget(new subWidget(results->array[m_indexPriv++]));
if( m_indexPriv < results->count() ) {
emit subWidgetAdded(); // NOT a recursion :-)
}
}
void update() {
// ...
m_results = generateData();
m_indexPriv = 0;
addNextWidget(); // slots are normal instance methods, call for the first time
}
I would like to alter the rendering schedule for updates to a CollectionView (as created by {{each}}) so that a large insertion does not block the UI thread for a long time. Ideally, I'd like to render as many elements as I can in say 50 ms, then pass control back to the UI thread and set a timeout to continue further rendering. It looks like there is some facility in Ember for implementing custom render buffer behavior, but I'm not sure where to get started with it.
Here's a jsfiddle benchmark showing insertion of 500 elements into a list blocking the UI thread for a while:
http://jsfiddle.net/Ecq8g/6/
I would like to find a better way to do this, but right now I am delaying how quickly I populate the contents of the ArrayController. Here is a really dirty example.
http://jsfiddle.net/BsjSH/1/
for (var i = 0; i <= 999; i++) {
Ember.run.later(function() {
App.ArrayController.pushObject(App.Thing.create());
}, i * 3);
}
You could improve this by only maintaining a list of content of items that would be in the viewport. I like your idea of hooking into the render function of a CollectionView's itemViewClass and only allow a certain number of views to render.