Thanks a lot for your help. I have now an application with a responsive GUI
First of all here's what I did:
I've got a GUI class, named PhotoMosaicMainWindow (derived from QMainWindow), which owns a data object of type/class PhotoMosaicManager (responsible for heavy computations like building a mosaic image, given a database of images and a single motive).
When the "Compute" button of the main window is pressed, its event handler calls the PhotoMosaicManager's computeMosaic method.
Now I create a (boost) thread and pass the compute Method as follows:
if (m_computationThread != 0)
delete m_computationThread;
m_computationThread = new boost::thread(boost::bind(&(PhotoMosaicManager::computeMosaic), m_mosaicManager));
if (m_computationThread != 0)
delete m_computationThread;
m_computationThread = new boost::thread(boost::bind(&(PhotoMosaicManager::computeMosaic), m_mosaicManager));
To copy to clipboard, switch view to plain text mode
In order to access the progress bar (or other parts of the GUI), I emit signals from the PhotoMosaicManager's computeMosaic method. The signals are connected to the corresponding slots in the main window's constructor:
PhotoMosaicMainWindow
::PhotoMosaicMainWindow(QWidget* parent, Qt
::WindowFlags flags
){
// create gui elements defined in the Ui_MainWindow class
setupUi(this);
progressBar->setRange(0, 100);
m_mosaicManager = new PhotoMosaicManager();
m_mosaicManager->setManagerListener(this);
m_computationThread = 0;
connect(m_mosaicManager, SIGNAL(updateProgress(int)), this, SLOT(updateProgress(int)));
connect(m_mosaicManager, SIGNAL(computationFinished()), this, SLOT(finishedComputation()));
}
PhotoMosaicMainWindow::PhotoMosaicMainWindow(QWidget* parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
{
// create gui elements defined in the Ui_MainWindow class
setupUi(this);
progressBar->setRange(0, 100);
m_mosaicManager = new PhotoMosaicManager();
m_mosaicManager->setManagerListener(this);
m_computationThread = 0;
connect(m_mosaicManager, SIGNAL(updateProgress(int)), this, SLOT(updateProgress(int)));
connect(m_mosaicManager, SIGNAL(computationFinished()), this, SLOT(finishedComputation()));
}
To copy to clipboard, switch view to plain text mode
Three questions:
1) In http://lists.trolltech.com/qt-intere...ad00803-0.html I've read the following warning:
"Warning: Slots that generate window system events or use window system
functions must not be connected to a signal that is emitted from a thread
that is not the GUI thread."
But this is exactly what I'm doing, isn't it? I've got a slot which updates the progressbar, where the corresponding signal is emitted from a non-GUI thread. Is this a problem?
2) I would like to design the software in such a way, that all Qt stuff is encapsulated and completely separated from the data and computation classes like PhotoMosaicManager. But in order to emit signals from PhotoMosaicManager's computeMosaic method, I had to derive this class from QObject and use Qt's "emit" syntax. Any suggestions, how I can separate Qt/GUI from data classes? Add some kind of "third layer" between GUI and computation, which is responsible for communication between these two (the third layer could emit the signals)?
3) corresponding the timer problem, I've had earlier (let me know, if I've got the point):
my timer-event-handler wasn't called, because I started the timer from within an event handler of a button click (that's why the event loop of the GUI was disrupted) and because I started the heavy computation within this button-event handler immediately after calling timer->start(). Until timer->stop was called at the end of the button-event-handler, the heavy computation was done, so control was never returned back to the GUI event loop during computation and the timer-event could never be triggered...?
Bookmarks