Dusan Zatkovsky wrote:
> Hi all.
> I have a question about how to show some task progress. Here is my story:
> I needed to create a "task", that runs a long-time job ( simulated by cycle 
> over sleep()s in example code ) and shows the progress.
> I have tried 2 ways to do this, but none is the best. I'll be happy if 
> someone tell me the right way.
> Create primitive dialog with progressbar and slider. It will be used in 
> following cases:
> 
>         QDialog d = new QDialog();
>         QLayout l = new QFormLayout(d);
>         QProgressBar b = new QProgressBar();
>         l.addWidget(b);
>         QSlider s = new QSlider();
>         l.addWidget(s);
> 
> 
> 
> Way 1 - job in thread:
> ----------------------

This way is by far superior as it lets you completely decouple the work 
done from the UI. It means, as pointed out by others that you cannot 
access the UI directly, but as long as you communicate with the UI 
thread using connect/emit statememtns this is fine. This means you need 
to introduce a second signal,

If the emitter and the receiver recide in different threads then the 
signal is emitted as an asynchronous queued connection. This means that 
the progressbar has not been updated when the call terminates, but it 
does work across threads and is definitely the approach I would choose.

I would rewrite the class like this though:

class Job extends QObject <---- Always use QObjects for signals
implements Runnable
{
     public QSignal1<Integer> progress;
     public QSignal0 jobDone;

     public void run() {
         while (stuffToDo) {
            doABitMoreStuff();
            progress.emit(currentProgress);
         }
         jobDone.emit();
     }
}

In the UI thread:

Job job = new Job();
job.progress.connect(progressBar, "valueChanged(int)")
job.jobDone.connect(progessDialog, "accept()");

new Thread(job).start();
progressDialog.exec();

This way, the worker thread is nicely decoupled from the main UI.


>       disadvantages:
>               -       too much of code. Nested class, threading, ...
>               -       too many signals (at least 2 - progress changed and job 
> done, because executed dialog must be closed
>                       when job has finished. Number of signals is growing if 
> you have another special needs ).
I don't see why the number of signals is a problem?

>               -       I can't do anything with gui from within the thread ( 
> show the error messages etc... ).
>                       It throws exceptions about out-of-main-loop and app 
> (probably) crashes.
You would use an errorOccured<String> signal for that.

> 
> 
> Way 2 - calling processEvents():
> ----------------------

This approach would work, but it freezes the API for the interval you 
choose so the processing interval needs to be less than 20ms or so, 
unless your UI will feel jerky. This approach was common in the past 
when Qt (in C++ mind you) was built without threading support enabled.

>       // only show, do not exec the dialog
>       d.show();
> 
>       // job loop
>         for ( int i = 0; i < 30; i++ ) {
> 
>             // simulate work
>             Thread.sleep(2000);
> 
>             // set progress
>             b.setValue(i);
> 
>             // process events
>             QApplication.processEvents();
> 
>             // show message - no problem here
>             QMessageBox.info(...)
>         }
>
_______________________________________________
Qt-jambi-interest mailing list
[email protected]
http://lists.trolltech.com/mailman/listinfo/qt-jambi-interest

Reply via email to