Pregunta

I create my scene in my dialog.cpp and draw some QGraphicsItem's in my scene.cpp. When I add my QTimer to my dialog.cpp it makes whenever I move the cursor over the scene to crash.

dialog.cpp

#include "dialog.h"
#include "scene.h"
#include "ui_dialog.h"
#include "instructions.h"
#include "settings.h"
#include "highscore.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    // Create and configure scene
     scene = new Scene;
     scene->setBackgroundBrush(Qt::black);
     scene->setItemIndexMethod(QGraphicsScene::NoIndex);
     ui->graphicsView->setScene(scene);
     scene->setSceneRect(-200, -150, 400, 300);
     ui->graphicsView->setMouseTracking(true);

     QPixmap tankbase1(":/images/tankbase.jpg");
     ui->tankbaseplay1->setPixmap(tankbase1);

//\/\/\/This is my problem. And not sure why\/\/\/\/\/\/
//     timer = new QTimer(this);
//     QObject::connect(timer, SIGNAL(timeout()), scene, SLOT(advance()));
//     timer->start(10);

}

Dialog::~Dialog()
{
    delete ui;
}

//void Dialog::shoot()
//{

//}


void Dialog::on_startButton_clicked()
{
    ui->settingsButton->hide();
    ui->titlescreen->hide();
    ui->highscoreButton->hide();
    ui->instructionButton->hide();
    ui->startButton->hide();

    QGraphicsTextItem *FirstP;
    QString P1 = "Player1";
    FirstP = scene->addText(P1);
    FirstP->setFont(QFont("Nimbus Mono L", 12,QFont::Bold));
    FirstP->setDefaultTextColor(Qt::white);
    FirstP->setPos(-300, -220);


    QGraphicsTextItem *SecondP;
    QString P2 = "Player2";
    SecondP = scene->addText(P2);
    SecondP->setFont(QFont("Nimbus Mono L", 12,QFont::Bold));
    SecondP->setDefaultTextColor(Qt::white);
    SecondP->setPos(230, -220);
}

void Dialog::on_instructionButton_clicked()
{
    Instructions intDialog;
    intDialog.setModal(true);
    intDialog.exec();
}

void Dialog::on_settingsButton_clicked()
{
    settings intDialog;
    intDialog.setModal(true);
    intDialog.exec();
}


void Dialog::on_highscoreButton_clicked()
{
    highscore intDialog;
    intDialog.setModal(true);
    intDialog.exec();
}

scene.cpp

#include "scene.h"
#include <QGraphicsEllipseItem>
#include <QGraphicsLineItem>
#include <QGraphicsSceneMouseEvent>
#include <QTimer>
#include "qmath.h"
#include <math.h>




class GraphicsCircle : public QGraphicsEllipseItem
// class for the fire bullets
{
public:
    GraphicsCircle(qreal dirx, qreal diry)
        : m_Speed(3)
        , m_DirX(dirx)
        , m_DirY(diry)
    {
        setRect(-3.0,-3.0,8.0,8.0);
        setPos(-195, 130);
        QRadialGradient rGrad( 0.0, 0.0, 20.0, 0.0, 0.0);
        rGrad.setColorAt(0.0, QColor(255,255,255));
        rGrad.setColorAt(0.7, QColor(255,255,225));
        rGrad.setColorAt(1.0, QColor(255,0,0,0));
        setBrush(QBrush(rGrad) );
        setPen(QPen(Qt::NoPen));
    }

    virtual ~GraphicsCircle() {}

    void advance(int phase)
    {
        if(!phase) return;
        setPos(x()+m_Speed*m_DirX, y()+m_Speed*m_DirY);
    }

private:
    qreal m_Speed;
    qreal m_DirX;
    qreal m_DirY;
};

