QT5 mixing QML and opengl draw - qt

i want to mix opengl and QML stuff. I used qt 5 beta 2.
I make a minimalist programm for show you the problem :
main.ccp
#include <QGuiApplication>
#include "back.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Back b;
b.setSource(QUrl("ui.qml"));
b.show();
return a.exec();
}
back.h
#ifndef BACK_H
#define BACK_H
#include <QtQuick>
#include <QtOpenGL>
#include <QTimer>
class Back : public QQuickView
{
Q_OBJECT
public:
~Back();
Back();
public slots :
void paint();
};
#endif // BACK_H
back.ccp
#include "back.h"
Back::Back()
{
setClearBeforeRendering(false);
connect(this, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()), Qt::DirectConnection);
timer->start(3000);
}
Back::~Back()
{
}
void Back::paint()
{
glViewport(0, 0, 150, 150);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 150, 150,0,0,10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glColor3ub(255, 0, 0);
glBegin(GL_QUADS);
glVertex2i(0, 0);
glVertex2i(100, 0);
glVertex2i(100, 100);
glVertex2i(0, 100);
glEnd();
}
ui.qml
import QtQuick 2.0
Item {
width : 150
height : 150
Rectangle {
x : 50
y : 50
width: 100
height: 100
color: "green"
}
}
The first picture is correct :
I have a red square with a green square with offset and a black background.
picture 1
After 3 seconds, the second is uncorrect :
I have only the green square with withe background
picture 2
Is someone know what i make wrong ?

Related

I bind a custom FBO, but what I draw goes beyond it

I've made a simple testcase. What I do, in short:
I have a QQuickFramebufferObject subclass called MyItem. It uses the CombinedDepthStencil Attachment type.
I create an instance of MyItem on window hover and destroy it on window unhover
In MyItemRenderer::render() I create a local FBO and draw a triangle to it
This local FBO uses a custom FBO wrapper class instead of QOpenGLFramebufferObject, to narrow down the problem. The problem occurs with QOpenGLFramebufferObject too, though.
The expected behavior is that nothing should ever be drawn to the window. But instead, on the second time you hover the window (after launching the app), the triangle is drawn to the window.
My code:
main.cpp:
#include <QGuiApplication>
#include <QQuickView>
#include <QQuickWindow>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include "fbo.h"
class MyItem : public QQuickFramebufferObject {
Q_OBJECT
public:
Renderer* createRenderer() const;
};
class MyItemRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions {
public:
MyItemRenderer() {
initializeOpenGLFunctions();
m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader.vert.glsl");
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader.frag.glsl");
m_program.link();
}
void render() {
glClearColor(0, 0, 0, 0);
glDisable(GL_DEPTH_TEST);
Fbo fbo(m_size);
m_program.bind();
fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
paintGeometry();
framebufferObject()->bind();
m_window->resetOpenGLState();
}
void paintGeometry() {
QVector<QVector2D> vertices = { QVector2D(0, 0), QVector2D(1, 0), QVector2D(1, 1) };
m_program.enableAttributeArray("aPos");
m_program.setAttributeArray("aPos", vertices.constData());
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
m_program.disableAttributeArray("aPos");
}
QOpenGLFramebufferObject* createFramebufferObject(const QSize &size) {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
return new QOpenGLFramebufferObject(size, format);
}
private:
QOpenGLShaderProgram m_program;
QQuickWindow* m_window;
QSize m_size;
protected:
void synchronize(QQuickFramebufferObject* qqfbo) {
MyItem* parentItem = (MyItem*)qqfbo;
m_window = parentItem->window();
m_size = QSize(parentItem->width(), parentItem->height());
}
};
QQuickFramebufferObject::Renderer* MyItem::createRenderer() const {
return new MyItemRenderer();
}
int main(int argc, char **argv) {
QGuiApplication app(argc, argv);
qmlRegisterType<MyItem>("MyItem", 1, 0, "MyItem");
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
view.show();
return app.exec();
}
#include "main.moc"
main.qml:
import QtQuick 2.0
import MyItem 1.0
Item {
width: 400
height: 400
id: root
Loader {
active: mouseArea.containsMouse
sourceComponent: MyItem {
parent: root
anchors.fill: parent
}
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
}
}
shader.frag.glsl:
void main() {
gl_FragColor = vec4(0.40, 1.0, 0.0, 1.0);
}
shader.vert.glsl:
attribute highp vec2 aPos;
void main() {
gl_Position = vec4(aPos, 0.0, 1.0);
}
fbo.h:
#ifndef FBO_H
#define FBO_H
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
class Fbo : public QOpenGLFunctions {
public:
Fbo(const QSize &size)
: m_colorAttachment(QOpenGLTexture::Target2D)
{
initializeOpenGLFunctions();
glGenFramebuffers(1, &m_id);
m_colorAttachment.setSize(size.width(), size.height());
m_colorAttachment.setFormat(QOpenGLTexture::RGBA8_UNorm);
m_colorAttachment.allocateStorage();
bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorAttachment.textureId(), 0);
}
~Fbo() {
glDeleteFramebuffers(1, &m_id);
}
void bind() {
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
}
private:
GLuint m_id;
QOpenGLTexture m_colorAttachment;
};
#endif
Any ideas?
Note that I've ran the testcase in the CodeXL OpenGL debugger and it has found no OpenGL errors. Same with Qt's QOpenGLDebugLogger mechanism.

