views:

822

answers:

2

I am trying to write an OpenGL visualization program for some scientific data using qt. I would like to be able to use my existing program unchanged and simply be able to call the glwidget and tell it to update the data at the end of each time step. However in order to run a qt program it appears you have to use QApplication and then qt.run() which blocks the cpu.

Here is the pseudo code

main()

{

..set up stuff

myVisualizer = new myGLWidget();

for(int i=0;i<1000;i++) {

..do calculations

myVisualizer.update(new data)

}

}

I realize that I could put all of my existing code in to a qthread and have it send a signal whenever it is done to connect to an update. It would just be easier this way. Does anybody have an idea how to solve this?

A: 

Hi,

You can use QThread in your application and do the calculations in a seperate thread. What you have to do is to subclass the QThread and implement the run() method.

You can create a calculator class and add some signals in that class and connect the signal to your display widget's update slot (in this case QGLWidget::updateGL()).

Here is a rough example: (All you have to is to create a thread and DisplayWidget in your main() function and set the thread's DisplayWidget.)

class Calculator: public QObject
{
     Q_OBJECT

     public:
        Calculator();
        void start();

    signals:
        void updateDisplayWidget(/* you can put the resulting data */);
};

class DisplayWidget(): public QGLWidget
{
     Q_OBJECT
     // override paint methods here
     public slots:
          void slotUpdateDisplayWidget(/* you can receive the resulting data*/);
};

class MyThread : public QThread
{
public:
    void run();
    void setDisplayWidget(DisplayWidget* displayWidget);

private:
    Calculator mCalculator;
};

void MyThread::run()
{
     mCalculator.start();
     exec();
}

MyThread::setDisplayWidget(DisplayWidget* displayWidget)
{
    connect(&mCalculator, SIGNAL(updateDisplayWidget()), displayWidget, SLOT(slotUpdateDisplayWidget()));
}
alisami
wouldn't the slot in DisplayWidget run in the QThread's context?
Idan K
nope, Qt main event loop handles the threads and everything will work fine.
alisami
+1  A: 

If you really don't want to investigate the threaded solution, which would be nicer all around, you can use the special-case timeout with 0. Basically, when you run a timer with a timeout of 0, it runs the appropriate code after processing the events that are currently on the event queue. So, you could set up something like this:

class MyDialog : public QDialog
{
    Q_OBJECT
public:
    MyDialog()
    {
        m_step = 0;
        QTimer::singleShot( 0, this, SLOT( Process() ) );
    }

public slots:
    void Process() 
    {
        // do calculations
        m_step++;
        QTimer::singleShot( 0, this, SLOT( Redraw() ) );
        if ( m_step != 1000 )
            QTimer::singleShot( 0, this, SLOT( Process() ) );
    }

    void Redraw() { // do redrawing code here }

private:
    int m_steps;
};

And then combine it with the Qt-proper main code:

int main( int argc, char** argv )
{
    QApplication app( argc, argv );
    MyDialog dialog;
    dialog.show();
    return ( app.exec() );
}
Caleb Huitt - cjhuitt
Upvoted this answer as using a timer is the way I would do it. No need for a separate thread.However I don't see the need of the single shot timer to the Redraw slot and also why the widget is a subclass of QDialog and not QGLWidget.
Troubadour