Using Qt signals/slots instead of a worker thread
I am using Qt and wish to write a class that will perform some network-type operations, similar to FTP/HTTP. The class needs to connect to lots of machines, one after the other but I need the applications UI to stay (relatively) responsive during this process, so the user can cancel the operation, exit the application, etc. My first thought was to use a separate thread for network stuff but the built-in Qt FTP/HTTP (and other) classes apparently avoid using threads and instead rely on signals and slots. So, I'd like to do something similar and was hoping I could do 开发者_如何学JAVAsomething like this:
class Foo : public QObject
{
Q_OBJECT
public:
void start();
signals:
void next();
private slots:
void nextJob();
};
void Foo::start()
{
...
connect(this, SIGNAL(next()), this, SLOT(nextJob()));
emit next();
}
void Foo::nextJob()
{
// Process next 'chunk'
if (workLeftToDo)
{
emit next();
}
}
void Bar::StartOperation()
{
Foo* foo = new Foo;
foo->start();
}
However, this doesn't work and UI freezes until all operations have completed. I was hoping that emitting signals wouldn't actually call the slots immediately but would somehow be queued up by Qt, allowing the main UI to still operate.
So what do I need to do in order to make this work? How does Qt achieve this with the multitude of built-in classes that appear to perform lengthy tasks on a single thread?
If you're doing a length job in the UI thread the UI is going to freeze. One way to avoid this is to call once in a while QCoreApplication::processEvents()
.
You should be VERY careful however to understand what this does before you decide to do it. Calling this function means that a GUI event can fire in the middle of your operation. If this event can in turn create some more jobs you can end up starting a new job while in the middle of the old job.
I wouldn't be so quick dismissing the worker thread approach. It has the advantage of completely separating the work from the GUI so you are certain that something that began is going to finish.
You should also consider that Windows especially sometimes introduces non trivial delays to GUI loops. If the host is somewhat busy or in a memory thrashing state you'll find that GUI events may take up to several long seconds to finish and return control to your processing.
Use QThread with a run method like this:
void run(){ exec(); }
this will provide another execution loop, where you can do your "hard work" without acutally freezing the UI.
Note: Make sure to actually use the thread's execution loop by adding
moveToThread(this);
at the end of the Constructor of your QThread derived Thread class (the doc doesn't say much about it)
精彩评论