I'm trying to have a QPushButton in my scene, but when I'm trying to add the QGraphicsProxyWidget to the scene, it crashes.
So here's the .cpp:
#include "upgradecromagnon.h"
#include "game.h"
#include <QGraphicsProxyWidget>
#include <qDebug>
extern Game *game;
UpgradeCromagnon::UpgradeCromagnon()
{
this->setRect(-50,0,150,50);
buttonAmelio = new QPushButton("salut");
teste();
}
void UpgradeCromagnon::teste()
{
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();
proxy->setWidget(buttonAmelio);
scene()->addItem(proxy);
}
and its .h:
#ifndef UPGRADECROMAGNON_H
#define UPGRADECROMAGNON_H
#include <QPainter>
#include <QGraphicsRectItem>
#include <QPushButton>
class UpgradeCromagnon: public QGraphicsRectItem
{
public:
UpgradeCromagnon();
void teste();
private:
QPushButton *buttonAmelio;
};
#endif // UPGRADECROMAGNON_H
Your UpgradeCromagnon constructor calls UpgradeCromagnon::teste which, in turn, calls QGraphicsItem::scene. At that point QGraphicsItem::scene must return a null pointer since there's no possible way the UpgradeCromagnon instance can have been added to a QGraphicsScene before its contructor has completed (not according to the code you've provided at any rate).
Related
This question already has answers here:
QObject connection function
(3 answers)
Closed 4 years ago.
I am currently making a main menu for a game, but when the button is clicked it does not seem to call the relevant slot (The button does not do anything). I have tried to move the button to a thread to ensure that nothing is keeping it from running immediately. I have written a simpler program where the button works, so it would seem the problem is not with the button or signal itself. Therefore it must be something keeping it from running?
The source file is given as:
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QObject>
#include <QBrush>
#include"game.h"
#include <QMediaPlayer>
#include <QImage>
#include<QGraphicsPixmapItem>
#include <QPixmap>
#include<QGraphicsItem>
#include <QPushButton>
#include <QLineEdit>
#include <QPalette>
#include <QMessageBox>
#include <QLabel>
#include <QComboBox>
Game::Game(QWidget*parent)
{
//adding the background
QGraphicsScene *scene=new QGraphicsScene();//to create a new graphics scene
scene->setSceneRect( 0,0,1366,768);
setBackgroundBrush(QBrush(QImage(":/images/Back_1_withlogo.jpg")));
setScene(scene);
show();
setFixedSize(1366,768);
//adding logo
//setPixmap(QPixmap(":/images/Logo.png"));
//adding the soundtrack
music=new QMediaPlayer();
music->moveToThread(&MusicThread);
music->setMedia(QUrl("qrc:/sounds/Surreal-Game-Menu.mp3"));
music->play();
MusicThread.start();
//add GUI
this->setFixedSize(1366,768);
this->move(-7,-5);
//start button and username edit box
btnStart = new QPushButton(this);
btnStart->moveToThread(&btnThread);
UserName = new QLineEdit(this);
UserName->setFixedSize(100,25);
UserName->move(300,300);
UserName->show();
UserName->setMaxLength(12);
btnStart->setText("Start");
btnStart->setFixedSize(100,30);
btnStart->show();
btnStart->move(300,600);
connect(btnStart, SIGNAL (released()),this, SLOT (btnStart_clicked()));
btnThread.start();
//label for username edit box
QLabel *LblUsername= new QLabel(this);
LblUsername->setStyleSheet("QLabel { color : white; }");
LblUsername->setFixedSize(100,30);
LblUsername->move(230,300);
LblUsername->setText("Username:");
LblUsername->show();
QLabel *lblGameMode = new QLabel(this);
lblGameMode->setStyleSheet("QLabel { color : white; }");
lblGameMode->setFixedSize(100,30);
lblGameMode->move(190,450);
lblGameMode->setText("Select Game mode:");
lblGameMode->show();
//combobox to select players
GameMode=new QComboBox(this);
GameMode->move(300,450);
GameMode->setFixedSize(100,30);
QStringList Modelist=(QStringList()<<"singleplayer"<<"co-op"<<"multiplayer (3 players)");
GameMode->addItems(Modelist);
GameMode->show();
}
void Game::btnStart_clicked()
{
if (UserName->text()==NULL)
{
QMessageBox messageBox;
messageBox.critical(0,"Error","Please insert username!");
messageBox.setFixedSize(500,200);
}
else
{
numPlayers = GameMode->currentIndex();
SUsername= UserName->text();
UserName->setText("works");
}
}
And the header code is given as:
#ifndef GAME_H
#define GAME_H
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QMediaPlayer>
#include <QThread>
#include <QComboBox>
class Game:public QGraphicsView
{
public:
Game(QWidget*parent=0);
QGraphicsScene*scene;
private slots:
void btnStart_clicked();
private:
QPushButton *btnStart;
QLineEdit *UserName;
QMediaPlayer *music;
QThread MusicThread;
QString SUsername;
QThread btnThread;
QComboBox *GameMode;
int numPlayers;
};
#endif // GAME_H
I received the following error:
QObject::connect: No such slot QGraphicsView::btnStart_clicked() in game.cpp:57
add a Q_OBJECT macro as shown below:
class Game:public QGraphicsView
{
Q_OBJECT
public:
Game(QWidget*parent=0);
QGraphicsScene*scene;
private slots:
void btnStart_clicked();
private:
QPushButton *btnStart;
QLineEdit *UserName;
QMediaPlayer *music;
QThread MusicThread;
QString SUsername;
QThread btnThread;
QComboBox *GameMode;
int numPlayers;
};
This macro helps compiler to determine that the class is using signals and slots mechanism. Basically it creates a entry of defined signals and slots in MOC (meta object compiler) file.
Go through below link for info:
http://www.bogotobogo.com/Qt/Qt5_Q_OBJECT_Macro_Meta_Object.php
QObject::connect (btnStart, &QPushButton::clicked, this, &Game::btnStart_clicked); might work... if you want to use the release event try overriding virtual void mouseRelease or the eventFilter.
And of course... the Q_OBJECT marco.
i've created a custom progress bar, but when i call the SetValue() method the paintEvent method (overrided) is not called, so the progress bar show just the veryfirst value.
This is the Header grafica_progressbar.h
#ifndef GRAFICA_PROGRESSBAR_H
#define GRAFICA_PROGRESSBAR_H
#include <QWidget>
#include <QProgressBar>
#include <QPaintEvent>
#include <QPainter>
#include <QBrush>
#include <QStyle>
#include <QPen>
#include <QColor>
class grafica_ProgressBar : public QProgressBar
{
Q_OBJECT
public:
grafica_ProgressBar();
protected:
void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
};
#endif // GRAFICA_PROGRESSBAR_H
and this is the cpp grafica_progressbar.cpp
#include "grafica_progressbar.h"
grafica_ProgressBar::grafica_ProgressBar()
{
}
void grafica_ProgressBar::paintEvent(QPaintEvent *)
{
int tmpValue = value();
int TopPos = QStyle::sliderPositionFromValue(minimum(), maximum(), tmpValue, width());
QPainter p(this);
if (tmpValue<maximum()*0.85)
{
p.setPen(Qt::green);
p.setBrush(QBrush(Qt::green));
}
else
{
p.setPen(QColor(255,51,51));
p.setBrush(QColor(255,51,51));
}
p.drawRect(0,0,TopPos,height());
p.setPen(Qt::gray);
p.setBrush(QBrush(Qt::lightGray));
p.drawRect(TopPos, 0, width(), height()); //riempio tutto il resto di grigio
p.setPen(Qt::black);
p.setBrush(QBrush(Qt::black));
p.drawText(0,0, width(), height(), Qt::AlignCenter, QString::number(tmpValue ) + " bar");
}
and this is the first call into the userinterface costructor
TestProgres = new grafica_ProgressBar();
ui->gridLayout->addWidget(TestProgres);
TestProgres->setMaximum(400);
TestProgres->setValue(300);
if i try to call TestProgres->setValue(200) inside a button, i can't see any refresh.
So, where's the problem?
The code starts to work after a "clean, rebuilt & run" operation.
I've edited the code just for showing the correct value.
Thanks to all!
I am having a bit of difficulty with some code. I am super rather new to Qt so it is entirely possible that I am simply ignorant to the problem I am having.
Basically, I am blocking out a program so that I can add the specifics of it later. I want to be able to create a grid of buttons, and when one of those buttons is pressed, another shape to replace it.
I am able to make my button grid, have it be scrollable, and have the button call it its position on the grid when pressed. However, when I try and use those coordinates to add another button to the grid, Qt crashes.
Here's my code so far:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QScrollArea>
#include <QDebug>
#include <QString>
#include <QSignalMapper>
#include <QStringList>
#include <QLayoutItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
populateViewGrid(); //I wanted to see if I could add in a scrollbar
//from outside the main window. Could this be causing
// the issue?
}
void MainWindow::populateViewGrid()
{
QScrollArea*scrollArea = new QScrollArea(this);
QWidget*central = new QWidget(this);
QGridLayout*gridLayout = new QGridLayout(central);
QSignalMapper *signalMapper = new QSignalMapper(central);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
QString position= QString("%1,%2").arg(i).arg(j);
QPushButton* button = new QPushButton("addTrack",central);
gridLayout->addWidget(button, i, j);
connect(button, SIGNAL(clicked()),signalMapper, SLOT(map()));
signalMapper->setMapping(button, position);
}
}
connect(signalMapper, SIGNAL(mapped(QString)),this, SLOT(addTrack(QString )));
central->setLayout(gridLayout);
scrollArea->setWidget(central);
setCentralWidget(scrollArea);
}
void MainWindow::addTrack(QString position)
{
QStringList query = position.split(",");
int x;
x=query.at(0).toInt();
int y;
y=query.at(1).toInt() ;
QPushButton *Ifthisworks=new QPushButton(this);
//This first line is where is crashes. I know this due to having the code
//laced with qDebugs. From all of my google searches and such, it seems that
// something simple should be wrong and I can't find it.
QLayoutItem * existingitem = gridLayout->itemAtPosition(x, y);
if(existingitem) {
gridLayout->removeItem(existingitem);
delete existingitem;
}
// before I included the above to remove the button from the grid point, the
//program would crash here.
gridLayout->addWidget(Ifthisworks, x, y);
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
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 <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QMainWindow>
#include <QScrollArea>
#include <QSignalMapper>
#include <QHash>
//unrelated question, do I need the above in my code? I know not all of them
//used, but do I need includes in this file as well?
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void populateViewGrid();
QGridLayout *gridLayout;
public slots:
void addTrack(QString);
private:
QScrollArea*scrollArea;
QWidget * central;
QPushButton *Ifthisworks;
QSignalMapper *signalMapper;
QPushButton *clockViews;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
If you could help me understand how to not make Qt crash there and also add a button, that would be fantastic =)
So some background real quick incase you are looking at my code and are scratching your head. I'm a mechanical engineer who should have probably been an electrical or computer engineer and knows enough about coding to get myself into these kinds of messes. For the most part, I searched for what I wanted Qt to do and hacked it all together to hopefully make it work. Any bit of deeper understanding you can share would be more than welcome.
Thank you for your time.
You are initializing a local variable called gridLayout in your MainWindow::populateViewGrid() method:
QGridLayout*gridLayout = new QGridLayout(central);
Then in your MainWindow::addTrack(QString position) method, you are trying to access the member variable called gridLayout which is never initialized.
To fix this, simply initialize the member variable instead of creating a local variable in your MainWindow::populateViewGrid() method:
gridLayout = new QGridLayout(central);
You are doing the same mistake with your other member variables as well. Fix them the same way.
I would go for a different implementation.
Move gridlayout, signalmapper,... to be class members. I personally like also to keep a list of my widgets QList<QPushButton*> for manually deleting or keeping a button cache.
Make the signalmapper to map to index in list or QWidget*. For the example i`ll go with the QWidget* pointer.
QPushButton *newButton = new QPushButton("The new Thing");
QPushButton *oldButton = static_cast<QPushButton*>(widgetPointer);
gridLayout->replaceWidget(oldButton ,newButton);
buttonList->takeAt(buttonList->indexOf(oldButton))->deleteLater()); //if you keep a list..
buttonList->insert(buttonList->indexOf(oldButton),newButton);
I'm creating a sort of drawable object class for mesh data and i'm getting this linker error. This is also on top of another class that handles the drawing of the meshes that was used in one of the Qt tutorials. I'm also using a QGLWidget to be the surface i'm drawing to. Here's what the header file looks for the first class.
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector3D>
#include <QVector2D>
#include <QDebug>
#include <QFile>
struct VertexData
{
QVector3D position;
QVector2D texCoord;
QVector3D normal;
};
class GLObject
{
public:
GLObject();
VertexData *data;
GLushort *indices;
GLuint vboIds[2];
int faceCount, vertCount;
bool generateFromPLY(QString filename);
};
#endif // GLOBJECT_H
Here's the header for the other class.
#ifndef GEOMETRYENGINE_H
#define GEOMETRYENGINE_H
#include <QObject>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector2D>
#include <QVector3D>
#include <QFile>
#include <QDebug>
#include <QVector>
#include <globject.h>
class GeometryEngine : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
GeometryEngine();
~GeometryEngine();
void init();
void drawGeometry(QOpenGLShaderProgram *program);
//void drawCubeGeometry(QOpenGLShaderProgram *program);
bool generateFromPly(QString filename);
QVector<GLObject> drawables;
int drawableId = 0;
};
#endif // GEOMETRYENGINE_H
G:\Dropbox\GLSLDemo\globject.cpp:60: error: 'glGenBuffers' was not declared in this scope
glGenBuffers(2, vboIds);
along with the same error for the other gl calls.
Initially I had all the code in GeometryEngine to begin with. I didn't have a scope issue then. initilizeOpenGLFunctions() is called in GeometryEngine's init() if that's relevant.
^
QT OpenGL is weird. I think the QOpenGLFunctions maintains a common context. Also i'm bad at C++ and used protected wrong.
I create sample application in that I was used first two Qwidget from UI form and third widget is custom one. I created one cpp file and header file. there is no issues when build while run the application the first two widget come fine and when i click the to navigate third one, it say's error( login.exe file has stop working)
My header file is:
#ifndef LISTWIDGET_H
#define LISTWIDGET_H
#include <QObject>
#include <QWidget>
#include <QtGui>
#include <QPushButton>
class listWidget : public QWidget
{
Q_OBJECT
public:
explicit listWidget(QWidget *parent=0);
~listWidget();
public:
QPushButton *button;
signals:
};
#endif // LISTWIDGET_H
and my cpp file is:
#include "listwidget.h"
#include <QHBoxLayout>
#include <QObject>
#include <QWidget>
#include <QtGui>
listWidget::listWidget(QWidget *parent):QWidget(parent)
{
resize(100,100);
button = new QPushButton("Click here to go back");
QHBoxLayout *hLayout;
hLayout->addWidget(button);
setLayout(hLayout);
}
listWidget::~listWidget()
{
}
Here is your problem:
QHBoxLayout *hLayout;
hLayout->addWidget(button);
You forgot to either:
instantiate and assign on object for hLayout to point to:
hLayout = new QHBoxLayout();
or instantiate hLayout on the spot:
QHBoxLayout hLayout;
hLayout.addWidget(button);
Basically you are dereferencing an uninitialized pointer and in most cases your application would crash.