Hello everybody. I have a very strange behaviour with QLabel and QGraphicsScene.
I develop a simple game, where 2 players how a set of soldiers and basically try to eliminate each other. This is a turn-based strategy and obviously I use QLabel to display QTimer value on a game map.
The aim of developing this game is learning of Qt, c++11 and some programming techniques.
I'm gonna highlight troubled parts with comments containing "ololo". So here is a code:
std::shared_ptr<GameManager> GameManagerCreator::createGameManager()
{
// ololo if remove static everything is fine.
static std::shared_ptr<GameManager> gameManager(new GameManager());
gameManager->init();
qDebug() << "GameManagerCreator::createGameManager use count " << gameManager.use_count();
return gameManager;
}
std::shared_ptr<GameManager> GameManagerCreator::createGameManager()
{
// ololo if remove static everything is fine.
static std::shared_ptr<GameManager> gameManager(new GameManager());
gameManager->init();
qDebug() << "GameManagerCreator::createGameManager use count " << gameManager.use_count();
return gameManager;
}
To copy to clipboard, switch view to plain text mode
This is a creation of my game logic class. As u can see, I would like to use here a singleton.
void GameManager::initialiseGameInterface()
{
setButtonSettings(mp_menuButton, ":/settingImages/menuButton.png");
mp_scene->addWidget(mp_menuButton.get())->setZValue(1.0);
const std::shared_ptr<Tile> rightTopCorner = mp_scene->tile(std::make_pair(0, mp_scene->mapSizeInTiles().second - 1));
mp_menuButton->move(rightTopCorner->rect().x(), rightTopCorner->rect().y());
setButtonSettings(mp_changeTurnButton, ":/settingImages/changeTurnButton.png");
mp_scene->addWidget(mp_changeTurnButton.get())->setZValue(1.0);
connect(mp_changeTurnButton.get(), SIGNAL(clicked(bool)), this, SLOT(changeTurn()));
QString settingsFolder
(":/settingImages/");
setButtonSettings(mp_moveBlantButton, settingsFolder + "moveButton.png");
mp_scene->addWidget(mp_moveBlantButton.get())->setZValue(1.0);
connect(mp_moveBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(moveButtonClicked()));
setButtonSettings(mp_attackBlantButton);
mp_scene->addWidget(mp_attackBlantButton.get())->setZValue(1.0);
connect(mp_attackBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(attackButtonClicked()));
setButtonSettings(mp_meleeAttackBlantButton, settingsFolder + "meleeAttackButton.png");
mp_scene->addWidget(mp_meleeAttackBlantButton.get())->setZValue(1.0);
connect(mp_meleeAttackBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(meleeAttackButtonClicked()));
mp_timerDisplayer.
reset(new QLabel);
setTimerSettings();
// ololo this line is leading to a crash in the destructor!!!
mp_scene->addWidget(mp_timerDisplayer.get())->setZValue(1.0);
placeTimerDisplayer();
}
void GameManager::initialiseGameInterface()
{
mp_menuButton.reset(new QPushButton);
setButtonSettings(mp_menuButton, ":/settingImages/menuButton.png");
mp_scene->addWidget(mp_menuButton.get())->setZValue(1.0);
const std::shared_ptr<Tile> rightTopCorner = mp_scene->tile(std::make_pair(0, mp_scene->mapSizeInTiles().second - 1));
mp_menuButton->move(rightTopCorner->rect().x(), rightTopCorner->rect().y());
mp_changeTurnButton.reset(new QPushButton);
setButtonSettings(mp_changeTurnButton, ":/settingImages/changeTurnButton.png");
mp_scene->addWidget(mp_changeTurnButton.get())->setZValue(1.0);
connect(mp_changeTurnButton.get(), SIGNAL(clicked(bool)), this, SLOT(changeTurn()));
QString settingsFolder(":/settingImages/");
mp_moveBlantButton.reset(new QPushButton);
setButtonSettings(mp_moveBlantButton, settingsFolder + "moveButton.png");
mp_scene->addWidget(mp_moveBlantButton.get())->setZValue(1.0);
connect(mp_moveBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(moveButtonClicked()));
mp_attackBlantButton.reset(new QPushButton);
setButtonSettings(mp_attackBlantButton);
mp_scene->addWidget(mp_attackBlantButton.get())->setZValue(1.0);
connect(mp_attackBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(attackButtonClicked()));
mp_meleeAttackBlantButton.reset(new QPushButton);
setButtonSettings(mp_meleeAttackBlantButton, settingsFolder + "meleeAttackButton.png");
mp_scene->addWidget(mp_meleeAttackBlantButton.get())->setZValue(1.0);
connect(mp_meleeAttackBlantButton.get(), SIGNAL(clicked(bool)), this, SLOT(meleeAttackButtonClicked()));
mp_timerDisplayer.reset(new QLabel);
setTimerSettings();
// ololo this line is leading to a crash in the destructor!!!
mp_scene->addWidget(mp_timerDisplayer.get())->setZValue(1.0);
placeTimerDisplayer();
}
To copy to clipboard, switch view to plain text mode
Here I initialize interface settings (mostly buttons). And look at the line
mp_scene->addWidget(mp_timerDisplayer.get())->setZValue(1.0);
mp_scene->addWidget(mp_timerDisplayer.get())->setZValue(1.0);
To copy to clipboard, switch view to plain text mode
This one leads to an exception in the destructor. I can't understand why. There is no difference between initializing buttons and this QLabel. However if I comment this line everything works perfectly except there is no QLabel on the map but no surprise here
void GameManager::cleanScene()
{
QList<QGraphicsItem*> list =mp_scene->items();
for(int i=0;i<list.length();i++)
mp_scene->removeItem(list[i]);
}
void GameManager::clean()
{
cleanScene();
// cleaning other things
if(mp_playerInCharge)
mp_playerInCharge.reset();
if(mp_menuButton)
mp_menuButton.reset();
if(mp_moveBlantButton)
mp_moveBlantButton.reset();
if(mp_attackBlantButton)
mp_attackBlantButton.reset();
if(mp_meleeAttackBlantButton)
mp_meleeAttackBlantButton.reset();
if(mp_changeTurnButton)
mp_changeTurnButton.reset();
if(mp_turnTimer)
mp_turnTimer.reset();
if(mp_timerDisplayer) {
//ololo crashes here
mp_timerDisplayer.reset();
}
if(mp_view) {
mp_view.reset();
}
if(mp_scene) {
mp_scene.reset();
}
}
GameManager::~GameManager()
{
clean();
qDebug() << "gamemanager destructor";
}
void GameManager::cleanScene()
{
QList<QGraphicsItem*> list =mp_scene->items();
for(int i=0;i<list.length();i++)
mp_scene->removeItem(list[i]);
}
void GameManager::clean()
{
cleanScene();
// cleaning other things
if(mp_playerInCharge)
mp_playerInCharge.reset();
if(mp_menuButton)
mp_menuButton.reset();
if(mp_moveBlantButton)
mp_moveBlantButton.reset();
if(mp_attackBlantButton)
mp_attackBlantButton.reset();
if(mp_meleeAttackBlantButton)
mp_meleeAttackBlantButton.reset();
if(mp_changeTurnButton)
mp_changeTurnButton.reset();
if(mp_turnTimer)
mp_turnTimer.reset();
if(mp_timerDisplayer) {
//ololo crashes here
mp_timerDisplayer.reset();
}
if(mp_view) {
mp_view.reset();
}
if(mp_scene) {
mp_scene.reset();
}
}
GameManager::~GameManager()
{
clean();
qDebug() << "gamemanager destructor";
}
To copy to clipboard, switch view to plain text mode
And here is my destructor. In case you wondering why I don't use mp_scene->clear(), that's because if I have mp_timerDisplayer it crashes. So before deleting all my interface buttons and so on, I remove them from the scene.
The most strange part that everything works perfectly if i don't use singleton. (simply remove static from
static std::shared_ptr<GameManager> gameManager(new GameManager());
static std::shared_ptr<GameManager> gameManager(new GameManager());
To copy to clipboard, switch view to plain text mode
)
Another strange thing is that if I leave static be and remove this QLabel which displays timer count down everything also works fine.
It's worth mentioning that all other code which is used with mp_timerDisplayer is strictly about styles and setting values, I don't create it anywhere else and I don't delete it anywhere else.
If it's any help I can publish it as well.
The error is access violation and bla bla bla. Looks like I delete the same object twice. First it deleted then I remove it from the scene and the second one is when std::shared_ptr counter goes to zero in mp_timerDisplayer.reset();
But you see there is no difference between button creations and freeing and this QLabel.
Any help would be much appreciated.
Bookmarks