0

I have an image stored in a Qlabel in the scene. I want to get the Qlabel image to follow where ever the cursor moves when inside the scene. I've tried QGraphicsSceneMouseMove and haven't come close yet.

    void scene::mouseMoveEvent(QGraphicsSceneMouseEvent /*mouseEvent*/)
    {

        QPointF P1 = ui->tankarmplay1->mapFromParent(QCursor.pos()); 
        int x = P1.x();
        int y = P1.y();
        ui->tankarmplay1->setGeometry(x,y, 50, 50);

    }
user3353931
  • 47
  • 2
  • 8

1 Answers1

1

UPDATE: Added a QGraphicsLineItem that points at the mouse. This could be replaced by a full drawing of a turret of some sort using a QGraphicsItemGroup, and using the same rotation calculation.

The following links talks about a lot of the things you should be familiar with:

http://qt-project.org/doc/qt-5/graphicsview.html

http://qt-project.org/doc/qt-5/application-windows.html

void scene::mouseMoveEvent(QGraphicsSceneMouseEvent * e /*mouseEvent*/)
{

    // QPointF P1 = (e->pos()); 
    // int x = P1.x();
    // int y = P1.y();
    // ui->tankarmplay1->setGeometry(x, y, 50, 50);

    ui->tankarmplay1->move((int) e->pos().x(), (int) e->pos().y());
}

http://qt-project.org/doc/qt-5/qgraphicsscenemouseevent.html#pos

I haven't personally used QCursor. I think it is a very round-about way of finding about the mouse when you have the mouse event's pos information handy. If you did you QCursor, you would probably need to use mapFromGlobal not mapFromParent.

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

http://qt-project.org/doc/qt-5/qcursor.html#pos

Here is something I wrote up before using the specific QGraphicsSceneMouseEvent methods.

To get those to work I had to use mapToScene() to get the coordinates to probably match.

How to draw a point (on mouseclick) on a QGraphicsScene?

In the pos property of QWidget, you modify it with move() usually. setGeometry also works, but you also end up referencing the width and height a lot.

http://qt-project.org/doc/qt-4.8/qwidget.html#pos-prop

http://qt-project.org/doc/qt-4.8/qwidget.html#mouseTracking-prop

UPDATE: Awesome example that shows mouse tracking used in the scene and outside the scene Note, using a QGraphicsTextItem would probably be cleaner than using a QLabel + QGraphicsProxyWidget to move some text around in the scene.

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFrame>
#include <QLabel>
#include <QPointF>
#include "mygraphicsscene.h"
#include <QGraphicsView>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
    qreal map(const qreal & x1, qreal x, const qreal & x2, const qreal & y1, const qreal & y2);
public slots:
    void on_sceneMouseMove(QPointF);
private:
    QLabel * m_label;
    MyGraphicsScene * m_scene;
    QGraphicsView * m_view;
    QFrame * m_labelContainer;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include <QGraphicsView>
#include "mygraphicsscene.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QVBoxLayout * vbox = new QVBoxLayout;

    m_view = new QGraphicsView;

    m_scene = new MyGraphicsScene;

    m_view->setScene(m_scene);

    m_view->setMouseTracking(true);
    m_scene->setSceneRect(-300,-300, 600, 600);
    m_view->fitInView(m_scene->sceneRect());

    vbox->addWidget(m_view, 1);

    m_labelContainer = new QFrame;
    m_labelContainer->setFrameShape(QFrame::Box);
    m_label = new QLabel("Tracking Label");
    m_labelContainer->setFixedSize(300, 300);
    m_label->setParent(m_labelContainer);

    vbox->addWidget(m_labelContainer, 1);

    QObject::connect(m_scene, SIGNAL(mouseMoved(QPointF)),
                     this, SLOT(on_sceneMouseMove(QPointF)));

    this->setLayout(vbox);
}

