Increasing cpu and ram usage while calling update for multiple QSGNodes - c++

I create an application with Qt Scene Graph (Qt 5.6 on Ubuntu 16.04). It has about 12 instances of QSGNodes and calls update for them every 30ms.
I don't have any problem with updating one of them, but when i call update for all of them, cpu and ram usage began to increase. After some hours cpu usage will be near 100%. (under normal conditions cpu usage should be around 3-4).
Here is minimal version(Sorry for long code, It's simplest version that produces this bug):
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "gui/diagramgraph.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QQuickView>
#include <QTimer>
#include "gui/diagramgraph.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qmlRegisterType<DiagramGraph>("DiagramGraph", 1, 0, "DiagramGraph");
QTimer *updateTimer = new QTimer(this);
for(int i = 1; i <= 12; i++){
QQuickView *view = new QQuickView();
view->setSource(QUrl("qrc:/ui/diagram.qml"));
view->setClearBeforeRendering(true);
QObject *object = view->rootObject();
DiagramGraph* graph = object->findChild<DiagramGraph *>("diagram");
QObject::connect(updateTimer, SIGNAL(timeout()), graph, SLOT(update()));
QWidget *container = QWidget::createWindowContainer(view, this);
ui->vetical->addWidget(container);
}
updateTimer->setTimerType(Qt::PreciseTimer);
updateTimer->start(30);
}
MainWindow::~MainWindow()
{
delete ui;
}
gui/diagramgraph.h
#ifndef DIAGRAMGRAPH_H
#define DIAGRAMGRAPH_H
#include <QQuickItem>
class DiagramGraph : public QQuickItem
{
Q_OBJECT
public:
DiagramGraph();
void init();
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
};
#endif // DIAGRAMGRAPH_H
gui/diagramgraph.cpp
#include "samples.h"
#include "diagramgraph.h"
class DiagramGraphNode : public QSGNode
{
public:
Samples * samples;
};
DiagramGraph::DiagramGraph()
{
setFlag(ItemHasContents, true);
}
QSGNode * DiagramGraph::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *){
DiagramGraphNode *n= static_cast<DiagramGraphNode *>(oldNode);
QRectF rect = boundingRect();
if (rect.isEmpty()) {
delete n;
return 0;
}
if (!n) {
n = new DiagramGraphNode();
n->samples = new Samples();
n->appendChildNode(n->samples);
}
n->samples->updateGeometry();
return n;
}
void DiagramGraph::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry){
update();
QQuickItem::geometryChanged(newGeometry, oldGeometry);
}
gui/samples.h
#ifndef SAMPLES_H
#define SAMPLES_H
#include <QSGGeometryNode>
class Samples : public QSGGeometryNode
{
public:
Samples();
void updateGeometry();
private:
QSGGeometry _geometry;
};
#endif // SAMPLES_H
gui/samples.cpp
#include "samples.h"
#include <QtGui/QColor>
#include <QtQuick/QSGSimpleMaterial>
struct LineMaterial
{
QColor color;
};
class LineShader : public QSGSimpleMaterialShader<LineMaterial>
{
QSG_DECLARE_SIMPLE_SHADER(LineShader, LineMaterial)
public:
LineShader() {
setShaderSourceFile(QOpenGLShader::Vertex, ":/shaders/shaders/samples.vsh");
setShaderSourceFile(QOpenGLShader::Fragment, ":/shaders/shaders/samples.fsh");
}
QList<QByteArray> attributes() const { return QList<QByteArray>() << "y" << "t"; }
void updateState(const LineMaterial *m, const LineMaterial *) {
program()->setUniformValue(id_color, m->color);
}
void resolveUniforms() {
id_color = program()->uniformLocation("color");
}
private:
int id_color;
};
struct Vertex {
float y;
float t;
inline void set(float yy, float tt) { y = yy; t = tt; }
};
static const QSGGeometry::AttributeSet &attributes()
{
static QSGGeometry::Attribute attr[] = {
QSGGeometry::Attribute::create(0, 1, GL_FLOAT, true),
QSGGeometry::Attribute::create(1, 1, GL_FLOAT),
};
static QSGGeometry::AttributeSet set = { 2, 2 * sizeof(float), attr };
return set;
}
Samples::Samples()
: _geometry(attributes(), 0){
setGeometry(&_geometry);
_geometry.setLineWidth(3);
_geometry.setDrawingMode(GL_LINES);
QSGSimpleMaterial<LineMaterial> *m = LineShader::createMaterial();
m->state()->color = QColor("red");
m->setFlag(QSGMaterial::Blending);
setMaterial(m);
setFlag(OwnsMaterial);
}
void Samples::updateGeometry()
{
_geometry.allocate(20);
Vertex *v = (Vertex *) _geometry.vertexData();
for (uint i=0; i < 20; i++){
v[i].set(.5, i);
}
}
mainwindow.ui
just a QVBoxLayout
diagram.qml
import QtQuick 2.0
import QtQuick.Controls 1.4
import DiagramGraph 1.0
Item{
id: diagram_main
DiagramGraph{
id: diagram_graph
objectName: "diagram"
anchors.left: diagram_main.left
height: 100
}
}
shaders/samples.fsh
uniform lowp vec4 color;
uniform lowp float qt_Opacity;
void main(void)
{
gl_FragColor = color * qt_Opacity;
}
shaders/samples.vsh
attribute highp float y;
attribute highp float t;
uniform highp mat4 qt_Matrix;
void main(void)
{
gl_Position = qt_Matrix * vec4(t, y * 100.f, 0.f, 1.f);
}

