qt openGL - draw triangle - c++

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.

Related

Assertion failure when calling "initializeGLFunctions()"

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.

QGLWidget's background won't change in either initializeGL() or paintGL()

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)
{
}

Qt: glClear does not work with overpainting on OpenGL

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.

Trying to use boundingRect in Qt

What is wrong with class Kwadrat? I have an error:
Invalid new-expression of abstract class type 'Kwadrat'
Kwadrat* kwadrat = new Kwadrat(20);
I want a moving square on the screen (when it hit 370 on X or 370 on Y coordinate it comes back to middle).
when Kwadrat is classic QGraphicsRectItem I have a bug with (0,0) coordinate.
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPixmap>
#include "poruszanie.h"
#include <QRectF>
#include <QGraphicsRectItem>
class Kwadrat : public QGraphicsItem
{
Q_OBJECT
public:
Kwadrat(int size)
: QGraphicsItem(NULL) // we could parent, but this may confuse at first
{
m_boundingRect = QRectF(0, 0, size, size);
}
QRectF boundingRect() const
{
return m_boundingRect;
}
private:
QRectF m_boundingRect;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene*scena=new QGraphicsScene();
// Poruszanie*kwadrat=new Poruszanie();
// kwadrat->setRect(0,0,20,20);
// kwadrat->setBrush(QBrush(Qt::white));
// scena->addItem(kwadrat);
Kwadrat*kwadrat=new Kwadrat(20);
kwadrat->setBrush(QBrush(Qt::white));
scena->addItem(kwadrat);
kwadrat->setFlag(QGraphicsItem::ItemIsFocusable);
kwadrat->setFocus();
QGraphicsView *widok=new QGraphicsView(scena);
widok->setBackgroundBrush(QBrush(Qt::yellow));
widok->setMinimumSize(400,400);
widok->show();
return a.exec();
}
To write your own graphics item, you first create a subclass of
QGraphicsItem, and then start by implementing its two pure virtual
public functions: boundingRect(), which returns an estimate of the
area painted by the item, and paint(), which implements the actual
painting.
From http://doc.qt.io/qt-5/qgraphicsitem.html#details
So you need to implement the pure virtual function paint to do the painting of your QGraphicsItem to get rid of the error, your compiler should have shown that, besides telling you that your class is abstract (because of the missing function implementation).

QT drawing without erasing widget

I have a QWidget-derived class. In the constructor I say:
setPalette(QPalette(QColor(250,250,200)));
setAutoFillBackground(true);
Then in my widget's paintEvent() I say:
QPainter painter(this);
painter.drawRect(1,2,3,4);
There is also an updateNow() slot...which just calls update(). How can I make sure my palette doesn't get erased after that update call?
I don't have any problems with the following:
#include <QApplication>
#include <QWidget>
#include <QPalette>
#include <QPaintEvent>
#include <QPainter>
class Test : public QWidget
{
public:
Test()
{
setPalette(QPalette(QColor(250, 250, 200)));
setAutoFillBackground(true);
}
protected:
virtual void paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.drawRect(10, 20, 30, 40);
}
virtual void mousePressEvent(QMouseEvent*)
{
update();
}
};
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Test myTest;
myTest.show();
return app.exec();
}
The rectangle draws, and stays after I click, which triggers update. What are you seeing?