Esaith
Esaith

Reputation: 808

QTimer nonrelated to extending QThread

This question seems to have been answered in one form or another when someone is overloading a thread with their own class, but what about just trying to use the QTimer class without extending the QThread class. I am attempting to use the QTimer for QT. Their simple example on

http://qt-project.org/doc/qt-4.7/qtimer.html

Their example is as follows:

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);

But when I attempt this, I keep on getting the error:

QObject::startTimer: Timers can only be used with threads started with QThread.

I am working through the set of videos by Jamie King on YouTube through his Game Engine Development series. I plan on folllowing his videos to the tee, so any abstract completely different coding techniques is not preferred at this moment. This is what I have so far.

I tried to make a small quick side project to keep the code as simple as I could. I do not have any build errors - they only occur after the program starts to

QTimerApp.cpp

#include <QtWidgets\qapplication.h>
#include <QtWidgets\qwidget.h>
#include "GLWin.h"

int main(int argc, char* argv[])
{
    QApplication application(argc, argv);
    GLWin MyGL;
    MyGL.show();

    return application.exec();

}

GLWin.h

#ifndef My_GL_Window
#define My_GL_Window
#include <QtOpenGL\qglwidget>
#include <QtCore\qtimer.h>

class GLWin : public QGLWidget
{




    Q_OBJECT            // preprocessor from QT - gives what we need for slots
        // Declaration* - should be in class. Declared in class, but not defined.
        // Needs to be defined in .cpp (manually)
        // Or allow QT to define for us. (preferred)
        // use moc.exe (found in $(ProjectDir)..\Middleware\Qt\bin\moc.exe against myGLWindow.h
        // C:\MyEngine\ProgramFiles\Middleware\Qt\bin\moc.exe myGLWindow.h > MyGLWindow_moc.cpp 
        // then include MyGLWindow_moc.cpp in project


    GLuint vertexBufferID;
    QTimer myTimer;

protected:
    void initializeGL();
    void paintGL();

    private slots:              //All classes that contain signals or slots must mention Q_OBJECT at the top of their declaration.
    // They must also derive (directly or indirectly) from QObject.

private:
    void updateWin();
};

#endif

GLWin.cpp

#include <gl\glew.h>
#include "GLWin.h"
#include <cassert>
#include <QTCore\QTimer.h>

void GLWin::initializeGL()
{

    GLenum errorCode = glewInit();
    assert(errorCode == 0);

    glGenBuffers(1, &vertexBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);

    float verts[] =
    {
        +0.0f, +0.1f,
        -0.1f, -0.1f,
        +0.1f, -0.1f,
    };

    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);



    QTimer* timer = new QTimer(0);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateWin()));
    timer->start();

}

void GLWin::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);  
    glDrawArrays(GL_TRIANGLES, 0, 3);   
}

void GLWin::updateWin()
{
}

Most of the research that I have come up with has to do with overloading the run() function when their class has extended QThread. As far as I can tell, I shouldn't have to extend nor create another class for a simple timer loop to occur. Having extended QWidget already, my object is already a QObject type.

Any assistance is truly appreciated. Thank you!

Upvotes: 2

Views: 437

Answers (2)

Esaith
Esaith

Reputation: 808

Wow. Silly me, I finally found the answer after too long.

... while in debugging mode, make sure all of your .lib and .dll that you are linking are the debugger and NOT the release .dll.

... ie, I was using

Qt5OpenGL.dll and Qt5OpenGL.lib

instead of Qt5OpenGLd.dll and Qt5OpenGLd.lib

... I feel a fool but this will never catch me again. Just blindly choosing "Oh hey.. I see Qt5Open...." Good enough! Just make sure that you check all of your files and not just those two.

/facepalm!

Upvotes: -2

L&#225;szl&#243; Papp
L&#225;szl&#243; Papp

Reputation: 53145

Your code has many issues:

  • QtFoo\ style include. You better use forward slashes as that is the common way of using it for good.

  • You do not actually need to use QtFoo explicitly and it is also better as it makes the buildsystem more reliable and the project more portable.

  • You do not use Q_DECL_FINAL optimization for your end class.

  • You do not use Q_DECL_OVERRIDE for overridden member methods.

  • You do not actually mark your slot as slot.

  • You do not set a parent for your timer, so it leaks memory.

  • You use cassert when Qt has its own Q_ASSERT and Q_ASSERT_X.

  • You use qfoo.h style include, whereas QFoo is the common usage pattern.

  • You do not utilize the new signal-slot syntax.

This is the working version for me:

main.cpp

#include <glew.h>

#include <QApplication>
#include <QGLWidget>
#include <QTimer>

class GLWin Q_DECL_FINAL : public QGLWidget
{
    Q_OBJECT
    GLuint vertexBufferID;
    QTimer myTimer;

protected:
    void initializeGL() Q_DECL_OVERRIDE
    {
        GLenum errorCode = glewInit();
        Q_ASSERT(errorCode == 0);

        glGenBuffers(1, &vertexBufferID);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);

        float verts[] =
        {
            0.0f, 0.1f,
            -0.1f, -0.1f,
            0.1f, -0.1f,
        };

        glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);

        QTimer* timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &GLWin::updateWin);
        timer->start();
    }

    void paintGL() Q_DECL_OVERRIDE
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);  
        glDrawArrays(GL_TRIANGLES, 0, 3);   
    }
private slots:
    void updateWin() {}
};

#include "main.moc"

int main(int argc, char **argv)
{
    QApplication application(argc, argv);
    GLWin MyGL;
    MyGL.show();
    return application.exec();
}

main.pro

TEMPLATE = app
TARGET = main
QT += widgets opengl
SOURCES += main.cpp
packagesExist(glew) {
    CONFIG += link_pkgconfig
    PKGCONFIG += glew
}

Build and Run

qmake && make && ./main

Upvotes: 3

Related Questions