not able to draw line using QGLWiget

New to qt opengl. Am trying to draw a line in my opengl window it is not displaying.
Code is executing without error. Please help me. what is wrong in the below mentioned code.
//glwidget.cpp
#include "glwidget.h"
#include <QDebug>
#include <QGLWidget>
#include <QPainter>
GLWidget::GLWidget(QWidget *parent) :
QGLWidget(parent)
{
}
void GLWidget::initializeGL()/*initialize*/
{
qDebug()<<"iniialize";
glClearColor(0.0, 0.0, 102.0/255.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
void GLWidget::resizeGL(int width, int height)
{
qDebug()<<"resizeGL";
glViewport(0, 0, (GLint)width, (GLint)height);
}
void GLWidget::paintGL()
{
qDebug()<<"paintGL";
glBegin(GL_LINES);
glVertex3f( 0.0f, 0.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glEnd();
}
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QWidget>
#include <QGLWidget>
#include <QPainter>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
};
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;/*Mainwindow*/
w.show();
return a.exec();
}
Well, you should think about what you told OpengGL to do here:
With your
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
call, you set up your projection matrix to map the world in the area 0 to 1 (in X- and Y-direction) to your screen.
Then you draw a line from 0 to -1 (in X- and Y-direction). That line lies outside your screen now.
Try some better coordinates in your GL_LINES call.
Plus, you might want to start your paintGL() routine with clearing the screen:
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

Need to draw Transparent qimage that includes drawing of a circle using Qt

I am trying to draw a transparent image using QImage but everytime it gives black background. I have a image background,on that I want to draw a circle which should be trasparent(with no background).How can I do that?
I have used this code
QImage image(size, QImage::Format_ARGB32);
image.fill(qRgba(0,0,0,0));
// Pick an arbitrary size for the circle
const int centerX = size.width() / 2;
const int centerY = size.height() / 2;
const int radius = std::min(centerX, centerY) * 2 / 3;
const int diameter = radius * 2;
// Draw the circle!
QPainter painter(&image);
painter.setPen(Qt::yellow);
painter.drawEllipse(centerX-radius, centerY-radius, diameter, diameter);
http://qt-project.org/doc/qt-4.8/qpainter.html#settings
http://qt-project.org/doc/qt-4.8/qpainter.html#setBrush
The painter's brush defines how shapes are filled.
Hope that helps.
EDIT: Added an awesome example:
Basically what happens below, is the window is set to have a background color (so that the alpha value of the QImage is noticeable and predicable). The QImage is initialized to have a color with an alpha value less than 255. The image gets painted when the widget updates (when shown in the main).
widget.cpp
#include "widget.h"
#include <QImage>
#include <QPainter>
#include <QPalette>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
init_image();
QPalette p = this->palette();
p.setColor(QPalette::Background, Qt::white);
this->setPalette(p);
}
void Widget::init_image()
{
image = new QImage(200, 200, QImage::Format_ARGB32);
int opacity = 50;// Set this between 0 and 255
image->fill(QColor(0,0,0,opacity));
QPainter painter (image);
painter.setPen(Qt::green);
painter.drawEllipse(10, 10, 100, 100);
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent * e)
{
QPainter painter(this);
painter.drawImage(0,0, *image,0,0,-1,-1,Qt::AutoColor);
}
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPaintEvent>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void init_image();
public slots:
void paintEvent(QPaintEvent *);
private:
QImage * image;
};
#endif // WIDGET_H
Main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