Scene::Scene() : QGraphicsScene()
{
    // added the lines below to setup an item, pointing in the positive x direction
    int x1 = 0;
    int y1 = 0;
    cannon = new QGraphicsLineItem(x1, y1, x1 + 50, y1);
    cannon->setPen(QPen(Qt::white, 6));
    this->addItem(cannon);
    cannon->setPos(-195, 130);

    //Create bullets
    m_FireTimer= new QTimer();
    QObject::connect(m_FireTimer, SIGNAL(timeout()), this, SLOT(fire()));
}

void Scene::mousePressEvent(QGraphicsSceneMouseEvent *e)
{
    m_FireTarget = e->scenePos();
    m_FireTimer->start();
    QGraphicsScene::mousePressEvent(e);
}

void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *e)
{
//    emit mouseMoving(e->scenePos());
//    FirstPlayer->setPos(e->scenePos());

//    qAtan2(cannon->pos(), e->scenePos());

    m_FireTarget = e->scenePos();
    QGraphicsScene::mouseMoveEvent(e);

    QLineF arm(cannon->pos(), e->scenePos());
    cannon->setRotation(360 - arm.angle());


}

void Scene::mouseReleaseEvent ( QGraphicsSceneMouseEvent * e )
{
    m_FireTimer->stop();
    QGraphicsScene::mouseReleaseEvent(e);
}

void Scene::fire()
// creates a fire bullet
// the bullet will move in the direction of the mouse cursor
// the trajectory is sligthly perturbated by a random small angle
{
    qreal dirx = m_FireTarget.x()-195;
    qreal diry = m_FireTarget.y()-195;

    qreal length = sqrt(dirx*dirx+diry*diry);
    if (length!=0)
    {
        // normalized direction vector
        qreal invLength= 1.0/length;
        dirx *= invLength;
        diry *= invLength;

        // creating an angle perturbation of +/- 3°
        qreal alphaPerturbation = static_cast<qreal>(qrand()%6-3) * M_PI / 180.0;
        qreal xPerturbation = cos(alphaPerturbation);
        qreal yPerturbation = sin(alphaPerturbation);
        dirx = dirx*xPerturbation - diry*yPerturbation;            
        diry = diry*xPerturbation + dirx*yPerturbation;

        GraphicsCircle * circle = new GraphicsCircle(dirx, diry);
        addItem(circle);

    }
}

void Scene::advance()
{
   // first remove the pellet out of the sceneRect
    for (int i=0; i<items().count(); ++i)
    {
        QGraphicsItem * item = items().at(i);
        qreal x= item->x();
        qreal y= item->y();
        qreal sx=sceneRect().width();
        qreal sy= sceneRect().height();
        if ( (x < 0.0) || (y < 0.0) || (x > sx) || (y > sy))
        {
            removeItem(item);
            delete item;
        }
    }
    QGraphicsScene::advance();
}

When I run the code without the QTimer code in dialog.cpp it runs and my QGraphicsItems are displayed and move accordingly. When I add the QTimer the QGraphicsItem disappears. Completely lost to what the issue is.

Also I have taken the scene code and ran it separately and it works. The only difference is the scene and QTimer is created in main.cpp.

Help greatly needed!!!!!

¿Fue útil?

Solución

You are iterating through a list of items while you are deleting items in the list. That sounds like trouble.

http://qt-project.org/doc/qt-5/qrect.html#intersects

http://qt-project.org/doc/qt-5/qgraphicsitem.html#boundingRect

http://qt-project.org/doc/qt-5/qrectf.html#contains

I think this might be a little cleaner in your advance() function.

QList <QGraphicsItem *> itemsToRemove;
foreach( QGraphicsItem * item, this->items() )
{
    if( !this->sceneRect().intersects(item->boundingRect()) )
    {
        // The item is no longer in the scene rect, get ready to delete it
        itemsToRemove.append(item);
    }
}

foreach( QGraphicsItem * item, itemsToRemove )
{
    this->removeItem(item);
    delete(item);
}

Also reading the description of QGraphicsScene,

http://qt-project.org/doc/qt-5/qgraphicsscene.html#details

there a number of helper methods that can make finding items in an area or one item colliding with another, much easier.

Hope that helps.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top