Qt just draw the first frame using QGLWidget from QT - qt

I coded a small QT program using QGLWidget. The goal is to display a simple triangle in permanent rotation. The problem is that there is no animation because just the first frame is rendered.
Here's my main C++ source code :
#include "qtapplication.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtApplication w;
w.show();
return a.exec();
}
My qtapplication.h file :
include <QtWidgets/QMainWindow>
#include "ui_qtapplication.h"
#include "HSGLWidget.hpp"
class QtApplication : public QMainWindow
{
Q_OBJECT
public:
QtApplication(QWidget *parent = 0);
~QtApplication();
private:
Ui::QtApplicationClass ui;
HSGLWidget *_glwidget;
};
My qtapplication.cpp file :
#include "qtapplication.h"
QtApplication::QtApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->_glwidget = NULL;
if (this->_glwidget == NULL)
this->_glwidget = new HSGLWidget();
this->_glwidget->setVisible(true);
setCentralWidget(this->_glwidget);
}
QtApplication::~QtApplication()
{
}
My HSGLWidjet.h file:
#include <QGLWidget>
class HSGLWidget : public QGLWidget {
Q_OBJECT
public:
explicit HSGLWidget(QWidget *parent = 0);
virtual ~HSGLWidget();
protected:
virtual void initializeGL();
virtual void resizeGL(int width, int height);
virtual void paintGL();
virtual void keyPressEvent(QKeyEvent *keyEvent);
private:
void _onSetup();
private:
QTimer *_timer;
};
And my HSGLWidjet.cpp file:
#include <iostream>
#include "HSGLWidget.hpp"
float toto_angle = 0.0f;
HSGLWidget::HSGLWidget(QWidget *parent)
: QGLWidget(parent)
{
this->_onSetup();
}
HSGLWidget::~HSGLWidget(void)
{
}
void HSGLWidget::initializeGL()
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.20f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
void HSGLWidget::resizeGL(int width, int height)
{
if (height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void HSGLWidget::paintGL(void)
{
std::cout << "PAINTGL" << std::endl;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f, 0.0f, -6.0f);
glEnable(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0.0f, 0.0f, 0.0f);
glRotatef(toto_angle, 1.0f, 1.0f, 1.0f);
glScalef(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3ub(255, 0, 0);
glVertex3f(0.0f, 0.75f, 0.0f);
glColor3ub(0, 255, 0);
glVertex3f(-0.75f, 0.0f, 0.0f);
glColor3ub(0, 0, 255);
glVertex3f(0.75f, 0.0f, 0.0f);
glEnd();
toto_angle+=1.0f;
glPopMatrix();
}
void HSGLWidget::keyPressEvent(QKeyEvent *keyEvent)
{
}
void HSGLWidget::_onSetup()
{
}
The string 'PAINTGL' is written just for the first frame. Normally, paintGL is called automatically. I'm really lost in front of this situation. Does anyone can help me, please ? Thanks a lot in advance for your help.

There's no problem at all, that's the standard behavior.
You see, paint() and paintGL() are called only when the window needs to be draw. That is: when your application is created, when the window is resized, or moved around. Only then paintGL() is triggered. That's it!
If you want it to be called more than once, you will need to add a timer to execute update(), which is a method that forces the window to be redraw, which in turn triggers paintGL(). Do not call paintGL() directly!
QTimer can help you achieve what you are looking for!

Related

How to add QOpenGLWidget to QGraphicsScene?

My main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);
MyGLWidget w;
w.setFormat(format);
QGraphicsScene scene;
QGraphicsProxyWidget* proxy = scene.addWidget(&w);
scene.addText("Hello");
QGraphicsView view(&scene);
view.show();
return a.exec();
}
My MyGLWidget.h
class MyGLWidget :
public QOpenGLWidget
, protected QOpenGLFunctions
{
public:
MyGLWidget(QWidget* parent = nullptr);
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
};
MyGLWidget.cpp
MyGLWidget::MyGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
}
void MyGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
}
void MyGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
QPainter p(this);
p.drawText(rect(), Qt::AlignCenter, "Testing");
p.drawEllipse(100, 100, 100, 100);
}
Output image.
It seems that void MyGLWidget::paintGL() wasnt called. How do I call paintGL? Can I set it to auto update rendering?
Also, I get weird exception.
If I made changes like this,
MyGLWidget w;
w.setFormat(format);
w.show();
//QGraphicsScene scene;
//QGraphicsProxyWidget* proxy = scene.addWidget(&w);
//scene.addText("Hello");
//QGraphicsView view(&scene);
//view.show();
I get this. Which means that OpenGL rendering works fine.

