2

I am fairly new to Qt and creating a simple application that initializes a number of custom QGraphicsItems in a custom QGraphicsScene. Each item is initialized with a random start position and a Weight value which is dependent on the position of the item. On a mouse move event, i want the Weight value of the items to update based on the position of the mouse cursor

I think my the mouseMoveEvent is not recognized within the graphicsScene, it seems to work fine in the main window where i implemented a label in the status bar to show the number of mouseMoveEvents and the X-Y position of the mouseMoveEvent

Here is the code:

Custom graphics Scene .h:

class ParticleScene : public QGraphicsScene
{
public:
    ParticleScene();

protected: 
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);

private:
    qreal WTotal;
    Particle *particle;

} 

Custom Graphics Scene .cpp:

ParticleScene::ParticleScene()
{

//this->setBackgroundBrush(Qt::gray);
this->setSceneRect(0,0,500,500);

WTotal=0;
int ParticleCount =5;
for (int i =0; i<ParticleCount; i++)
    {
    particle= new Particle();
    particle->StartX= rand()%500;
    particle->StartY= rand()%500;
    particle->W= qSqrt(qPow(particle->StartX,2) + qPow(particle->StartY,2));
    particle->setPos(particle->StartX,particle->StartY);
    this->addItem(particle);
    particle->setFocus();
    WTotal+=particle->W;
    }

}

void ParticleScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    update();
    QGraphicsScene::mouseMoveEvent(event);
}

Particle.h:

I added the Keypress event function and this moved only the last item that was added to the scene, i assume only one item can get focus. The mouseMove event on the other hand didn't do anything

class Particle :public QGraphicsItem
{
public:
    Particle();

    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    int StartX;
    int StartY;
    qreal W;

protected:
    //added keyPressEvent to test
    virtual void keyPressEvent(QKeyEvent *event);
    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);

};

Particle.cpp:

Particle::Particle()
{
//    setFlag(ItemIsMovable);
    setFlag(ItemIsFocusable);
}

QRectF Particle::boundingRect() const
{
     return QRect(0,0,120,30);
}

void Particle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QRectF rec= boundingRect();
    QBrush Brush(Qt::white);

    painter->fillRect(rec,Brush);
    painter->drawText(15,15,"Weight: "+QString::number(W));
    painter->drawRect(rec);

}

void Particle::keyPressEvent(QKeyEvent *event)
{

    switch(event->key()){
    case Qt::Key_Right:{
        moveBy(30,0);
        break;}
    case Qt::Key_Left:{
        moveBy(-30,0);
        break;}
    case Qt::Key_Up:{
        moveBy(0,-30);
        break;}
    case Qt::Key_Down:{
        moveBy(0,30);
        break;}
    }
    update();
}

void Particle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    this->W= this->W / qSqrt(qPow(event->pos().x(),2) + qPow(event->pos().y(),2));
    moveBy(30,0);
    update();
}

MainWindow .h and cpp: the status bar label here displays the mouse coordinates correctly i.e. mouseMoveEvent functions here

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
   Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    void mouseMoveEvent(QMouseEvent *event);
protected:

private:
    Ui::MainWindow *ui;
    ParticleScene *scene;
    QLabel *statlabel;

    int moves;
};

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

    statlabel=new QLabel(this);
    ui->statusBar->addWidget(statlabel);
    statlabel->setText ("Mouse Coordinates");

    setCentralWidget(ui->graphicsView);
    centralWidget()->setAttribute(Qt::WA_TransparentForMouseEvents);
    ui->graphicsView->setMouseTracking(true);

    scene= new ParticleScene();
    ui->graphicsView->setScene(scene);
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);

    moves=0;

}

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

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    moves+=1;
    statlabel->setText("MouseMoves " +QString::number(moves)+ " X:"+QString::number(event->pos().x())+"-- Y:"+QString::number(event->pos().y()));
}

What am I missing in the program that causes the mousemoveevent to not function and Is there a way to focus all the items together? Would i need to perhaps, make them into QList?

In the Next step of the program, I would like the items to update their weight value based on the sum of all their weights and also move based on an algorithm that uses the new weight value to determine a new position.

Simon Warta
  • 10,850
  • 5
  • 40
  • 78
  • Remove the function *ParticleScene::mouseMoveEvent*. You do not need to call update here and unless there is other code in that function, it's not doing anything for you. When you move an item in the scene, as long as its bounding rect is correct, it will get updated for you. You can select multiple items at once, though a [QGraphicsItemGroup](http://doc.qt.io/qt-5/qgraphicsitemgroup.html) could be what you're looking for. – TheDarkKnight Dec 07 '15 at 10:03

1 Answers1

0

You are missing some kind of container in which you can save all your Particles. In the current implementation ParticleScene has particle pointer as a private variable. You are creating multiple Particles in the loop (which are QGraphicsItem's) but only the last pointer is stored in you custom Scene. As you said, you can use, for example, QList to save your Particles.

Also I assume you would like to move you items around the scene. For that you can also make you own implementation for MousePress event (to catch when item was pressed and at what coordinate), MouseMove(for actual moving the item around..you have done this already, and mouseRelease (for instance, for computing weights or sending the signal which will trigger computation of weights for all the items)

Instead of keeping all the items inside of custom scene better create a new class, for instance, ItemsManager in which all the items will be stored and the pointer to the scene. In this class you can perform all the operations concerning computation of weights for items or other operations which are required.

Alexander Tyapkov
  • 4,837
  • 5
  • 39
  • 65