Related

Qt QGraphicsView Scrolling causes items to randomly disappear

I am having issues with a weird bug which occurs after you adjust the size of a QGraphicsItem.
Here is a YouTube video showing the issue: https://youtu.be/gp1lQTkPf54
In my application, a slider is used to adjust the horizontal zoom of all the regions on the QGraphicsScene. I have made sure to call prepareGeometryChange(); when I am changing the geometry of a region and call update(); but that has not helped. It seems to affect regions that are being rendered out of view from the user.
Code:
mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene *scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
RegionGraphicsItem *rgi = new RegionGraphicsItem(ui->graphicsView->scene());
itemList.append(rgi);
ui->graphicsView->scene()->addItem(rgi);
rgi->setHScaleFactor(ui->horizontalSlider->value());
}
void MainWindow::test() {
QWidget test;
test.show();
}
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
for (int i = 0; i < itemList.size(); i++) {
itemList[i]->setHScaleFactor(value);
}
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "regiongraphicsitem.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QList<RegionGraphicsItem*> itemList;
private slots:
void on_pushButton_clicked();
void on_horizontalSlider_valueChanged(int value);
private:
void test();
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
regiongraphicsitem.cpp
#include "regiongraphicsitem.h"
RegionGraphicsItem::RegionGraphicsItem(QGraphicsScene *_scene) : QGraphicsItem()
{
regionColor = QColor::fromRgb(255,255,255);
setFlags(ItemIsMovable);
waveFormColor = regionColor.darker(80);
outlineColor = QColor("#0f0f0f");
selectedColor = selectedColor.lighter(30);
hScaleFactor = 100;
mainBrush = QBrush(regionColor);
mainPen = QPen(outlineColor, 1);
gridLength = 5;
height = 56;
oldPos = pos();
scene = _scene;
this->prepareGeometryChange();
gridLocation = 5;
setY((0 * 60) + 1);
}
QRectF RegionGraphicsItem::boundingRect() const
{
return QRectF(0, 0, float(gridLength * hScaleFactor), float(height));
}
void RegionGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
QRectF rect = boundingRect();
painter->setBrush(mainBrush);
painter->setPen(mainPen);
painter->drawRoundedRect(rect, 5, 5);
painter->setPen(mainPen);
if (selected) {
painter->setBrush(QBrush(mainPen.color()));
painter->drawRoundedRect(QRect(rect.x(), rect.y(), rect.width(), 20), 5, 5);
painter->drawRect(QRect(rect.x(), rect.y() + 5, rect.width(), 15));
}
QFont font = scene->font();
font.setPixelSize(10);
font.setBold(true);
QFontMetricsF fontMetrics(font);
QString text = "TEST";
int heightFont = fontMetrics.boundingRect(text).height();
if (selected) {
painter->setPen(QPen(mainBrush.color(), 1));
}
painter->drawText(5, heightFont + 3, text);
if (pressed == false ) {
setX((gridLocation - 1) * hScaleFactor);
}
}
void RegionGraphicsItem::setHScaleFactor(int value) {
prepareGeometryChange();
hScaleFactor = value;
update();
}
regiongraphicsitem.h
#ifndef RegionGraphicsItem_H
#define RegionGraphicsItem_H
#include <QGraphicsItem>
#include <QColor>
#include <QBrush>
#include <QPen>
#include <QtGui/QPainter>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <stdint.h>
class RegionGraphicsItem : public QGraphicsItem
{
public:
RegionGraphicsItem(QGraphicsScene *_scene);
float getGridLocation();
void setHScaleFactor(int value);
protected:
QColor outlineColor;
QColor selectedColor;
QColor regionColor;
QColor waveFormColor;
bool selected;
int penWidth;
int rounded;
QBrush mainBrush;
QBrush waveformBrush;
QPen mainPen;
int height;
float gridLength;
bool pressed = false;
QPointF oldPos, oldMousePos;
int oldTrackIndex;
float gridLocation;
QGraphicsScene *scene;
int oldHScaleFactor;
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
private:
int hScaleFactor;
};
#endif // RegionGraphicsItem_H
Steps to reproduce:
Add a RegionGraphicItem to the QGraphicsScene
Increase the slider until the region is off screen
Decrease the slider and the region will not be visible. <-- This is the issue.