QT5 and opengl core profile not show me simple shader

i'm a new member and i have a question.
I want to develope a simple project with QT5 and opengl core profile for an end term project.
I first tried with a simple example but nothing happen. The screen show me only the red background but not the shader that i have write.
the code is the following:
main.cpp
#include <QApplication>
#include <QGLFormat>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//specify oepngl version and other stuff
QGLFormat glFormat;
glFormat.setVersion(4, 3);
glFormat.setProfile(QGLFormat::CoreProfile);
glFormat.setSampleBuffers(true);
GLWidget w(glFormat);
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
#include <QGLBuffer>
#include <QGLShaderProgram>
#include <QOpenGLVertexArrayObject>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
GLWidget(const QGLFormat& format, QWidget* parent = 0);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
//virtual void keyPressEvent(QKeyEvent* e);
private:
bool prepareShaderProgram(const QString& vertexShaderPath, const QString& fragmentShaderPath);
QGLShaderProgram m_shader;
QGLBuffer m_vertexBuffer;
GLuint vertex_array_object;
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(const QGLFormat& format, QWidget* parent)
:QGLWidget(format, parent),
m_vertexBuffer(QGLBuffer::VertexBuffer)
{
}
void GLWidget::initializeGL()
{
QGLFormat glFormat = QGLWidget::format();
if(!glFormat.sampleBuffers())
qWarning() << "Can't enable sample buffers";
//set background color
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
//load the shaders
if(!prepareShaderProgram("/home/sera/workspace/qtWorkspace/provaShader/simple.vert",
"/home/sera/workspace/qtWorkspace/provaShader/simple.frag"))
return;
//create and bind the vertex buffer to the context
m_vertexBuffer.create();
if(!m_vertexBuffer.bind())
{
qWarning() << "could not bind vertex buffer to the opengl context";
return;
}
//bind program to the context
if(!m_shader.bind())
{
qWarning() << "could not bind shader program to the context";
return;
}
}
bool GLWidget::prepareShaderProgram(const QString &vertexShaderPath, const QString &fragmentShaderPath)
{
//load and compile shaders
bool result = m_shader.addShaderFromSourceFile(QGLShader::Vertex, vertexShaderPath);
if(!result)
qWarning() << m_shader.log();
result = m_shader.addShaderFromSourceFile(QGLShader::Fragment, fragmentShaderPath);
if(!result)
qWarning() << m_shader.log();
//link shaders into program
result = m_shader.link();
if(!result)
qWarning() << "could not link shader program" << m_shader.log();
return result;
}
void GLWidget::resizeGL(int w, int h)
{
//set the viewport
glViewport(0, 0, w, qMax(h, 1));
}
void GLWidget::paintGL()
{
//clear buffer with current color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPointSize(40.0);
glDrawArrays(GL_POINTS, 0, 1);
}
/*
void GLWidget::keyPressEvent( QKeyEvent* e )
{
switch (e->key())
{
case Qt::Key_Escape:
QCoreApplication::instance()->quit();
break;
default:
QGLWidget::keyPressEvent( e );
}
}
*/
simple.vert
#version 430 core
void main(void)
{
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
}
simple.frag
#version 430 core
out vec4 color;
void main(void)
{
color = vec4(1.0, 1.0, 1.0, 1.0);
}
And the result is this in the figure, but i'm aspected a point in the middle
result
What is wrong?

