I am trying to create a singleton game window class that I can use to add other items later on (such as player, enemy, bullet etc). This is the code:
#ifndef GAMEWINDOW_H
#define GAMEWINDOW_H
#include <QGraphicsScene>
#include <QGraphicsView>
class GameWindow {
public:
GameWindow();
static QGraphicsScene* scene();
static QGraphicsView* view();
private:
static QGraphicsScene* m_scene;
static QGraphicsView* m_view;
};
#endif // GAMEWINDOW_H
#include "gamewindow.h"
QGraphicsScene* GameWindow::m_scene = new QGraphicsScene(0, 0, 800, 600);
QGraphicsView* GameWindow::m_view = new QGraphicsView(m_scene);
GameWindow::GameWindow() {
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setFixedSize(800,600);
m_view->setBackgroundBrush(QBrush(QImage(":/images/space.png")));
m_view->show();
}
QGraphicsScene* GameWindow::scene() { return m_scene; }
QGraphicsView* GameWindow::view() { return m_view; }
// main.cpp
#include <QApplication>
#include "gamewindow.h"
int main(int argc, char* argv[]){
QApplication a(argc, argv);
// launch the game window
GameWindow win;
return a.exec();
}
But for some reason, the application crashes, and the compile output does not give any hints on why. It just says that the process exited normally. How can I solve this, or is this a stupid idea? I'm open to suggestions on alternative solutions.
I didn't know what to try, because my understanding of the underlying problem is very limited.
Related
I know that this type of problem has been reported before, but the answers weren't helpful to me. This is the code situation:
// main.cpp
#include <QApplication>
#include "game.h"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
Game game;
game.show();
return app.exec();
}
// game.h
#ifndef GAME_H
#define GAME_H
#include "scene.h"
class Game {
public:
Game();
void show();
private:
GameScene scene;
};
#endif // GAME_H
// scene.h
#ifndef SCENE_H
#define SCENE_H
#include "GraphicsManager.h"
struct GameScene {
static GraphicsManager<MainWindow> window() { return win; }
private:
static GraphicsManager<MainWindow> win;
};
#endif // SCENE_H
// game.cpp
#include "game.h"
Game::Game() {
scene.window().render();
}
void Game::show() {
qDebug() << "crash test before show";
scene.window().view()->show(); // crashes here
qDebug() << "crash test after show";
}
// GraphicsManager.h
#ifndef GRAPHICSMANAGER_H
#define GRAPHICSMANAGER_H
#include <QGraphicsScene>
#include <QGraphicsView> // inherits QWidget
#include <QGraphicsPixmapItem>
#include <QImage>
#include <QBrush>
template <typename T>
struct GraphicsManager {
void render() { static_cast<T*>(this)->render(); }
QGraphicsScene* scene() { return static_cast<T*>(this)->scene(); }
QGraphicsView* view() { return static_cast<T*>(this)->view(); }
};
struct MainWindow :
GraphicsManager<MainWindow> {
void render() {
m_scene = new QGraphicsScene(0, 0, 800, 800);
m_view = new QGraphicsView(m_scene);
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setFixedSize(800, 800);
}
QGraphicsScene* scene() { return m_scene; }
QGraphicsView* view() { return m_view; }
private:
QGraphicsScene* m_scene; // raw pointer is used here, since
QGraphicsView* m_view; // they both inherit QObject,
};
#endif // GRAPHICSMANAGER_H
Now admittedly I am very new to Qt in general, so it's possible that I don't understand some of its mechanics. But as you can see in the minimal code example above, I want to try to use CRTP when it comes to the graphics interface module, and according to my tests, everything works fine until the QWidget::show() method is called in Game::show(). Right after that call the application crashes.
The crash report message does not provide any useful information or hints as to why this happened. Does anyone have an idea of what I have done wrong?
EDIT: This is the compiler message:
11:05:06: Running steps for project test3...
11:05:06: Starting: "C:\CMake\bin\cmake.exe" --build C:/a_Skola/Programmeringsmetodik/space_invaders_testsite/build-test3-Desktop_Qt_6_4_1_MinGW_64_bit-Debug --target all
ninja: no work to do.
11:05:06: The process "C:\CMake\bin\cmake.exe" exited normally.
11:05:06: Elapsed time: 00:00.
Before taking up the main subject, please mind that i`m a beginner of Qt.
I made a AddIm.cpp, and I want to set an image on QLabel in MainWindow.
here is my source in AddIm.cpp
void AddIm::on_pushButton_clicked()
{
MainWindow mainwindow;
mainwindow.setImage();
}
and here is MainWindow.cpp
void MainWindow::setImage()
{
QPixmap pix("./test.jpg");
ui->label->setPixmap(pix);
}
and MainWindow.h
class MainWindow : public QMainWindow
{
public:
void setImage();
~ some source ~
private:
Ui::MainWindow *ui;
};
it doesn't work at all. so I added a button in MainWindow for testing.
and when it clicked, setImage works. but when I execute setImage in AddIm.
it doesn't work. please let me know why
Your problem has nothing to do with your knowledge with Qt but rather your knowledge of c++.
In AddIm::on_pushButton_clicked(), you create a new MainWindow object on the stack, create the image, and then exit the function.
When a function exits, all local stack objects are destroyed. This means that your image is indeed being loaded but the window is being destroyed before you get a chance to see it. Even if it survived to live longer than the function allowed, you never show the window so it remains hidden.
UPDATE:
Change AddIm.cpp to be the following:
void AddIm::on_pushButton_clicked()
{
MainWindow *mainwindow = new MainWindow;
mainwindow->setAttribute(Qt::WA_DeleteOnClose, true);
mainwindow->setImage();
mainwindow->show();
}
Compare this with with your code to see where you might have gone wrong. I tried as much as possible to code it just like you did. I hardly use the designer, i like to code everything. It works as expected.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QLabel>
#include <QPixmap>
class MainWindow : public QWidget {
Q_OBJECT
public:
void setImage();
private:
QLabel *label;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
void MainWindow::setImage() {
QPixmap pix(":/test.jpg");
label = new QLabel;
label->setPixmap(pix);
label->show();
}
addim.h
#ifndef ADDIM_H
#define ADDIM_H
#include <QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
#include "mainwindow.h"
class AddIm : public QMainWindow {
Q_OBJECT
public:
AddIm(QWidget *parent = 0);
~AddIm();
private slots:
void on_pushButton_clicked();
private:
QPushButton *button;
};
#endif // ADDIM_H
addim.cpp
#include "addim.h"
AddIm::AddIm(QWidget *parent) : QMainWindow(parent) {
button = new QPushButton("Show Image");
setCentralWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
}
void AddIm::on_pushButton_clicked() {
MainWindow mainwindow;
mainwindow.setImage();
}
AddIm::~AddIm() {
}
main.cpp
#include "addim.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
AddIm window;
window.show();
return a.exec();
}
You did not shown the window.
First, you have to create a C++ Class not a single .cpp file. Then add a pointer to the window in your AddIm.h file:
private:
MainWindow* mainwindow;
Then in your AddIm.cpp file:
mainwindow = new MainWindow(this);
mainwindow->setAttribute(Qt::WA_DeleteOnClose, true); // prevent memory leak when closing window
mainwindow->setImage();
mainwindow->show();
And remember to include MainWIndow in AddIm.h
#include "mainwindow.h"
i just started learning Qt few days ago, and i have a problem that i can't solve.
First there is the files :
main.cpp
#include <QApplication>
#include "test.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
test w;
w.show();
return a.exec();
}
test.h
#ifndef TEST_H
#define TEST_H
#include <QWidget>
#include <QTabWidget>
#include <QTextEdit>
#include <QPushButton>
class test : public QWidget
{
Q_OBJECT
public:
test();
~test();
private slots:
void addT();
private :
QTabWidget *tab;
QPushButton *b,*c;
};
#endif // TEST_H
and test.cpp
#include "test.h"
test::test()
{
QTabWidget *tab = new QTabWidget(this);
QPushButton *b = new QPushButton("Add",this);
tab->addTab(b,"test");
QObject::connect(b,SIGNAL(clicked()),this,SLOT(addT()));
}
test::~test()
{
}
void test::addT()
{
QPushButton *c= new QPushButton("Add",this);
tab->addTab(c,"test");
}
the program starts normally but when i push the button to add a new Tab it crashes
Please Help me!
In your constructor you are not assigning to the QTabWidget and QPushButton instanced declared in your header, but are creating two new instances (with the same name) that will be gone at the end of the scope. The tab instance is still a nullptr and when trying to derefence it in addT, your program will crash. You need to assign to the variables declared in test.h like this:
test::test() : tab(new QTabWidget(this), b(new QPushButton("Add", this) {
...
}
i read other questions about the same issue but wasn't able to solve mine. When i run my code, the program starts, send QObject::connect: No such slot mywindow::changerLargeur(int) and then fails.
thanks you for your help
h file
#ifndef MYWINDOW_H
#define MYWINDOW_H
#include <QWidget>
#include <QSlider>
#include <QLCDNumber>
class mywindow : public QWidget
{
Q_OBJECT
public:
mywindow();
public slots:
void changerlargeur(int largeur);
private:
QSlider *glisseur;
QLCDNumber *afficheur;
};
#endif // MYWINDOW_H
cpp file
#include "mywindow.h"
mywindow::mywindow(): QWidget()
{
setFixedSize(200, 100);
glisseur = new QSlider(Qt::Horizontal,this);
glisseur->setRange(100,900);
glisseur->setGeometry(10, 60, 150, 20);
QObject::connect(glisseur, SIGNAL(valueChanged(int)), this, SLOT(changerLargeur(int)));
QObject::connect(glisseur, SIGNAL(valueChanged(int)), afficheur, SLOT(display(int)));
afficheur = new QLCDNumber(this);
afficheur->setSegmentStyle(QLCDNumber::Flat);
}
void mywindow::changerlargeur(intlargeur)
{
setFixedSize(largeur, 100);
}
main file
#include <QApplication>
#include "mywindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
mywindow fenetrep;
fenetrep.show();
return app.exec();
}
Like most other things in C++, Qt's signals and slots are case sensitive. So this won't work:
void changerlargeur(int largeur);
vs.
SLOT(changerLargeur(int))
You need to decide whether you want the L to be upper or lower case and stick with it.
Another issue is this:
QObject::connect(glisseur, SIGNAL(valueChanged(int)), afficheur, SLOT(display(int)));
afficheur = new QLCDNumber(this);
You can't connect to a slot on an object that doesn't exist yet.
I'm learning gtkmm in order to program Conway's Game of Life as a demo. Currently I'm trying to show two buttons in a header bar, and I'm following a tutorial, but nothing is showing up in the window. Here's my code:
Display.h:
#include <gtkmm/window.h>
#include <gtkmm/headerbar.h>
#include <gtkmm/button.h>
class Display : public Gtk::Window
{
public:
Display();
Display(int xSize, int ySize);
virtual ~Display();
private:
//child widgets
Gtk::HeaderBar mHeader;
Gtk::Button startButton;
Gtk::Button stopButton;
};
Display.cpp:
#include "Display.h"
Display::Display(int xSize, int ySize):
startButton("start"),
stopButton("stop"),
mHeader()
{
//set window properties
set_title("Conway's Game of Life");
set_size_request(xSize, ySize);
set_border_width(5);
mHeader.set_title("Game of Life");
//add to header bar
mHeader.pack_start(startButton);
mHeader.pack_start(stopButton);
//add header bar
add(mHeader);
//make everything visible
show_all();
}
Display::Display()
{
Display(600, 600);
}
Display::~Display() {}
Main.cpp:
#include "Display.h"
#include <gtkmm.h>
int main(int argc, char **argv)
{
auto app = Gtk::Application::create(argc, argv);
Display Window;
return app->run(Window);
}
I've been trying to fix this for quite a while and can't seem to figure it out. Any help would be greatly appreciated.
The problem is that you are not using constructor delegation correctly. Try to write your default constructor as follow instead:
Display::Display()
: Display(600, 600) // Delegate here, not in body...
{
}
and it should work. Note that this is a C++11 feature.