Transferring data from one form to another in Qt?

there was such problem. I have a main and auxiliary form. With the second form, I take two values: the index and the color. I'm transferring to the main form. I get the values ​​in the "setParametr" method. But I can not get them in the "paintEvent" method. QDebug show that the method "setParametr" got the values. When I check the values ​​in "on_pushButton_clicked()" values is 0. What could be the problem. Just started to study Qt
dialog.h
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
void setcolor(int);
int getcolor();
void setindex(int);
int getindex();
private slots:
void ColorIndex();
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
int squareColor;
int Index;
};
dialog.cpp
#include "ui_dialog.h"
#include "dialog.h"
#include "mainwindow.h"
#include "QDebug"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(ColorIndex()));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::setcolor(int color)
{
squareColor = color;
}
int Dialog::getcolor()
{
return squareColor;
}
void Dialog::setindex(int index)
{
Index = index;
}
int Dialog::getindex()
{
return Index;
}
void Dialog::on_pushButton_clicked()
{
MainWindow *main = new MainWindow();
if(ui->radioButton->isChecked()){
setcolor(1);
}
if(ui->radioButton_2->isChecked()){
setcolor(2);
}
if(ui->radioButton_3->isChecked()){
setcolor(3);
}
if(ui->comboBox->currentIndex()==0)
{
setindex(1);
}
if(ui->comboBox->currentIndex()==1)
{
setindex(2);
}
if(ui->comboBox->currentIndex()==2)
{
setindex(3);
}
if(ui->comboBox->currentIndex()==3)
{
setindex(4);
}
qDebug() << QString::number(getcolor());
qDebug() << QString::number(getindex());
main->SetParametr(getindex(),getcolor());
}
mainwindow.h
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QPainterPath>
#include <QColor>
#include <QColorDialog>
#include <QPushButton>
#include <QMainWindow>
#include "dialog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setColor(int);
int getColor();
void setIndex(int);
int getIndex();
private:
Dialog *dial = new Dialog();
int fIndex;
int fColor;
private slots:
void on_actionMy_Dialog_triggered();
void paintEvent(QPaintEvent *event);
void on_pushButton_clicked();
signals:
void SetParametr(int index, int color);
private:
Ui::MainWindow *ui;
void onInit();
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include "dialog.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
fColor = 0;
fIndex =0;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::SetParametr(int index, int color)
{
fIndex = index;
fColor = color;
qDebug() << QString::number(fColor) + "s";
qDebug() << QString::number(fIndex);
}
/*void MainWindow::setColor(int _color)
{
fColor = _color;
}
int MainWindow::getColor()
{
return fColor;
}
void MainWindow::setIndex(int _index)
{
fIndex = _index;
}
int MainWindow::getIndex()
{
return fIndex;
}
*/
void MainWindow::paintEvent(QPaintEvent *event)
{
QColor red1;
if(fColor==1){
red1 = Qt::red;
}
if(fColor == 2){
red1 = Qt::blue;
}
if(fColor == 3){
red1 = Qt::green;
}
int index1;
if(fIndex == 0)
{
index1 = 0;
}
if(fIndex == 1)
{
index1 = 1;
}
if(fIndex == 2)
{
index1 = 2;
}
if(fIndex == 3)
{
index1 = 3;
}
Q_UNUSED(event);
QPainter painter(this);
if(index1 == 0)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawEllipse(100, 50, 150, 150);
}
if(index1 == 1)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawRect(50, 50, 250, 150);
}
if(index1 == 2)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
QPolygon polygon;
polygon<<QPoint(175,50)<<QPoint(50,200)<<QPoint(300,200);
painter.drawPolygon(polygon);
}
if(index1 == 3)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawRect(100, 50, 150, 150);
}
}
void MainWindow::on_actionMy_Dialog_triggered()
{
dial->show();
}
void MainWindow::on_pushButton_clicked()
{
qDebug() << QString::number(fColor);
qDebug() << QString::number(fIndex);
}