How to draw a linear gradient arc with Qt QPainter?

I'm trying to develop a custom QProgressBar that will look like the following image :
I created a class that extends QProgressBar and implemented the paintEvent() :
void CircularProgressBar::paintEvent(QPaintEvent*) {
int progress = this->value();
int progressInDegrees = (double)(progress*360)/100;
int barWidth = 20;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, barWidth, Qt::SolidLine,Qt::RoundCap));
painter.drawArc(barWidth/2, barWidth/2, this->width() - barWidth, this->height() - barWidth,
90*16, progressInDegrees*-16);}
This works great to draw the circular progress bar, but I'm having trouble with the linear gradient color of the bar. I tried creating a QPen with a QLinearGradient object and I tried setting the QPainter brush to a QLinearGradient object, but neither strategy worked. Is it possible to draw an arc with QPainter that has a linear gradient color?
I know this is an old question but I came across it some days ago and I think I have a solution. What you want is to create a conical gradient and clip the disk you want to use as circular loading bar. Here is an example:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QPaintEvent;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void setLoadingAngle(int loadingAngle);
int loadingAngle() const;
void setDiscWidth(int width);
int discWidth() const;
protected:
void paintEvent(QPaintEvent *);
private:
int m_loadingAngle;
int m_width;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QConicalGradient>
#include <QPen>
Widget::Widget(QWidget *parent) :
QWidget(parent),
m_loadingAngle(0),
m_width(0)
{
}
Widget::~Widget()
{
}
void Widget::setLoadingAngle(int loadingAngle)
{
m_loadingAngle = loadingAngle;
}
int Widget::loadingAngle() const
{
return m_loadingAngle;
}
void Widget::setDiscWidth(int width)
{
m_width = width;
}
int Widget::discWidth() const
{
return m_width;
}
void Widget::paintEvent(QPaintEvent *)
{
QRect drawingRect;
drawingRect.setX(rect().x() + m_width);
drawingRect.setY(rect().y() + m_width);
drawingRect.setWidth(rect().width() - m_width * 2);
drawingRect.setHeight(rect().height() - m_width * 2);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QConicalGradient gradient;
gradient.setCenter(drawingRect.center());
gradient.setAngle(90);
gradient.setColorAt(0, QColor(178, 255, 246));
gradient.setColorAt(1, QColor(5, 44, 50));
int arcLengthApproximation = m_width + m_width / 3;
QPen pen(QBrush(gradient), m_width);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
painter.drawArc(drawingRect, 90 * 16 - arcLengthApproximation, -m_loadingAngle * 16);
}
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setDiscWidth(20);
w.setLoadingAngle(270);
w.show();
return a.exec();
}
And the result is:
Of course, it is not the complete and exact solution but I think it is everything you need to know in order to achieve what you want. The rest are details not hard to implement.
This solution is not exactly what you're after; the gradient goes from top to bottom, rather than around the circle:
#include <QtWidgets>
class Widget : public QWidget
{
public:
Widget() {
resize(200, 200);
}
void paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const QRectF bounds(0, 0, width(), height());
painter.fillRect(bounds, "#1c1c1c");
QPen pen;
pen.setCapStyle(Qt::RoundCap);
pen.setWidth(20);
QLinearGradient gradient;
gradient.setStart(bounds.width() / 2, 0);
gradient.setFinalStop(bounds.width() / 2, bounds.height());
gradient.setColorAt(0, "#1c1c1c");
gradient.setColorAt(1, "#28ecd6");
QBrush brush(gradient);
pen.setBrush(brush);
painter.setPen(pen);
QRectF rect = QRectF(pen.widthF() / 2.0, pen.widthF() / 2.0, width() - pen.widthF(), height() - pen.widthF());
painter.drawArc(rect, 90 * 16, 0.65 * -360 * 16);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Widget w;
w.show();
return app.exec();
}
However, it is an arc with a linear gradient! :p

How to use glewInit function from glew.h with QT?