void Widget::on_sceneMouseMove(QPointF pt)
{
    QPointF pt2;
    pt2.setX(map(m_scene->sceneRect().left(), pt.x(), m_scene->sceneRect().right(),
                m_labelContainer->rect().left(), m_labelContainer->rect().right()));

    pt2.setY(map(m_scene->sceneRect().top(), pt.y(), m_scene->sceneRect().bottom(),
                m_labelContainer->rect().top(), m_labelContainer->rect().bottom()));

//    qDebug() << pt << pt2 << m_scene->sceneRect() << m_labelContainer->rect();
    m_label->move(pt2.x(), pt2.y());

//    m_label->setGeometry(pt.x(), pt.y(),
  //                       m_label->width(), m_label->height());
}

qreal Widget::map(const qreal & x1, qreal x, const qreal & x2, const qreal & y1, const qreal & y2)
{
    if(x < x1)
        x = x1;
    if(x > x2)
        x = x2;
    return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}

Widget::~Widget()
{

}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

mygraphicsview.h

#ifndef MYGRAPHICSSCENE_H
#define MYGRAPHICSSCENE_H

#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsProxyWidget>
#include <QGraphicsLineItem> // Added this

class MyGraphicsScene : public QGraphicsScene
{
    Q_OBJECT
public:
    explicit MyGraphicsScene(QObject *parent = 0);

signals:
    void mouseMoved(QPointF);
public slots:
    void mouseMoveEvent(QGraphicsSceneMouseEvent * );
private:
    QGraphicsProxyWidget * m_labelProxy;
    QGraphicsLineItem * m_lineItem; // Added this
};

#endif // MYGRAPHICSSCENE_H

mygraphicsview.cpp

#include "mygraphicsscene.h"
#include <QDebug>
#include <QLabel>
#include <QVector2D>
#include <qmath.h>
#include <QLineF>

MyGraphicsScene::MyGraphicsScene(QObject *parent) :
    QGraphicsScene(parent)
{
    QLabel * label = new QLabel("Tracking Widget\n in Scene");
    m_labelProxy = this->addWidget(label);

    // added the lines below to setup an item, pointing in the positive x direction
    int x1 = 0;
    int y1 = 0;
    m_lineItem = new QGraphicsLineItem(x1, y1, x1 + 20, y1);
//    m_lineItem->setTransformOriginPoint(x1, y1);
    this->addItem(m_lineItem);

    m_lineItem->setPos(-100, -100);
}


void MyGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * e)
{
//    qDebug() << e->pos() << e->screenPos() << e->scenePos();
    emit mouseMoved(e->scenePos());
    m_labelProxy->setPos(e->scenePos());

    // Added these lines below to calculate and set the rotation.
    // QVector2D v;
    // v.setX(e->scenePos().x() - m_lineItem->pos().x());
    // v.setY(e->scenePos().y() - m_lineItem->pos().y());
    // m_lineItem->setRotation(qAtan2(v.y(), v.x())*180./(3.1459));


    QLineF line(m_lineItem->pos(), e->scenePos());
    m_lineItem->setRotation(360 - line.angle());
}

Hope that helps.

Community
  • 1
  • 1
phyatt
  • 18,472
  • 5
  • 61
  • 80
  • phyatt, the move() function doesn't seem to work either. I setMouseTracking true when I first created the scene, but still no movement. – user3353931 Feb 27 '14 at 03:07
  • Works great! But I was looking at keeping the qwidget to stay stationary and point to the cursor direction. – user3353931 Mar 04 '14 at 01:38
  • Like have an arrow pointing towards the cursor? Like a stationary turrent in a game drawing its cannon at the target? – phyatt Mar 04 '14 at 02:10
  • Yes, I'm sorry I'm creating a game and that's exactly what i'm doing...making a cannon aim at targets to shoot them. That ui->tankarmplay1 is the cannon on top of a tank. – user3353931 Mar 04 '14 at 02:26
  • Phyatt thanks so much I've learned a great deal and appreciate your patience. – user3353931 Mar 04 '14 at 05:20