How to do (dynamic) offscreen render with QOffscreenSurface in Qt5 correctly?

I am try to do some offscreen rendering jobs in Qt5.3 and I want to use QOpenGLFramebufferObject::toImage to output each pictures(I want to output a few pictures when render() draws different things).
Following the instructions of this, I succeeded in offscreen rendering my first pic and outputing it. So to future on, I write an example as the following code and here is a package in Google. I can get the first fbo content(and its output file correctly, but from the second time, the fbo was not re-render() and it always output the same pictures).
So I want to know what should I do after I finish one time offscreen render to make sure the next time would be correct in qt? Or is there anyone could tell me how to set animation correctly in QOffscreenSurface?
qtestofffscreen.h:
#ifndef QTESTOFFSCREEN_H
#define QTESTOFFSCREEN_H
#include <QOffscreenSurface>
#include <QWindow>
#include <QtGui/QOpenGLFunctions_3_3_Core>
#include <QImage>
#include <QGLFramebufferObject>
#include <QOpenGLPaintDevice>
#include <QOpenGLFunctions>
#include <QMutex>
#include <QMutexLocker>
class QTestOffScreen : public QOffscreenSurface,
protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit QTestOffScreen(
QScreen* targetScreen = nullptr,
const QSize& size = QSize (1, 1));
~QTestOffScreen();
virtual void render();
virtual void initialize();
void renderNow();
void setAnimating(bool animating);
bool event(QEvent *) override;
void renderLater();
int counts;
private:
QGLFramebufferObject *fbo;
bool m_animating;
bool m_update_pending;
QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;
QSize m_size;
QMutex mutex;
signals:
void doneImg(int index);
};
#endif // QTESTOFFSCREEN_H
qtestofffscreen.cpp:
#include "qtestoffscreen.h"
#include <QTime>
#include <QDebug>
#include <QCoreApplication>
#include <QOpenGLFramebufferObject>
QTestOffScreen::QTestOffScreen(QScreen *targetScreen,
const QSize &size):
QOffscreenSurface(targetScreen),
m_size(size),
fbo(Q_NULLPTR),
m_context(Q_NULLPTR),
m_device(Q_NULLPTR),
counts(100)
{
requestedFormat().setVersion(3,3);
setFormat(requestedFormat());
create();
m_context = new QOpenGLContext(this);
m_context->setFormat(format());
if (m_context->create())
{
m_context->makeCurrent(this);
m_context->functions()->initializeOpenGLFunctions();
}else
{
delete m_context;
m_context = Q_NULLPTR;
throw ("Still wrong here");
}
//To make sure m_context was initialized
//in first time entering renderNow()
delete m_context;
m_context = Q_NULLPTR;
}
QTestOffScreen::~QTestOffScreen()
{
delete m_context;
delete m_device;
if (fbo)
delete fbo;
}
void QTestOffScreen::render()
{
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
| GL_TEXTURE_BIT);
glViewport(0,0,1920,1080);
glOrtho(0,1920,0,1080,0,1);
glColor3f(1.0,0.0,0.0);
float tmp = float(qrand()%1000);
float count = (float)counts * 10.0f;
glLineWidth(3.0f);
glBegin(GL_LINE_LOOP);
glVertex2f(count ,count );
glVertex2f(count + 100,count);
glVertex2f(count + 50,count + 100);
glEnd();
qDebug()<<QString("current tmp is %1").arg(count);
}
void QTestOffScreen::initialize()
{
if (!fbo)
{
fbo = new QGLFramebufferObject(1920,1080,GL_TEXTURE_2D);
}
fbo->bind();
}
void QTestOffScreen::renderNow()
{
bool needsInitialize = false;
if (!m_context)
{
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
if (m_context->isValid())
{
qDebug()<<"Right Here when creating m_context in renderNow";
}
needsInitialize = true;
}
if ( !m_context->makeCurrent(this) )
{
qDebug()<<"This fails in makeCurrent";
}
if (needsInitialize)
{
initializeOpenGLFunctions();
initialize();
}
render();
qDebug()<<counts;
counts--;
fbo->toImage().save(QString::number(counts) + QString(".png"));
m_context->doneCurrent();
if (counts >= 0)
{
m_update_pending = false;
emit doneImg(counts);
}
}
void QTestOffScreen::setAnimating(bool animating)
{
m_animating = animating;
m_update_pending = false;
if (m_animating)
renderLater();
}
bool QTestOffScreen::event(QEvent *event)
{
switch (event->type())
{
case QEvent::UpdateRequest:
m_update_pending = true;
renderNow();
return true;
default:
return QOffscreenSurface::event(event);
}
}
void QTestOffScreen::renderLater()
{
if (!m_update_pending)
{
m_update_pending = true;
QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
}
}
void QTestOffScreen::generateImg(QImage *tmp_img_pointer)
{
GLint viewPort[4]={0};
glGetIntegerv(GL_VIEWPORT,viewPort);
int win_width,win_height;
win_width = 1920;
win_height = 1080;
GLubyte *colorArr=new GLubyte[win_width*win_height*3];
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadBuffer (GL_FRONT);
int tmp_x,tmp_y;
tmp_x = 0;
tmp_y = 0;
glReadPixels(tmp_x,tmp_y,win_width,win_height,
GL_RGB,GL_UNSIGNED_BYTE,colorArr);
int winrows = tmp_img_pointer->height();
int wincols = tmp_img_pointer->width ();
for(int ii=0; ii < winrows * wincols * 3; ii ++)
{
if((colorArr[ii] <0)|(colorArr[ii] >255))
{ colorArr[ii] = 255; }
}
for(int j=0;j<winrows;j++)
for(int i=0;i<wincols;i++)
{
int index=(j*wincols+i)*3;
QRgb value=qRgb(colorArr[index+2],
colorArr[index+1],
colorArr[index ]);
tmp_img_pointer->setPixel(i,winrows-j-1,value);
}
delete colorArr;
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "qtestoffscreen.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QTestOffScreen *scr;
private slots:
void ReceiveCurrentIndex(int);
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSurfaceFormat format;
format.setSamples(1);
format.setRenderableType(QSurfaceFormat::OpenGL);
scr = new QTestOffScreen();
connect(scr,SIGNAL(doneImg(int)),this,SLOT(ReceiveCurrentIndex(int)));
scr->setFormat(format);
scr->setAnimating(true);//Start rendering animation here.
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::ReceiveCurrentIndex(int)
{
Sleep(100);
scr->renderLater();
}

Qt Unresolved External Symbol

I have classes, ImageLabel, and ChoiceLabel. ChoiceLabel inherits from ImageLabel. When I try to make a new ChoiceLabel, I get an Unresolved External Symbol error. Here are the relevant files:
imagelabel.h
#ifndef IMAGELABEL_H
#define IMAGELABEL_H
#include <QLabel>
class QPixmap;
class QStringList;
class QFileDialog;
class QResizeEvent;
class ImageLabel : public QLabel
{
Q_OBJECT
public:
explicit ImageLabel(QWidget *parent = 0);
protected:
virtual int heightForWidth( int width ) const;
virtual QSize sizeHint() const;
QPixmap scaledPixmap() const;
void setPixmap ( const QPixmap & );
void resizeEvent(QResizeEvent *);
private:
QPixmap pix;
};
#endif // IMAGELABEL_H
choicelabel.h
#ifndef CHOICELABEL_H
#define CHOICELABEL_H
class QStringList;
class ChoiceLabel : public ImageLabel
{
Q_OBJECT
public:
ChoiceLabel();
private:
QStringList *imageFiles;
void mousePressEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *);
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
};
#endif // CHOICELABEL_H
mainwindow.cpp
#include "mainwindow.h"
#include "imagelabel.h"
#include "choicelabel.h"
#include <QGridLayout>
#include <qDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
choiceLabelA = new ChoiceLabel; //the problem occurs here
resultLabel = new ImageLabel;
centralWidget = new QWidget(this);
this->setCentralWidget(centralWidget);
gridLayout = new QGridLayout(centralWidget);
gridLayout->addWidget(resultLabel);
}
EDIT:
imagelabel.cpp
#include "imagelabel.h"
#include <QDebug>
ImageLabel::ImageLabel(QWidget *parent) :
QLabel(parent)
{
setMinimumSize(250,250);
setAlignment(Qt::AlignCenter | Qt::AlignCenter);
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QPixmap initialPixmap(250, 250);
initialPixmap.fill(Qt::black);
setPixmap(initialPixmap);
}
void ImageLabel::setPixmap ( const QPixmap & p)
{
pix = p;
QLabel::setPixmap(scaledPixmap());
}
QPixmap ImageLabel::scaledPixmap() const
{
return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
int ImageLabel::heightForWidth( int width ) const
{
return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width();
}
QSize ImageLabel::sizeHint() const
{
int w = this->width();
return QSize( w, heightForWidth(w) );
}
void ImageLabel::resizeEvent(QResizeEvent *)
{
if(!pix.isNull())
QLabel::setPixmap(scaledPixmap());
}
choicelabel.cpp
#include "choicelabel.h"
#include <QStringList>
#include <QFileDialog>
#include <QFrame>
ChoiceLabel::ChoiceLabel():
imageFiles()
{
setFocusPolicy(Qt::StrongFocus);
}
void ChoiceLabel::mousePressEvent(QMouseEvent *)
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter("Images (*.png *.jpg)");
dialog.setDirectory("C:/Users/FrankFritz/Desktop/qt/uglypictures");
if (dialog.exec()){
imageFiles = dialog.selectedFiles();
QPixmap pixmap = imageFiles->first();
setPixmap(pixmap);
}
}
void ChoiceLabel::keyPressEvent(QKeyEvent *ev)
{
static int index(0);
if (ev->key() == Qt::Key_Right){
index = (index + 1) % imageFiles->length();
setPixmap( QPixmap(imageFiles->at(index)) );
}
if (ev->key() == Qt::Key_Left){
if (index == 0){
index = imageFiles->length() - 1;
}
else{
index = (index - 1) % imageFiles->length();
}
setPixmap( QPixmap(imageFiles->at(index)) );
}
}
void ChoiceLabel::focusInEvent(QFocusEvent *)
{
setFrameStyle(QFrame::StyledPanel);
}
void ChoiceLabel::focusOutEvent(QFocusEvent *)
{
setFrameStyle(QFrame::NoFrame);
}
Most probably
ChoiceLabel::ChoiceLabel():
imageFiles()
{
setFocusPolicy(Qt::StrongFocus);
}
ChoiceLabel::ChoiceLabel(QWidget *parent): ImageLabel(parent)
{
setFocusPolicy(Qt::StrongFocus);
}
Forgot to call the base class' constructor. Also forgot to specify a parent QWidget * for ChoiceLabel in its own constructor.
See What are the rules for calling the superclass constructor? for reference.

