I'm trying to use GLEW with QT in a QOpenGLWidget in Visual Studio.
Some details:
Visual Studio 2013
Glew 2.0.0 x64
QT 5.6.2 x64
I keep getting "Missing GL version" error when calling glewInit(). I've searched online a lot, and this problem seems to sometimes be caused by how the format is set (QSurfaceFormat), or how the functions create()/ makeCurrent() / doneCurrent() are used. But I can't seem to find a working solution. I'm still a bit confused about the whole QOpenGLContext thing also.
I manage to get the QOpenGLWidget work without GLEW, and using "old" gl functions (glBegin(), glEnd(), etc...). And I also get GLEW to work with GLFW3.
Is there something I seem to misunderstand in the code below?
My subclass of QOpenGLWidget
MyGLWidget.h
#pragma once
#include <QWidget>
#include "GL\glew.h"
#include <QOpenGLWidget>
#include <gl/GLU.h>
#include <gl/GL.h>
#include <iostream>
#include "qopenglcontext.h"
#include "loadShader.h"
class MyGLWidget : public QOpenGLWidget
{
public:
MyGLWidget(QWidget *parent = 0);
~MyGLWidget();
public:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
};
MyGLWidget.cpp
#include "MyGLWidget.h"
MyGLWidget::MyGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
QSurfaceFormat glformat;
glformat.setVersion(3, 2);
glformat.setOption(QSurfaceFormat::DeprecatedFunctions);
glformat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
glformat.setProfile(QSurfaceFormat::CompatibilityProfile);
QSurfaceFormat::setDefaultFormat(glformat);
this->setFormat(glformat);
create();
makeCurrent();
}
MyGLWidget::~MyGLWidget(){}
void MyGLWidget::initializeGL()
{
glewExperimental = TRUE;
GLenum err = glewInit();
if (GLEW_OK != err){
std::cout << "[Error] GLEW failed to initialize. " << (const char*)glewGetErrorString(err);
}
doneCurrent();
GLuint TextShader_ID = LoadShaders("Shaders/TextVertShader.vert", "Shaders/TextFragShader.frag");
}
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void MyGLWidget::resizeGL(int w, int h)
{
//...
}
main.cpp
#include "OGLQT_test2.h"
#include <QtWidgets/QApplication>
#include "GL\glew.h"
#include <QOpenGLFunctions>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
OGLQT_test2 w;
w.show();
return a.exec();
}
OGLQT_test2.h
#pragma once
#include "GL\glew.h"
#include <QtWidgets/QMainWindow>
#include "ui_OGLQT_test2.h"
#include "qopenglcontext.h"
class OGLQT_test2 : public QMainWindow
{
Q_OBJECT
public:
OGLQT_test2(QWidget *parent = Q_NULLPTR);
private:
Ui::OGLQT_test2Class ui;
};
OGLQT_test2.cpp
#include "OGLQT_test2.h"
#include "MyGLWidget.h"
OGLQT_test2::OGLQT_test2(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
MyGLWidget* glwidget = new MyGLWidget(this);
glwidget->setFixedHeight(400);
glwidget->setFixedWidth(500);
glwidget->move(50, 50);
glwidget->initializeGL();
glwidget->resizeGL(400,500);
glwidget->paintGL();
}
It seems that you cannot do this:
glformat.setVersion(x, y);
with GLEW. It works with QOpenGLFunctions, but apparently, it doesn't work with GLEW. You may not be able to do this, either:
glformat.setOption(QSurfaceFormat::DeprecatedFunctions);
glformat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
glformat.setProfile(QSurfaceFormat::CompatibilityProfile);
Try removing the format.
Also, I think you're doing a little bit of a mess here:
glwidget->initializeGL();
glwidget->resizeGL(400,500);
glwidget->paintGL();
There is a simple way to do this, just do:
glwidget->resize(400,500);
glwidget->show();
resizeGL is an event called by resize. That goes the same for initializeGL() and paintGL() being called by show.
Another one is:
GLenum err = glewInit();
if (GLEW_OK != err){
std::cout << "[Error] GLEW failed to initialize. " << (const char*)glewGetErrorString(err);
}
doneCurrent();
Now why would you call doneCurrent here?
Related
I observed that through task mgr, the memory increases in steps of 4kB and 8kB, though not necessarily in this order.
Possible duplicate: Windows Task Manager shows process memory keeps growing even though there are no memory leaks
I am not sure whether this's occurring because I did not release the QTimer object, timer2. Please advise me how to stop this memory increase, and whether my guess of why it's occurring, is correct.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCore>
#include <QDebug>
#include <QDateTime>
#include <QFileInfo>
#include <QString>
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#define TIMER2_VALUE 3000
#define UPDATED_IMAGE_STORAGE_PATH "E:\\QT1\\timeStampDateMod2\\TimeStampDateMod2\\updatedRefImg.JPG"
#define UPDATED_IMAGE_BACKUP_PATH "E:\\QT1\\timeStampDateMod2\\TimeStampDateMod2\\backUp\\updatedRefImg[%1].JPG"
using namespace std;
using namespace cv;
typedef struct
{
QDateTime dateTimeMod1;
QDateTime dateTimeMod2;
}tTimeMods;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QTimer *timer2;
tTimeMods findTimeModifiedStruct();
QDateTime findTimeModified();
void compareTimeMods(tTimeMods timeTypeFunction, QDateTime dateTimeMod2);
QString appendWithImageName(tTimeMods timeTypeFunction);
void shiftToRepository(QString pathString);
void updatedImgToRepository(QString pathString);
public slots:
void timerSlot2();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
tTimeMods timeTypeFunction, timeTypeMain;
QDateTime dateTimeMod2;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timeTypeMain = findTimeModifiedStruct();
timer2 = new QTimer(this);
connect(timer2, SIGNAL(timeout()), this, SLOT(timerSlot2()));
timer2->start(TIMER2_VALUE);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::timerSlot2()
{
dateTimeMod2 = findTimeModified();
compareTimeMods(timeTypeMain, dateTimeMod2);
//delete timer2;
}
//tTimeMods findTimeModifiedStruct()
tTimeMods MainWindow::findTimeModifiedStruct()
{
QString myFileName = UPDATED_IMAGE_STORAGE_PATH;
QFileInfo info(myFileName);
/*find last date modified*/
timeTypeFunction.dateTimeMod1 = info.lastModified();
timeTypeFunction.dateTimeMod2 = info.lastModified();
qDebug()<< "dateTimeMod1: " << timeTypeFunction.dateTimeMod1.toString() << endl << "dateTimeMod2: "<< timeTypeFunction.dateTimeMod2.toString();
return(timeTypeFunction);
}
QDateTime MainWindow::findTimeModified()
{
QString myFileName = UPDATED_IMAGE_STORAGE_PATH;
QFileInfo info(myFileName);
QDateTime dateTimeMod2 = info.lastModified();
qDebug()<< "dateTimeMod2: "<< dateTimeMod2.toString();
return(dateTimeMod2);
}
void MainWindow::compareTimeMods(tTimeMods timeTypeFunction, QDateTime dateTimeMod2)
{
if(dateTimeMod2 >= timeTypeFunction.dateTimeMod1)
{
timeTypeFunction.dateTimeMod1 = dateTimeMod2;
QString pathString = appendWithImageName(timeTypeFunction);
shiftToRepository(pathString);
}
}
QString MainWindow::appendWithImageName(tTimeMods timeTypeFunction)
{
/*appending just the timeMod with the path & image name*/
QString path = QString(UPDATED_IMAGE_BACKUP_PATH).arg(timeTypeFunction.dateTimeMod1.toString());
qDebug()<< "path: " << path;
return path;
}
void MainWindow::shiftToRepository(QString pathString)
{
updatedImgToRepository(pathString);
}
void MainWindow::updatedImgToRepository(QString pathString)
{
pathString.replace(":","-");
pathString.replace(1,1,":");
qDebug()<<"pathString now: "<<pathString;
/*convert QString into char* */
QByteArray pathByteArray = pathString.toLocal8Bit();
const char *path = pathByteArray.data();
IplImage *InputImg = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
InputImg = cvLoadImage(UPDATED_IMAGE_STORAGE_PATH ,CV_LOAD_IMAGE_UNCHANGED);
/*save the image*/
cvSaveImage(path,InputImg);
cvReleaseImage(&InputImg);
}
I'm not familiar with OpenCV, but it seems that these two lines cause you memory leak:
IplImage *InputImg = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
InputImg = cvLoadImage(UPDATED_IMAGE_STORAGE_PATH ,CV_LOAD_IMAGE_UNCHANGED);
In the first line you are creating an object, but in the second you are assigning another object to the pointer without releasing the previous one, so the previous one gets leaked.
Is creating an image even needed, while you are going to load it?
I have been trying to use Qt5 to give me an OpenGL context, which I believe it does, but when I try to call glewInit() from within the initializeGL function, the error returns back "Missing GL version," which I have been led to believe indicates that there is no valid context. The solution I saw was to call glewInit() from within initializeGL... but I'm already doing that.
I am setting the clear color and clearing to dark red to verify that gl calls are working, which they appear to be.
Any suggestions?
main.c
#define QT_NO_OPENGL_ES_2
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GLWidget w;
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <GL/glew.h>
#define QT_NO_OPENGL_ES_2
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QGLWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QGLWidget *parent) :
QGLWidget(parent)
{
}
GLWidget::~GLWidget() {}
QSize GLWidget::minimumSizeHint() const {
return QSize(640, 480);
}
QSize GLWidget::sizeHint() const {
return QSize(800, 600);
}
void GLWidget::initializeGL() {
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("GLEW error: %s\n", glewGetErrorString(err));
} else {
printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION));
}
glClearColor(0.2f, 0, 0, 1.0f);
}
void GLWidget::resizeGL(int w, int h) {
}
void GLWidget::paintGL() {
glClear( GL_COLOR_BUFFER_BIT );
}
Something tells me this is because of the QGLWidget's default QGLFormat using OpenGL version 1.0 (Looking through GLEW's change logs, it seems the earliest version they claim to fully support is 1.5) . Try instead to override the QGLWidget constructor that requires a QGLFormat and pass it an instance of QGLFormat that uses the version you are targeting.
The call to your widget should look something like:
QGLFormat format;
format.setVersion(3,3); // or whatever version you are targeting.
format.setDoubleBuffer(true);
GLWidget * widget = new GLWidget(format);
I tried declaring a signal in a prototype and then connecting it is script funcition for some reason it does not work as I hoped. My code is as follows. Could some one help me in this.
What I expected was, once I called p.setText('New String') in the script code, since setText emits the textChanged signal it should invoke the slot which is catchSignal(text) already connected in the script code.
Prototype header
#ifndef SCRIPTACTION_H
#define SCRIPTACTION_H
#include <QObject>
#include <QtScript>
class ScriptAction : public QObject , public QScriptable
{
Q_OBJECT
public:
ScriptAction(QObject *parent = 0);
signals:
void textChanged(const QString changedString);
};
#endif // SCRIPTACTION_H
Class
#include "scriptaction.h"
#include <QAction>
Q_DECLARE_METATYPE(QAction*)
ScriptAction::ScriptAction(QObject *parent) : QObject(parent)
{
}
Main Class
#include <QApplication>
#include <QDebug>
#include <QAction>
#include "scriptaction.h"
#include <QPushButton>
Q_DECLARE_METATYPE(QAction*)
QScriptValue qAction_Constructor(QScriptContext *ctx, QScriptEngine *eng)
{
qDebug() << "QAction is called";
if(ctx->isCalledAsConstructor())
{
QObject *parent = ctx->argument(0).toQObject();
QAction *action = new QAction("Test",parent);
return eng->newQObject(action, QScriptEngine::ScriptOwnership);
} else {
return QString("invalid call. Use new Constructor");
}
}
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QScriptEngine engine;
//Evaluating a simaple expresssion
qDebug() << engine.evaluate("1+2").toNumber();
QPushButton button;
QScriptValue buttonScript= engine.newQObject(&button);
engine.globalObject().setProperty("button", buttonScript);
engine.evaluate("button.text ='Hello Text'; button.show()");
//QAction Prototype
ScriptAction qsAction ;
QScriptValue script_proto = engine.newQObject(&qsAction);
engine.setDefaultPrototype(qMetaTypeId<QAction*>(), script_proto);
QScriptValue ctor = engine.newFunction(qAction_Constructor , script_proto);
QScriptValue metaObject = engine.newQMetaObject(&QObject::staticMetaObject, ctor);
engine.globalObject().setProperty("QSAction" , metaObject);
engine.evaluate("var p = new QSAction(button);p.textChanged.connect(catchSignal);");
engine.evaluate("function catchSignal(text) { print ('PROTOTYPE SIGNAL IS CALLED ',text); } p.setText('New String'); " );
return app.exec();
}
I got rid of the issue, and now I see the signal is being triggered and slot is called properly.
All I did was moving the code to a separate script file and start using the QScriptDebugger to see its output. Then I figured there was an error and the code is edited to work.
Anyone who wants an example prototype class, this will hopefully be a good guideline.
I derived a class from QTextEdit and use it as a "logbook". I equipped it with a slot to receive log-messages.
class CLogbook : public QTextEdit
{
Q_OBJECT;
public:
void log(QString msg) {append(msg)};
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n";
log(message);
}
};
another class then emits a signal like this:
// in the header
signals:
void logMessage(const QString);
// in the implementation
emit logMessage("qt is cute");
std::cout << "if you can read this the logMessage was emitted\n";
and also i connect the signal to the slot
connect(tableeditor, SIGNAL(logMessage(const QString)), logbook, SLOT(recvLogSignal(const QString)));
However the message is never shown in the "logbook". What am i missing here?
SOLVED: The connect method was called after emitting the signal :-(
It is hard to see exactly what is wrong with your implementation without a full example. Sometimes signals or slots will fail if an object goes out of scope if it isn't initialized on the heap.
Another way that it could fail is if your QApplication hasn't reached the exec() call.
I haven't experimented with using const in signal and slot calls, and I haven't seen it in any examples before, so that could be causing the problem; but it seems to work fine in the example below.
Working Example With a Derived Class of QTextEdit
Here is a simple example I put together that does some basic logging with a push button and a line edit.
Here is the header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
//#include <QTextEdit>
#include "clogbook.h"
#include <QLineEdit>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget() {}
public slots:
void on_pushButton();
void on_lineEditReturn();
private:
CLogBook * text_edit_log;
QLineEdit * line_edit;
};
#endif // WIDGET_H
Here is the source:
#include "widget.h"
#include <QBoxLayout>
#include <QPushButton>
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QBoxLayout * box_layout = new QBoxLayout(QBoxLayout::TopToBottom);
text_edit_log = new CLogBook;
line_edit = new QLineEdit("Type Here and press Enter.");
QPushButton * push_button = new QPushButton("Click to Add To Log");
text_edit_log->setText("My Log Book");
box_layout->addWidget(text_edit_log);
box_layout->addWidget(line_edit);
box_layout->addWidget(push_button);
this->setLayout(box_layout);
QObject::connect(push_button, SIGNAL(clicked()), this, SLOT(on_pushButton()));
QObject::connect(line_edit, SIGNAL(returnPressed()), this, SLOT(on_lineEditReturn()));
}
void Widget::on_pushButton()
{
// text_edit_log->append("Push Button Logging Test");
text_edit_log->recvLogSignal("Push button test.");
}
void Widget::on_lineEditReturn()
{
// text_edit_log->append(line_edit->text());
text_edit_log->recvLogSignal(QString("LineEdit: ") + line_edit->text() );
line_edit->clear();
}
And here is the main:
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
And here is the CLogBook class:
#ifndef CLOGBOOK_H
#define CLOGBOOK_H
#include <QTextEdit>
#include <iostream>
class CLogBook : public QTextEdit
{
Q_OBJECT
public:
explicit CLogBook(QWidget *parent = 0) : QTextEdit(parent) { }
void log (QString msg) { append(msg); }
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n" << std::endl;
log(message);
}
};
#endif // CLOGBOOK_H
How do I detect if my application has been suspended (when someone changes applications) and react by deactivating my timer and then re-activating it when my application becomes un-suspended (when someone re-opens my half running app). Beneath Is how far I have coded so far on this part my app but it gives an error: "'QApplication::QApplication(const QApplication&)' is private" and it says within the context of myapp.cpp line 4. Please if anyone can tell me what I'm doing wrong it would be greatly appreciated.
Here is my code for the main.cpp:
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include <QObject>
#include <QGraphicsObject>
#include <QTimer>
#include <QVariant>
#include "timecontrol.h"
#include "scorecontrol.h"
#include "Retry.h"
#include <QEvent>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationLockLandscape);
viewer.setMainQmlFile(QLatin1String("qml/Raker/main.qml"));
viewer.showExpanded();
QObject *rootObject = viewer.rootObject();
QTimer *timmer = new QTimer;
timmer->setInterval(1000);
TimeControl *timcon = new TimeControl;
scorecontrol *scorer = new scorecontrol;
Retry *probeer = new Retry;
QObject::connect(timmer, SIGNAL(timeout()), timcon, SLOT(updateTime()));
QObject::connect(timcon, SIGNAL(setTime(QVariant)), rootObject, SLOT(setTime(QVariant)));
QObject::connect(rootObject, SIGNAL(blockClicked(int, int)), scorer, SLOT(checkRight(int, int)));
QObject::connect(scorer, SIGNAL(setScore(QVariant)), rootObject, SLOT(setScore(QVariant)));
QObject::connect(scorer, SIGNAL(setState(QVariant)), rootObject, SLOT(setState(QVariant)));
QObject::connect(rootObject, SIGNAL(start()), probeer, SLOT(Reetry()));
QObject::connect(probeer, SIGNAL(start()), timmer, SLOT(start()));
QObject::connect(probeer, SIGNAL(start(int)), scorer, SLOT(randomNum(int)));
QObject::connect(probeer, SIGNAL(sReset()), timcon, SLOT(reset()));
QObject::connect(probeer, SIGNAL(tReset()), scorer, SLOT(reset()));
QObject::connect(timcon, SIGNAL(timeOut()), scorer, SLOT(reset()));
QObject::connect(timcon, SIGNAL(setState(QVariant)), rootObject, SLOT(setState(QVariant)));
QObject::connect(timcon, SIGNAL(changeFinal()), scorer, SLOT(changeFinal()));
QObject::connect(scorer, SIGNAL(setFinal(QVariant)), rootObject, SLOT(setFinal(QVariant)));
return app.exec();
}
myApp.h:
#ifndef MYAPP_H
#define MYAPP_H
#include <QApplication>
#include <QObject>
class MyApp : public QApplication
{
public:
MyApp(QApplication &app);
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
#endif // MYAPP_H
myapp.cpp:
#include "myapp.h"
#include <QEvent>
MyApp::MyApp(QApplication &app) : QApplication(app)
{
installEventFilter(this);
}
bool MyApp::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::ApplicationDeactivate)
{
}
if (event->type() == QEvent::ApplicationDeactivate)
{
}
else
{
return false;
}
}
Add an event filter to check for the activate and deactivate events. From the QEvent documentation:
QEvent::ApplicationActivate 121 The application has been made available to the user.
QEvent::ApplicationDeactivate 122 The application has been suspended, and is unavailable to the user.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->comboBox->installEventFilter(this);
.
.
.
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::ApplicationDeactivate)
{
// Deactivate timer
}
if (event->type() == QEvent::ApplicationActivate)
{
// Turn timer back on
}
return false;
}
QEvent::AppliciationActivate and QEvent::ApplicationDeactivate have been deprecated (see here). Instead, use QEvent::ApplicationStateChange. There is no need to use an event filter to utilise this; just connect to QGuiApplication::applicationStateChanged(Qt::ApplicationState) and handle it as appropriate.