Why doesn't setPos() move the QGraphicsItems in the scene?

In the code below, I have three QGraphicsItems that are laid out by QGraphicsLinearLayout, which is set as layout to a QGraphicsWidget.
#include <QApplication>
#include <QBrush>
#include <QDebug>
#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
#include <QGraphicsLinearLayout>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QPen>
class MyShape : public QGraphicsRectItem, public QGraphicsLayoutItem {
public:
MyShape(void) {
setPen(QPen(QBrush(Qt::black), 1));
setBrush(QBrush(Qt::green));
setRect(0, 0, 20, 20);
}
virtual QSizeF sizeHint(Qt::SizeHint which,
const QSizeF& constraint = QSizeF()) const {
Q_UNUSED(which);
Q_UNUSED(constraint);
return boundingRect().size();
}
virtual void setGeometry(const QRectF& rect) {
setPos(rect.topLeft());
}
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
QGraphicsScene scene;
MyShape* shape1 = new MyShape;
MyShape* shape2 = new MyShape;
MyShape* shape3 = new MyShape;
scene.addItem(shape1);
scene.addItem(shape2);
scene.addItem(shape3);
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout;
layout->addItem(shape1);
layout->addItem(shape2);
layout->addItem(shape3);
QGraphicsWidget* container = new QGraphicsWidget;
container->setLayout(layout);
scene.addItem(container);
container->setPos(300, 300); // This doesn't appear to have any affect
// Item for indicating origin
QGraphicsRectItem* tmp = scene.addRect(0, 0, 2, 2, QPen(),
QBrush(Qt::green));
tmp->setPos(0, 0);
qDebug() << tmp->scenePos();
qDebug() << container->scenePos();
QGraphicsView view;
view.setScene(&scene);
view.centerOn(0, 0);
view.show();
return app.exec();
}
Then, I try to move the QGraphicsWidget within the scene by calling setPos(), but it doesn't appear to work (the QGraphicsItems remain in the same place). However, something appears to happen since the scrollbars change. It seems that the QGraphicsWidget moves, without taking the QGraphicsItems along with it.
Why?
EDIT:
By suggestion from DerManu, I changed the inheritance of MyShape to QGraphicsWidget, and with the following code, it works:
#include <QApplication>
#include <QBrush>
#include <QDebug>
#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
#include <QGraphicsLinearLayout>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QPen>
class MyShape : public QGraphicsWidget {
public:
MyShape(void) {
setMinimumSize(20, 20);
setMaximumSize(20, 20);
setPreferredSize(20, 20);
}
QRectF boundingRect(void) const {
QRectF box(0, 0, 22, 22);
box.translate(box.center() * -1);
return box;
}
void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget) {
Q_UNUSED(option);
Q_UNUSED(widget);
// Set box border appearance
painter->setPen(QPen(Qt::black, 1));
// Set box background appearance
painter->setBrush(QBrush(Qt::green));
QRectF box(0, 0, 20, 20);
box.translate(box.center() * -1);
painter->drawRect(box);
}
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
QGraphicsScene scene;
MyShape* shape1 = new MyShape;
MyShape* shape2 = new MyShape;
MyShape* shape3 = new MyShape;
scene.addItem(shape1);
scene.addItem(shape2);
scene.addItem(shape3);
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(Qt::Vertical);
layout->addItem(shape1);
layout->addItem(shape2);
layout->addItem(shape3);
QGraphicsWidget* container = new QGraphicsWidget;
container->setLayout(layout);
scene.addItem(container);
container->setPos(200, 200); // This doesn't appear to have any affect
scene.setSceneRect(-300, -300, 600, 600);
// Item for indicating origin
QGraphicsRectItem* tmp = scene.addRect(0, 0, 2, 2, QPen(),
QBrush(Qt::green));
tmp->setPos(0, 0);
qDebug() << tmp->scenePos();
qDebug() << container->scenePos();
QGraphicsView view;
view.setScene(&scene);
view.centerOn(0, 0);
view.show();
return app.exec();
}
So what is it that QGraphicsWidget provides that I missed in the original code such that using setPos on the container item correctly moves the position of the MyShape items?

Resources