QOpenGLWidget problems under Fullscreen

I'm using Qt 5.4.0.
I added two widgets in QMainWindow: QOpenGLWidget and QQuickView. But my problem is when I clicked on fullscreen button, QQuickView would be disappeared and then when I maximized it, QQuickView would be appeared on the screen. what did i do wrong?
my code:
helper.h
#include <QBrush>
#include <QFont>
#include <QPen>
#include <QWidget>
class Helper
{
public:
Helper();
public:
void paint(QPainter *painter, QPaintEvent *event, int elapsed);
private:
QBrush background;
QBrush circleBrush;
QFont textFont;
QPen circlePen;
QPen textPen;
};
helper.cpp
#include <QPainter>
#include <QPaintEvent>
#include <QWidget>
Helper::Helper()
{
QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));
background = QBrush(QColor(64, 32, 64));
circleBrush = QBrush(gradient);
circlePen = QPen(Qt::black);
circlePen.setWidth(1);
textPen = QPen(Qt::white);
textFont.setPixelSize(50);
}
void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
painter->fillRect(event->rect(), background);
painter->translate(100, 100);
painter->save();
painter->setBrush(circleBrush);
painter->setPen(circlePen);
painter->rotate(elapsed * 0.030);
qreal r = elapsed / 1000.0;
int n = 30;
for (int i = 0; i < n; ++i) {
painter->rotate(30);
qreal factor = (i + r) / n;
qreal radius = 0 + 120.0 * factor;
qreal circleRadius = 1 + factor * 20;
painter->drawEllipse(QRectF(radius, -circleRadius,
circleRadius * 2, circleRadius * 2));
}
painter->restore();
painter->setPen(textPen);
painter->setFont(textFont);
painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter, QStringLiteral("Qt"));
}
glwidget.h
#include <QOpenGLWidget>
class Helper;
class GLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
GLWidget(Helper *helper, QWidget *parent);
public slots:
void animate();
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private:
Helper *helper;
int elapsed;
};
glwidget.cpp
#include "glwidget.h"
#include "helper.h"
#include <QPainter>
#include <QTimer>
GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QOpenGLWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(200, 200);
setAutoFillBackground(false);
}
void GLWidget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
update();
}
void GLWidget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}
mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
bool _showFullScreen;
Helper helper;
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQuickView>
#include <QQuickItem>
#include <QTimer>
#include "glwidget.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
_showFullScreen = false;
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, this);
container->setMinimumSize(200, 200);
container->setMaximumSize(200, 200);
container->setFocusPolicy(Qt::TabFocus);
view->setSource(QUrl("QquickView.qml"));
ui->verticalLayout->addWidget(container);
GLWidget *openGL = new GLWidget(&helper, this);
ui->verticalLayout_2->addWidget(openGL);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), openGL, SLOT(animate()));
timer->start(50);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if (_showFullScreen == false) {
showFullScreen();
_showFullScreen = true;
} else {
showMaximized();
_showFullScreen = false;
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}