I coded a small QT application (version 5.1.0 (msvc2012_64_opengl), Add-in 1.2.2) in Visual studio 2012. I started with GLU.h include and the program works perfectly. But I want to implement some functions from glew.h. The first thing to do in this case is to call the 'glewInit' method a the top of the 'initializeGL' QT method. But I have the following error :
error lnk2019 unresolved external symbol __glewInit
But I noticed that the code is well exectuted without glewInit but with the #include "glew.h" and not #include "glu.h". So the linkage in the project properties are correct (glu32.lib). So the problem seems to comes from the interaction between QT and my own include of glew.h (I want to say I use glew.h since lots of time without any problem but NOT with QT).
Here's my c++ header file :
#include <gl/glew.h>
#define QT_NO_OPENGL_ES_2
#include <QGLWidget>
//#include <QtOpenGL\qgl.h>
//#include <qtopengl.h>
class HSGLWidget : public QGLWidget {
Q_OBJECT
public:
explicit HSGLWidget(QWidget *parent = 0);
virtual ~HSGLWidget();
protected:
virtual void initializeGL();
virtual void resizeGL(int width, int height);
virtual void paintGL();
virtual void keyPressEvent(QKeyEvent *keyEvent); /// From QWidget
private:
void _onSetup();
private:
QTimer *_timer;
};
My C++ source file :
#include "HSGLWidget.hpp"
#define QT_NO_OPENGL_ES_2
HSGLWidget::HSGLWidget(QWidget *parent)
: QGLWidget(parent) {
this->_onSetup();
}
HSGLWidget::~HSGLWidget() {
}
void HSGLWidget::initializeGL() {
glewInit();
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.20f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
void HSGLWidget::resizeGL(int width, int height) {
if (height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void HSGLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f, 0.0f, -6.0f);
glBegin(GL_TRIANGLES);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glEnd();
glTranslatef(3.0f, 0.0f, -6.0f);
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glVertex3d(1.0f, 1.0f, 0.0f);
glEnd();
}
And my main :
#include <QApplication>
#include "HSGLWidget.hpp"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
HSGLWidget myWin;
myWin.show();
return app.exec();
}
I tried to use #define QT_NO_OPENGL_ES_2 declaration just below my glew.h include definition but it still the same thing. I 'm really lost in front of this situation.
Does anyone can help me?
Linking failure?
Project options-> Linker-> Input
Put there the glew(For example on my project: glew32.lib)
Hope this helped you

Displaying a triangle with Qt and OpenGL

I am trying to display a triangle with OpenGL and Qt but only get a black window.
What am I doing wrong?
glwidget.h:
#pragma once
#include <QGLWidget>
class GLWidget : public QGLWidget {
public:
GLWidget(QWidget *parent = 0);
~GLWidget();
QSize sizeHint() const { return QSize(400, 400); }
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
glwidget.cpp:
#include "glwidget.h"
GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent) {}
GLWidget::~GLWidget(){ }
void GLWidget::initializeGL() { }
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
}
void GLWidget::resizeGL(int w, int h)
{
QGLWidget::resize(w,h);
}
main.cpp:
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GLWidget glWidget;
glWidget.show();
return app.exec();
}
You must set a viewport and projection at the beginning of the paintGL member function. Put this at the beginning of your paintGL:
QSize viewport_size = size();
glViewport(0, 0, viewport_size.width(), viewport_size.height());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1, 1, -1, 1, 5, 7); // near and far match your triangle Z distance
glMatrixMode(GL_MODELVIEW);
Also if the window is double buffered, the buffers must be swapped, after drawing. Either set
setAutoBufferSwap(true);
in the constructor, to swap after paintGL returns, or add
swapBuffers();
at the end of paintGL.
triangle is transform out the form
glTranslatef(-0.5f,0.0f, 0.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 0.2f, 0.0f);
glVertex3f(-0.2f,-0.2f, 0.0f);
glVertex3f( 0.2f,-0.2f, 0.0f);
glEnd();

Resources