How to show "waiting" while files are loaded in a Qt application? - c++

I'm selecting and loading some big Dicom files on my program. The whole loading process takes a long time(depends on the number of files, but the whole process can take more than minutes if the files are many). I want show a "waiting symbol" or something like that when the file uploading is going on. I searched for it, but I didn't get anything definite.
My code for the selection and uploading part is as below:
void MainWindow::showTheSelectedList()
{
QFileDialog * fileDialog = new QFileDialog(this);
fileDialog->setFileMode(QFileDialog::ExistingFiles);
QListView* list = fileDialog->findChild<QListView*>("listView");
if(list)
{
list->setSelectionMode(QAbstractItemView::MultiSelection);
}
QTreeView* tree = fileDialog->findChild<QTreeView*>();
if(tree)
{
tree->setSelectionMode(QAbstractItemView::MultiSelection);
}
if(fileDialog->exec())
{
if(fileDialog->selectedFiles().size()>0)
{
int listsize=stringList.size();
for(int i=0;i<listsize;i++)
{
// get the name of the file
// check if the file is dicom
// upload if the file is dicom
// after uploading, get the pixel data of that file
// use the pixel data and make a icon out of it
//then insert the icon in an a QTablewView
}
}
}
//show the QtableView
}
Could you please instruct me where and how I can show the waiting sign or symbol while the uploading part is running?
Thanks

I think you are looking for the QProgressBar class. The documentation makes it clear below. You will need to set up the minimum and maximum values, and it will do the job for you.
The QProgressBar widget provides a horizontal or vertical progress bar.
A progress bar is used to give the user an indication of the progress of an operation and to reassure them that the application is still running.
The progress bar uses the concept of steps. You set it up by specifying the minimum and maximum possible step values, and it will display the percentage of steps that have been completed when you later give it the current step value. The percentage is calculated by dividing the progress (value() - minimum()) divided by maximum() - minimum().
You can specify the minimum and maximum number of steps with setMinimum() and setMaximum. The current number of steps is set with setValue(). The progress bar can be rewound to the beginning with reset().
If minimum and maximum both are set to 0, the bar shows a busy indicator instead of a percentage of steps. This is useful, for example, when using QNetworkAccessManager to download items when they are unable to determine the size of the item being downloaded.
I do not think much more details can be provided based on the question as the worker loop seems to be commented without actual code being provided in there, but this documentation should make it clear either way.
Note that I would personally even move the worker loop into an own worker thread if it is that hefty that it deserves a progressbar. As for the progressbar, you would probably write something like this:
QProgressBar bar(this);
bar.setRange(maximum, maximum);
bar.setValue(minimum);
bar.show();

Dialog box:
My novice suggestion would be to use progress bar inside your for loop and increment the progress bar as each file finishes loading.
Let me know if you need more detail.

Related

Performantly appending (rich) text into QTextEdit or QTextBrowser in Qt

