I am loading a set of 100 images to a QTableWidget. Since it takes about 4 seconds loading, I want to show a progress bar (customised one) with activity indicators or spinner etc. How could I update the GUI and the progress bar simultaneously, by signals & slots, and after loading the images?
Your event loop is busy with your main task, so it can't process your request. All slots will be called after event loop is free. Your options are:
Move slow processing to another thread. That may be not an option here because you can't interact with Qt's widgets in non-main thread.
Call QApplication::processEvents() each time when you want your GUI changes to apply. This is a common and simple solution. This function will execute your slots (if any calls are sheduled), updates GUI and returns execution flow to you.
A better way to load your images would be using a QThread that emits a signal as it processes the images, and connect that signal to a slot in your main widget, here you'll find a couple of examples
Related
I have a small IDE for a modeling language I wrote, implemented in PyQt/PySide, and am trying to implement a code navigator that let's you jump to different sections in the file being edited.
The current implementation is: (1) connect to QPlainTextEditor.textChanged, (2) any time a change is made, (sloppily) parse the file and update the navigator pane
It seems to work OK, but I'm worried this could cause major performance issues for large files on slower systems, in particular if more stuff is connected to textChanged in the future.
My question: Has anybody here implemented a delayed reaction to events, so that multiple events (i.e. keystrokes) within a short period only trigger a single update (say once per second)? And is there a proper QT way of doing this?
Thanks,
Michael
You can try using timers if you want some "delay".
There would be 2 ways to use them (with different results).
One is only parse after no input has been done for a certain amount of time
NOTE: I only know C++ Qt but I assume the same things are valid for pyqt so this is kind of "pseudocode" I hope you get the concept though.
QTimer timer; //somewhere
timer.setSingleShot(true); //only fire once
connect(timer,QTimer::timeout(),OnTimerDone(...);
OnTextChanged(...)
{
timer.start(500); //wait 500ms
}
OnTimerDone(...)
{
DoStuff(...);
}
This will restart the timer every input, so when you call that and the timer is not done the timeout signal is not emitted. When no input is done for an amount of time the timer timeouts and you parse the file.
The second option would be to have a periodic timer running (singleShot(false)).
Just start the timer for like each second. and timeout will be called once a second. You can combine that with a variable which you set to true when the input changes and to false when the file is parsed. So you avoid parsing when nothing has changed.
In C++Qt you won't have to worry about multi-threading because the slot gets called in the GUI thread. I assume it is the same for python but you should probably check this.
I have a Qwidget with a few tabs. In one of the tabs, after clicking a button, a function starts processing data and updates a progress bar.
I'd like to be able to change tabs while this process is running, currently it does'nt let me do so. Any idea?
(1) You must use a modeless progressdialog insteal of modal one. Practically, the main event loop must get the control to allow user interaction.
http://www.bogotobogo.com/Qt/Qt5_QProgressDialog_Modal_Modeless_QTimer.php
(2) You should put your data processing function to worker thread and invoke a progress dialog update to main UI thread from that. That way your task would not block UI, so you could interact with the window (like changing tab) meanwhile.
Qt also provides means to implement this, you might want to refer to:
QFuture, QtConcurrent::run(): run a task in separate thread.
QFutureWatcher: help monitor the progress of a task running in worker thread.
Example:
http://doc.qt.io/qt-5/qtconcurrent-progressdialog-example.html
Below logic may help you.
You can achieve this by using QThread.
Move the process to a separate thread(assume as worker thread)
So now there will be two thread (1. main thread & 2.worker thread)
Execute the process from worker thread
Use signal & slot mechanism to communicate between the main thread(1) & worker thread(2) (to update GUI and or to do some process)
This logic will stop the application from getting hanged.
Refer this link to know in detail.
You can get the sample application here, which follow the above said logic
Application screen shot :
Start Progress(Thread) : Start the thread and do process
Stop Process (Thread) : Stop the thread
My Qt 4 application can only update the log box area (actually the whole GUI) until a function finishes execution. Is there any way to update the GUI/log box during the execution? Like adding something like QWidget::repaint() or QWidget::update() in the for loop, so the user can see that the GUI is processing, rather than wait until the function finishes and print out the log at once.
You need to occasionally call QCoreApplication::processEvents() during the execution of your function. This will keep the GUI alive and responsive by letting the event loop run.
An alternative is to execute your function in a separate thread. More information on threads in Qt can be found here: http://qt-project.org/doc/qt-4.8/threads.html.
I am working on a multi -segment download manager. I want to display the segmentation procedure. QGraphicsScene works fine but , unfortunately it slows the download. Is there any better option, other than using QProgressBars.
I am using QNetworkAccessManager to download files. If I connect the downloadProgress signal of QNetworkManager object to a slot of Main Gui Thread which draws on QGraphicsView, the download speed decreases even upto 10 times in some cases
// a custom progress bar
void Download::showGProgress(int num, float prgrss) //slot
{
prgrss=prgrss/100;
x_coord=(ui->graphicsView_2->width()-3)*prgrss;
for(float b=0;b<=x_coord;b=b+0.5)
{
progress.addRect(0,0,x_coord,y_coord);
}
}
QNetworkAccessManager is not threaded. It is asynchronous, using the current threads eventloop. It is the HTTP requests which it create that are the threaded aspect.
This would explain why anything you do in your main thread could theoretically slow down the operations of the download. Though not necessarily the underlying threaded download itself, but rather the signaling response time that would allow you to have fast feedback about it.
What you should probably do is create your own QThread subclass, and create the QNetworkAccessManager in the run() method. And then create a QEventLoop in the thread and call exec()
In a nutshell, you need to create your own Threaded QNetworkAccessManager.
create your own widget to do what you would like
this is easier than it sounds.
Make a class that subclasses from a QWidget. And in this widget make a Horizontal Sizer that contains 100 Qlabels (store the QLabels in a vector). Give it slots to 'update' the current progress by setting the background color of each QLabel to a different color. This should be fairly easy to do progressively, meaning you store the current 'percentage' as a member variable and then only adjust the fields that are necessary to get to the percentage that you're looking for (This will eliminate some flickering if you were to do it from scratch every time).
Add functions that will switch the sizer to a vertical one instead of a horizontal one to make it even more customizable.
This allows you to get creative in the what you can do for the progress bar as each element could be a different picture, or a different color, or whatever you would like.
Did you try QProgressBar? Maybe you can write a subclass of it to handle your own properties.
I have an application which makes use of 20 different classes. The program execution starts in mainwindow. I start a progress dialog. I will make use of different classes for different purposes. After each function call which the execution goes to the particular class and does the required and come back to the mainwindow class, I will update the progress dialog. Now, the issue is the progress dialog freezes when the execution goes away from the mainwindow class. The cancel button is unable to accessed and so, the execution could not be stopped at the required time.
mainclass::mainclass()
{
ProgressDialog->exec();
x->add();
updateProgressDialog();
y->do();
updateProgressDialog();
zz->bring();
updateProgressDialog();
}
// x, y, z are three different classes.
This is how the execution goes. As soon as I enter the function in the main class, I will start the progress dialog. and call functions from different classes. The functions take considerable amount of time. I have invoked a thread to do the execution part, but I am unable to cancel the progress diaolog. I want the program execution to be stopped as and when the cancel button is pressed on the proggress dialog.
Please let me know how to get away with this issue. Hope I am clear here.
Without knowing exactly what calculations are being preformed in your threads its hard to isolate the problem. Maybe this can help: Keeping the GUI Responsive
Excerpt from: Performing Long Operations (by: Witold Wysota)
During long calculations (regardless of any usage of signals and slots) all event processing gets halted. As a result, the GUI is not refreshed, user input is not processed, network activity stops and timers don't fireāthe application looks like it's frozen and, in fact, the part of it not related to the time-intensive task is frozen.
The functions you are calling are not processing the Qt events loop. You are using a modal progress bar, since you are calling exec(). This means that Qt only gets control at the times where you update the dialog.
The only way that I know of to work around this is to code the dialog as modeless, but you will also have to provide an opportunity for the events loop to process.
This is explained in a fair amount of detail in the Qt docs: QProgressDialog