So I have this program should uses a QGLWidget, I'm still relatively new to using OpenGL and QT so I started following this tutorial. However the background of my QGLWidget won't change no matter what I do (I'm using ubuntu not windows). Do I need to create a class for it inside the mainWindow.cpp or is what I've done enough for it to work?
This is what is shown when the program is executed. The QGLWidget on the right is completely black when it show be yellow with a red triangle
Here is the promoted widget of the QGLWidget which is linked to the drawingArea class
Finally here's the code from the drawing area. It compiles fine and I cant see anything wrong with the logic hence my confusion.
drawingarea.h
#ifndef DRAWINGAREA_H
#define DRAWINGAREA_H
#include <QGLWidget>
#include <QOpenGLWindow>
#include <QSurfaceFormat>
#include <QOpenGLFunctions>
#include <QtOpenGL>
#include <GL/glu.h>
class drawingArea : public QGLWidget
{
public:
drawingArea(QWidget *parent=0);
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
void paintEvent(QPaintEvent *event);
private:
QOpenGLContext *context;
QOpenGLFunctions *openGLFunctions;
};
#endif // DRAWINGAREA_H
drawingarea.cpp
#include "drawingarea.h"
drawingArea::drawingArea(QWidget *parent) : QGLWidget(parent)
{
}
void drawingArea::initializeGL()
{
glClearColor(1,1,0,1);
}
void drawingArea::resizeGL(int w, int h)
{
}
void drawingArea::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0);
glVertex3f(0.5,-0.5,0);
glVertex3f(0,0.5,0);
glEnd();
}
void drawingArea::paintEvent(QPaintEvent *event)
{
}
Related
I'm currently trying to learn how to use QTWidgets (version 6.4.2) in C++ in VS2022. Right now, I'm trying to just run a simple ui I created in the QT designer. On the window, I have a QOpenGLWidget that I want to use to display graphics. I have this widget promoted as a MyOpenGLWidget. My issue is that when I call "initializeOpenGLFunctions()" in "initializeGL()" the code breaks with the following error:
ASSERT: "context" in file qopenglfunctions.cpp, line 155
I've tried looking through the QOpenGLFunctions page on the qt website and couldn't find any information related to this.
Here is my code:
MyOpenGLWidget.h
#pragma once
#include <QOpenGLWidget>
#include <qopenglfunctions>
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit MyOpenGLWidget(QWidget* parent = nullptr) : QOpenGLWidget(parent)
{
initializeGL();
}
~MyOpenGLWidget()
{
}
void Initialize()
{
initializeGL();
}
protected:
void initializeGL()
{
initializeOpenGLFunctions(); // Code breaks when this is called
}
void paintGL() {}
void resizeGL(int w, int h) {}
};
QT_OpenGL.h
class QT_OpenGL : public QMainWindow
{
Q_OBJECT
public:
QT_OpenGL(QWidget *parent = nullptr);
~QT_OpenGL();
private:
Ui::QT_OpenGLClass * ui;
protected:
};
QT_OpenGL.cpp
#include "QT_OpenGL.h"
QT_OpenGL::QT_OpenGL(QWidget *parent)
: QMainWindow(parent)
{
ui = new Ui::QT_OpenGLClass();
ui->setupUi(this);
}
QT_OpenGL::~QT_OpenGL()
{}
main.cpp
#include "QT_OpenGL.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QT_OpenGL w;
w.show();
return a.exec();
}
Thanks to #holtavolt 's comment, I was able to gain some insight from the example he provided and therefore was able to do some more digging until I found this QOpenGLWidget's context is null post. The problem was me calling initializeGL in the constructor when the context was still NULL, so I removed the call since it would be called at some point when the window shows up.
Problem
When QPainter is created after glClear the latter has no effect.
Description
I use Qt 5.7.1. I get same results with gcc on Linux and vc++ on Windows.
I have the following in a widget derived from QGLWidget:
void CanvasWidget::initializeGL()
{
qglClearColor(m_backgroundColor);
}
V1:
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
QPainter painter(this);
painter.drawLine(0, 0, 1000, 1000);
}
Produces:
V2:
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
}
Produces:
What I want is:
Which can be done with a hack:
void CanvasWidget::paintGL()
{
QPainter painter(this);
qglClearColor(m_backgroundColor);
glClear(GL_COLOR_BUFFER_BIT);
painter.drawLine(0, 0, 1000, 1000);
}
Question
What is going on? Why can't glClean and QPainter work together? Why can't I get it with V1?
Minimal Reproducible Example
main.cpp
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainwindow;
mainwindow.show();
return app.exec();
}
MainWindow.h
#pragma once
#include "CanvasWidget.h"
#include <QMainWindow>
#include <memory>
class MainWindow : public QMainWindow
{
public:
explicit MainWindow(QWidget *parent = 0);
MainWindow(const MainWindow &) = delete;
MainWindow & operator= (const MainWindow &) = delete;
virtual ~MainWindow() = default;
private:
std::unique_ptr<CanvasWidget> m_canvasWidget;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, m_canvasWidget(new CanvasWidget(parent))
{
setCentralWidget(m_canvasWidget.get());
}
CanvasWidget.h
#pragma once
#include <QGLWidget>
class CanvasWidget : public QGLWidget
{
Q_OBJECT
public:
CanvasWidget(QWidget* parent = 0, const QGLWidget* shareWidget = 0, Qt::WindowFlags f = 0);
private:
virtual void initializeGL() override;
virtual void paintGL() override;
private:
QColor m_backgroundColor;
};
CanvasWidget.cpp
#include "CanvasWidget.h"
#include <QMessageBox>
#include <QWheelEvent>
CanvasWidget::CanvasWidget(
QWidget* parent /*= 0*/,
const QGLWidget* shareWidget /*= 0*/,
Qt::WindowFlags f /*= 0 */)
: QGLWidget(parent, shareWidget, f)
, m_backgroundColor(0, 93, 196)
{}
void CanvasWidget::initializeGL()
{
qglClearColor(m_backgroundColor);
}
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
QPainter painter(this);
painter.drawLine(0, 0, 1000, 1000);
}
Adding setAutoFillBackground(false) in CanvasWidget constructor solves the problem.
All the credit goes to #G.M.
In Qt tutorial about overpainting OpenGL with QPainter it is stated:
When overpainting 2D content onto 3D content, we need to use a
QPainter and make OpenGL calls to achieve the desired effect. Since
QPainter itself uses OpenGL calls when used on a QGLWidget subclass,
we need to preserve the state of various OpenGL stacks when we perform
our own calls
So, looking at your code in V1 I suppose that QPainter sets its own clear color state, and if you don't set your glClearColor explicitly, you will get what QPainter object has set.
And I would also suggest you to use a tool like RenderDoc or gDebugger to trace GL commands of your app to see exactly what happens under the hood.
So my goal is to (first) draw a triangle with openGL.
my questions:
1) How/when do both of my functions get called? I see that only one gets called. i.e. void MyGLWidget::paintGL. I am confused because as you can see I never call this function, it gets called automatically.I added a widget on my ui which I promoted to MyGLWidget. But when/why/how does it get (not) called?
my code:
myglwidget.cpp
#include "myglwidget.h"
#include <QtWidgets>
#include <QtOpenGL>
#include <GL/glu.h>
MyGLWidget::MyGLWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
}
void MyGLWidget::initializeGL()
{
glClearColor(1,1,0,1);
qDebug("init"); //<-------never gets printed
}
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
qDebug("painting"); //<---- does get printed
glColor3f(1,0,0);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0);
glVertex3f(0.5,-0.5,0);
glVertex3f(0.0,0.5,0);
glEnd();
}
myglwidget.h
#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H
#include <QGLWidget>
class MyGLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit MyGLWidget(QWidget *parent = 0);
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
private:
};
#endif // MYGLWIDGET_H
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("OpenGL with Qt DAO");
w.show();
return a.exec();
}
I do not see a class called Widget made by you which is connected to the class MyGlWidget. Maybe I am wrong but shouldn't you have to make a instance of MyGlWidget (Call it's constructor instead of Widget?)
Both functions are called internally by the QGLWidget super class. See QT Docs
In the documentation you also see that these virtual functions are protected. In your code they are public. So you have to change that in order to make it work.
I'm making in Qt an application for educational purposes.. The goal is that students can write any OpenGL code that they want, and see what the results are in a QGLWidget inherited class..
For that I'm trying to use QtScript in this way:
The OpenGL code students write should be executed in a reimplemented painGL() method...
But the problem is that from the script I would generate from their OpenGL code, I can't access OpenGL methods, or enums, or enything, as they are neither Q_INVOKABLE methods nor slots...
Any ideas about how can I do that??
Here is the code:
*.h:
#include <QtOpenGL/QGLWidget>
#include <GL/glu.h>
#include <QColor>
#include <QtScript>
class Graficador : public QGLWidget
{
Q_OBJECT
public:
Graficador(QWidget *parent = 0);
void dibujar(QString);
void ejecutar_script();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
private:
void draw();
QScriptEngine motor;
QScriptValue valor;
QString orden_motor;
};
*.cpp:
Graficador::Graficador(QWidget *parent)
: QGLWidget(parent)
{
setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));
}
void Graficador::initializeGL()
{
qglClearColor(Qt::black);
}
void Graficador::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Graficador::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
}
void Graficador::draw()
{
QScriptValue resultado;
resultado = motor.evaluate(orden_motor); //Here is where the script should be executed
}
void Graficador::dibujar(QString orden)
{
orden_motor = orden; //Here I load the script content, which is generated from what the students write
}
void Graficador::ejecutar_script()
{
valor = motor.newQObject(this);
motor.globalObject().setProperty("app",valor);
}
The QString "orden_motor" is the code, which I receive from a QPlainTextEdit, that is a child of the same QMainWindow that Graficador is.. When the student presses a QPushButton, "dibujar" and "ejecutar_script" are executed, as well as "updateGL", which are all members of the Graficador class...
So the script should be executed... But instead, when I read the results of QScriptValue "resultado", I get that none of the functions I don't declare as Q_INVOKED are recognized... And that includes all OpenGL methods, as well as OpenGL enums...
If anybody could throw me some light here, I would really appreciate it!!
The ideal case for me would be that the entire QGLWidget class could be accessible from the script... I know it's not the ideal thing to do, but I think it's the most suitable way to do this...
But again, any ideas are welcome!
Thanks!!
Im having a problem of my Rectangle class not being seen as a type. I've included the proper header, and so I am confused.
shapes.h
#ifndef SHAPES_H
#define SHAPES_H
#include "Colors.h"
#include <QPoint>
#include "glwidget.h"
//class GLWidget;
class Shape
{
public:
virtual void draw();
};
class Rectangle : Shape
{
public:
Rectangle(GLWidget *w, QPoint tl, QPoint br){
glWidget = w;
topLeft = tl;
btmRight = br;
}
virtual void draw(){
// top horizontal
for(int i = topLeft.x(); i < btmRight.x(); i++){
glWidget->setPixel(i,topLeft.y(), color);
}
}
private:
QPoint topLeft,btmRight;
GLWidget *glWidget;
RGBColor color;
};
#endif // SHAPES_H
glwidget.cpp
#include <QtGui>
#include <QtOpenGL>
#include <math.h>
#include <stdio.h>
#include "glwidget.h"
#include "Shapes.h"
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
// ... a bunch of code that doesn't need to be included
void GLWidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){
// do some drawing stuff
QPoint mPos = event->pos();
switch(drawmode)
{
case 1:
currentShape = new Rectangle(this,mPos, mPos); /*** This is the error ***/
}
}
}
glwidget.h
#ifndef AGLWIDGET_H
#define AGLWIDGET_H
#include <QGLWidget>
#include "Colors.h"
class Shape;
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
GLWidget(QWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
void setPixel(int x, int y, RGBColor c);
public slots:
void setColor(RGBColor c);
void setDrawRectangle();
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint lastPos;
QVector<QPoint> drawPoints;
RGBColor paintColor;
int drawmode;
Shape *currentShape;
};
Sorry for the load of code... the exact error is
'Rectangle' is not a type glwidget.cpp line 85
Anybody have an idea why it wouldn't be seeing Rectangle as a type in glwidget.cpp despite my including "Shapes.h"?
Thanks in advance!
This is a bit of a longshot, but are you sure you're using moc correctly in regards to the GLWidget code? IE, have you added #include "glwidget.moc to the .cpp file or included it in your build system (qmake knows to do this for you), as well as running moc first. I only mention this because forgetting to do this many moons ago caused me to see a pile of inscrutable type-related warnings and errors.
Perhaps somewhere in the ancestry of GLWidget there is a method or member called Rectangle and there is a confusion. See the documentation for GLWidget and its ancestors
Looks like the compiler believes Rectangle is a template
Well I'm gonna go with it had something to do with the virtual function within Shape not being defined as in g++ undefined reference to typeinfo. The machine I had the strange error on is using an older version of Qt than I have on my personal machine, and my personal is having no issues with this code.
Thanks for the suggestions everyone, but I'm just gonna put this one to rest.