QTextEdit can be appended text to simply using append(). However, if the document is rich text, every time you append to the document, it is apparently reparsed. This seems like a bit of a trap in Qt.
If you're using the edit box as a log window and appending text in fast successions as a result of external signals, the appending can easily hang your app with no intermediate appends shown until each of the appends have completed.
How do I append rich text to a QTextEdit without it slowing down the entire UI?
If you want each append to actually show quickly & separately (instead of waiting until they've all been appended before they are shown), you need to access the internal QTextDocument:
void fastAppend(QString message,QTextEdit *editWidget)
{
const bool atBottom = editWidget->verticalScrollBar()->value() == editWidget->verticalScrollBar()->maximum();
QTextDocument* doc = editWidget->document();
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.beginEditBlock();
cursor.insertBlock();
cursor.insertHtml(message);
cursor.endEditBlock();
//scroll scrollarea to bottom if it was at bottom when we started
//(we don't want to force scrolling to bottom if user is looking at a
//higher position)
if (atBottom) {
scrollLogToBottom(editWidget);
}
}
void scrollLogToBottom(QTextEdit *editWidget)
{
QScrollBar* bar = editWidget->verticalScrollBar();
bar->setValue(bar->maximum());
}
The scrolling to bottom is optional, but in logging use it's a reasonable default for UI behaviour.
Also, if your app is doing lots of other processing at the same time, appending this at the end of fastAppend, will prioritize actually getting the message displayed asap:
//show the message in output right away by triggering event loop
QCoreApplication::processEvents();
This actually seems a kind of trap in Qt. I would know why there isn't a fastAppend method directly in QTextEdit? Or are there caveats to this solution?
(My company actually paid KDAB for this advice, but this seems so silly that I thought this should be more common knowledge.)

QChart realtime performance

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.

Proper way to get 'infinite loading' progress bar with minimum duration delay using QProgressDialog

Problem
I am trying to use QProgressDialog to display a modal dialog window that shows an 'infinite loading' progress bar, but which also takes advantage of the minimum duration which can be specified before showing the window. I am able to do it using a bit of hacky code, but wanted to ask if there is a more correct way to do it.
Use case
A query is made to some back-end service and the results may come quickly or may take a little more time. If the results are returned 'quickly', eg < 500ms, no dialog should show (to avoid a dialog box flickering on screen). If the results take 'more time', the modal dialog should appear (allowing the user to potentially cancel the operation, etc).
Code
Initialization
m_progress = new QProgressDialog(this);
m_progress->setWindowModality(Qt::WindowModal);
m_progress->setLabelText("Looking up data...");
m_progress->setMinimumDuration(500);
connect(m_progress, SIGNAL(canceled()), this, SLOT(onProgressCanceled()));
'Look up data' button onClicked slot (sends request to back-end and shows dialog)
// HACKY CODE ----------
//
m_progress->setMaximum(100); // some value != 0 (0 is the value passed to setValue)
m_progress->setValue(0); // starts the minimum duration timer
m_progress->setMaximum(0); // set maximum to 0 to get 'infinite loading' progress bar
//
// HACKY CODE ----------
onProgressCanceled slot
m_progress->reset();
onResults method (callback that handles returned results)
m_progress->reset();
That is the entirety of the relevant code.
The reason for the hack is that in the Qt source, there is this explicit check:
(d->bar->value() == -1 && progress == d->bar->maximum())
If the maximum is set to 0 (for 'infinite loading') before the value is set to 0 (which starts the minimum duration timer), then QProgressDialog::setValue simply returns. The d->bar->value is initialized to -1 and reset to -1 when QProgressDialog::reset is called. It's almost as if this specific use case of QProgressDialog ('infinite loading' but with a minimum duration delay) is being singled out.
Question
Is there a way to achieve the same result but without the use of the hacky code that I'm missing? I feel like I'm missing something simple.

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.

show a simple progress bar in C++

Here is the problem:
I want to show a progress bar (just as a text like "Remaining 35%...") during a C++ function execution. I've done the first part which is the progress bar but the problem is how do I show the progress bar during the other functions execution?
I just want to start showing the bar when execution enters a specific function and reach 100% when leaving the function.
How do I do this in C++? any suggestion?
thanks in advance!
/Niklas
Use a separate thread to update the progress bar. That should give "near real" progress of your application.
There are two things to consider. First is, when do you update your progress bar? In general this can be done by dividing the work your function does into ticks, and then use a tick-count that you increase every time the function has advanced one tick. One example would be this:
void SomeFunction() {
for ( int i = 0; i < 1337; i++ ) {
// do important stuff
ProgressBar.IncreaseTickCount();
}
}
The caller would then do something like this:
ProgressBar.SetNumberOfTicks( 1337 );
SomeFunction();
This way, the progress bar would be able to recalculate its value at every iteration of the loop. How this is presented on the screen depends on your GUI-Framework. As has been suggested by #Amit and the comments to his answer, you will most likely have the function run in a worker-thread, and the UI-thread will update the progress bar continuously. In this case make sure that the tick-counter is thread-safe.
A simple text-based stdout tic style progress bar can be found in a single file at ezProgressBar
. You can wrap it in a thread if you'd like. One nice feature is that is does minimal printing to a single line so overhead is pretty cheap and you don't need to play games with finding the magic "reset cursor to beginning of line" character like '\r'.