PDA

View Full Version : drag mouse problem



robel
2nd November 2015, 12:02
Hi,
i want when i clic on object and drag the mouse cursor the object move to the new position
i have



void My_app:mousePressEvent(QMouseEvent* evt)
void My_app::mouseMoveEvent(QMouseEvent *e)
{
if(e->buttons().testFlag(Qt::LeftButton))
{
Ogre::Real offsetX =(double)e->pos().x()/(double)width();
Ogre::Real offsetY=(double) e->pos().y()/(double)height();



mRayScnQuery = mSceneMgr->createRayQuery(Ogre::Ray());



Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(offsetX, offsetY);


mRayScnQuery->setRay(mouseRay);
// Execute query
Ogre::RaySceneQueryResult &result =mRayScnQuery->execute();
Ogre::RaySceneQueryResult::iterator itr;

Ogre::RaySceneQueryResult::iterator target;
float shortestDistance = -1 ;

for( itr = result.begin() ;itr != result.end();++itr)
{

if( itr->distance < shortestDistance || shortestDistance < 0 )
{
// remember the closest
shortestDistance = itr->distance;
target = itr;
}

}



Ogre:: Vector3 point=mouseRay.getPoint(target->distance);
emit move_object(point);
}

the problem is the mouse move event do not work exactelly , it give me always the same position( point posiiton is the same) even if i move the mouse

i know that's maybe i do

anda_skoa
2nd November 2015, 12:08
the problem is the mouse move event do not work exactelly , it give me always the same position( point posiiton is the same) even if i move the mouse

Mouse event positions are relative to the widget's top left corner.

You might want to map to global coordinates.

Cheers,
_

robel
2nd November 2015, 15:52
You might want to map to global coordinates.
what you mean?
but why the code work with a camera orienttaion and not for another?

anda_skoa
2nd November 2015, 17:49
Ah, you edited while I was replying.

I thought you meant moving the widget.

Cheers,
_

robel
2nd November 2015, 17:55
Ah no, i want to move the object while i move the mouse
itried to add "setMouseTracking(true);"



void My_app::mouseMoveEvent(QMouseEvent *e)
{
if(e->buttons().testFlag(Qt::LeftButton))
{
Ogre::Real offsetX =(double)e->pos().x()/(double)width();
Ogre::Real offsetY=(double) e->pos().y()/(double)height();



mRayScnQuery = mSceneMgr->createRayQuery(Ogre::Ray());



Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(offsetX, offsetY);


mRayScnQuery->setRay(mouseRay);
// Execute query
Ogre::RaySceneQueryResult &result =mRayScnQuery->execute();
Ogre::RaySceneQueryResult::iterator itr;

Ogre::RaySceneQueryResult::iterator target;
float shortestDistance = -1 ;

for( itr = result.begin() ;itr != result.end();++itr)
{

if( itr->distance < shortestDistance || shortestDistance < 0 )
{
// remember the closest
shortestDistance = itr->distance;
target = itr;
}

}



Ogre:: Vector3 point=mouseRay.getPoint(target->distance);
emit move_object(point);
setMouseTracking(true);
e->accept();

}
emit mouseMove(e);
}

but nothing it change it detect just the first clic on the mouse when i mouse nothing change it print the first position

anda_skoa
2nd November 2015, 19:24
Mouse Tracking only gets mouse move events delivered when no button is pressed.
In any case it wouldn't make sense to call this inside the mouse move event handler.

So is your mouseMoveEvent() method called at all?
Does buttons() not contain left button?

Cheers,
_

robel
2nd November 2015, 21:31
No,
i clic on the left button and i drag the mouse in the same time
but always it detect the same position (where i clicked the first time)

Caolan O'Domhnaill
3rd November 2015, 03:18
No,
i clic on the left button and i drag the mouse in the same time
but always it detect the same position (where i clicked the first time)

I draw a line vector and I click on a single end and while holding the mouse button down I can reposition where it is pointing until i release it.

This happens in the drawing and signla/slot handlers for the QGraphicsLineItem class. You should be able to do something similar. Here is a look at mine. In the mousePressEvent I set a dragIndex depending upon where I clicked it because that determines what my rotation is or whether I am dragging the vector...

void PhysVector::mousePressEvent(QGraphicsSceneMouseEve nt *event) {
const QPointF pos = event -> pos();
const qreal line1 = QLineF(pos, line().p1()).length();
const qreal line2 = QLineF(pos, line().p2()).length();
const qreal threshold = 3.5;

if (line1 < line2 && line1 < threshold)
m_dragIndex = DI_VECTORTAIL;
else if (line2 < line1 && line2 < threshold)
m_dragIndex = DI_VECTORHEAD;
else {
m_dragIndex = DI_VECTORLINE;
m_currPos = event -> pos();
}
event -> setAccepted(true);
// qDebug("mousePressEvent m_dragIndex: '%d'", m_dragIndex);
update();
QGraphicsItem::mousePressEvent(event);
}

The update() and handling of QGraphicsItem::mousePressEvent(event) allows painting and default handling to occur.

The paint function which handles how it gets drawn:

void PhysVector::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *) {
QPen myPen = pen();
pPainter -> setPen(pen());

// If there are two particles to attach to then draw a the vector and attach to them
if (m_pStartParticle && m_pEndParticle) {
if (m_pStartParticle -> collidesWithItem(m_pEndParticle))
return;
QLineF centerLine(m_pStartParticle -> pos(), m_pEndParticle -> pos());
QPolygonF endPolygon = m_pEndParticle -> polygon();
QPointF p1 = endPolygon.first() + m_pEndParticle -> pos();
QPointF p2;
QPointF intersectPoint;
QLineF polyLine;

for (int i = 1; i < endPolygon.count(); ++i) {
p2 = endPolygon.at(i) + m_pEndParticle -> pos();
polyLine = QLineF(p1, p2);
QLineF::IntersectType intersectType = polyLine.intersect(centerLine, &intersectPoint);
if (intersectType == QLineF::BoundedIntersection)
break;
p1 = p2;
}
setLine(QLineF(intersectPoint, m_pStartParticle -> pos()));
}

// else if there is a starting particle and no ending particle then handle
else if (m_pStartParticle && !m_pEndParticle) {
}

// likewise if there is no starting particle but an ending particle, handle
else if (!m_pStartParticle && m_pEndParticle) {

}

// The default case of NO particles, is just a vector. We do nothing and just drop into the vector draw
else {
}

// Draw the vector
QLineF aLine = line();
QPointF arrowP1, arrowP2;
double drawAngle, realAngle, Theta;

realAngle = ::acos(aLine.dx() / aLine.length());
if (m_Theta.axisOrientation == AXIS_HORIZ) {
QPointF currCoordP1(aLine.p1().x(), aLine.p1().y());
Theta = (::atan(aLine.dy() / aLine.dx()) * (180 / PhysConsts::PI));
qDebug("Line (x, y): (%f, %f)", currCoordP1.x(), currCoordP1.y());

// If we're in the Quad I (+x, +y) or Quad II (-x, +y)
if ((currCoordP1.x() >= 0 && currCoordP1.y() >= 0) || (currCoordP1.x() < 0 && currCoordP1.y() >= 0)) {
if (Theta < 0)
Theta = -Theta;
}

// Quad III (-x, -y) or Quad IV (+x, -y)
else if ((currCoordP1.x() < 0 && currCoordP1.y() < 0) || (currCoordP1.x() >= 0 && currCoordP1.y() < 0)) {
if (Theta > 0)
Theta = -Theta;
}
}
m_Theta.degrees = Theta;

drawAngle = (aLine.dy() >= 0) ? (PhysConsts::PI * 2) - realAngle : (PhysConsts::PI * 2) + realAngle;
arrowP1 = aLine.p1() + QPointF(sin(drawAngle + PhysConsts::PI / 3) * m_arrowSize, cos(drawAngle + PhysConsts::PI / 3) * m_arrowSize);
arrowP2 = aLine.p1() + QPointF(sin(drawAngle + PhysConsts::PI - PhysConsts::PI / 3) * m_arrowSize, cos(drawAngle + PhysConsts::PI - PhysConsts::PI / 3) * m_arrowSize);
m_arrowHead.clear();
m_arrowHead << line().p1() << arrowP1 << arrowP2;
pPainter -> drawLine(aLine);
pPainter -> drawPolygon(m_arrowHead);

QString formattedLabel;
m_pLabel -> setPlainText(formattedLabel.sprintf("%s: (%.6f, @=%3.2f)", m_rawLabel.toStdString().c_str(), m_magnitude, Theta));
QPainterPath tmpPath;
QBrush brush(m_Color);
tmpPath.addPolygon(m_arrowHead);
pPainter -> fillPath(tmpPath, brush);
}


It's a little long (and admittedly not fully fleshed out) but really your own drawing would go here...

The mouseMoveEvent is really where the control of the thing happens and how the paint() needs to occur:

void PhysVector::mouseMoveEvent(QGraphicsSceneMouseEven t *event) {
qDebug("mouseMoveEvent m_dragIndex: '%d'", m_dragIndex);
if (m_dragIndex != DI_VECTORLINE) {

const QPointF anchor = (m_dragIndex == DI_VECTORHEAD) ? line().p1() : line().p2();
QLineF ma = QLineF(anchor, event -> pos());
ma.setLength(line().length());
const QPointF rotated = anchor + QPointF(ma.dx(), ma.dy());
setLine(m_dragIndex == DI_VECTORHEAD ? QLineF(anchor, rotated) : QLineF(rotated, anchor));
}
else {
QPointF pt1 = line().p1();
QPointF pt2 = line().p2();
qreal dx = event -> pos().x() - m_currPos.x();
qreal dy = event -> pos().y() - m_currPos.y();
pt1.setX(pt1.x() + dx);
pt1.setY(pt1.y() + dy);
pt2.setX(pt2.x() + dx);
pt2.setY(pt2.y() + dy);
setLine(QLineF(pt1, pt2));
m_currPos = event -> pos();
QGraphicsItem::mouseMoveEvent(event);
}
update();
}

Then when I have positioned it accordingly, I call the mouseReleaseEvent which really just determines logic for how I am linking up my vectors and particles. The real engine that drives the release and final paint is the update() at the end:


void PhysVector::mouseReleaseEvent(QGraphicsSceneMouseE vent *event) {
if (m_dragIndex == DI_VECTORLINE) {
event -> pos();
}
else
m_dragIndex = DI_VECTORLINE;

// Now check to see if one of the end points collides with a particle. If so, attach to it
QList<PhysParticle *> particles = m_pParent -> Particles();
QPointF pt1 = line().p1();
QPointF pt2 = line().p2();

// Check to see if the currently assigned particles are still intersected
if (m_pStartParticle || m_pEndParticle) {
QRectF rcPart;
if (m_pStartParticle) {
if (!collidesWithItem(m_pStartParticle)) {
rcPart = m_pStartParticle -> boundingRect();
QPointF ptPart = m_pStartParticle ->pos();
QRectF rcLocalPart(ptPart.x() + rcPart.topLeft().x(), ptPart.y() + rcPart.topLeft().y(),
ptPart.x() + rcPart.bottomRight().x(), ptPart.y() + rcPart.bottomRight().y());

if (!rcLocalPart.contains(pt1)) {
// No longer intersecting the start point so disconnect from the particle
m_pStartParticle -> removeVector(this);
m_pStartParticle = NULL;
}
}
}

// Handle the end point particle
else {
if (!collidesWithItem(m_pEndParticle)) {
rcPart = m_pEndParticle -> boundingRect();
if (!rcPart.contains(pt2)) {
// No longer intersecting the end point so disconnect from the particle
m_pEndParticle -> removeVector(this);
m_pEndParticle = NULL;
}
}
}
}
for (QList<PhysParticle *>::Iterator iter = particles.begin(); iter != particles.end(); iter++) {
PhysParticle *pParticle = *iter;

if (collidesWithItem(pParticle)) {

// Verify that the end points are the only things intersecting
QRectF rcPart = pParticle -> boundingRect();
if (rcPart.contains(pt1)) {
if (m_pStartParticle) {
m_pStartParticle -> removeVector(this);
}
m_pStartParticle = pParticle;
pParticle -> addVector(this);
}
if (rcPart.contains(pt2)) {
if (m_pEndParticle) {
m_pEndParticle -> removeVector(this);
}
m_pEndParticle = pParticle;
pParticle -> addVector(this);
}
}
}
update();
QGraphicsItem::mouseReleaseEvent(event);
}

One thing to note is that in object creation, I set these flags:
setFlag(ItemIsMovable);
setFlag(ItemIsSelectable);
setFlag(ItemSendsGeometryChanges);
setFlag(ItemSendsScenePositionChanges);
setFlag(ItemIsFocusable);
setCacheMode(DeviceCoordinateCache);

HTH
-Caolan

robel
3rd November 2015, 08:42
Hi,
thank you for the code but it's very long :)
for me and to change the posiiton of the object according to the recuperated position of the mouse
i use just

object->setPosition(recuperatedposition)
so for me it will be simple
i want just to know how i recuperate the mouse position while it move (i know recuperate it where i press)

Caolan O'Domhnaill
4th November 2015, 01:46
Hi,
thank you for the code but it's very long :)
for me and to change the posiiton of the object according to the recuperated position of the mouse
i use just

object->setPosition(recuperatedposition)
so for me it will be simple
i want just to know how i recuperate the mouse position while it move (i know recuperate it where i press)

Hahah Yeah it was very long. I didn't know what you know about QT or the extent of your issue. If all you need is the mouse position while you're moving it, you should just get the pos() from the event object in your void mouseMoveEvent(QGraphicsSceneMouseEvent *event) handler.
http://doc.qt.io/qt-4.8/qgraphicsscenemouseevent.html

robel
5th November 2015, 15:46
:crying: i di not understand how i made it at all,
i do not use QGraphicsSceneMouseEvent *event because i use the widget in Ogre3d

Caolan O'Domhnaill
6th November 2015, 09:07
:crying: i di not understand how i made it at all,
i do not use QGraphicsSceneMouseEvent *event because i use the widget in Ogre3d

Ah well I do not know what to help with then as I am not familiar with that graphics library and how it interacts with QT. All I can say is that I am able to make it work in QT only using the methods above. If ogre3D is interfering with how QT handles it's signals/slots then maybe they're the ones you should be asking help from... Is there an example that does what you need it to do? If so see how that is achiving the results.

robel
6th November 2015, 11:34
Hi,
i am not sure if Ogre influence or no
but i have the mouse press and mouse release event that work
that's it's code
mouseReleaseEvent(QMouseEvent* e):


void My_app::mouseReleaseEvent(QMouseEvent* e)
{
if(!e->buttons().testFlag(Qt::LeftButton))
{
oldPos = QPoint(invalidMousePoint);
e->accept();
}
else
{
e->ignore();
}
emit mouseRelease(e);
}

mousePressEvent(QMouseEvent* evt):


if(evt->button() == Qt::LeftButton)
{


Ogre::Real offsetX =(double)evt->pos().x()/(double)width();
Ogre::Real offsetY=(double) evt->pos().y()/(double)height();
move_object(double offsetX ,double offsetY)
}
emit mousePress(evt);
}


it work mouse press event
but mouse move event

oid QOgreRenderWindow::mouseMoveEvent(QMouseEvent *e)
{

if(e->buttons().testFlag(Qt::LeftButton))
{
Ogre::Real offsetX =(double)e->pos().x()/(double)width();
Ogre::Real offsetY=(double) e->pos().y()/(double)height();

move_object(offsetX,offsetY);
e->accept();
}
emit mouseMove(e);
}

the mouse work just when i pree when i move nothing it work

Caolan O'Domhnaill
7th November 2015, 01:22
Hi,
i am not sure if Ogre influence or no
but i have the mouse press and mouse release event that work
that's it's code
mouseReleaseEvent(QMouseEvent* e):


void My_app::mouseReleaseEvent(QMouseEvent* e)
{
if(!e->buttons().testFlag(Qt::LeftButton))
{
oldPos = QPoint(invalidMousePoint);
e->accept();
}
else
{
e->ignore();
}
emit mouseRelease(e);
}

mousePressEvent(QMouseEvent* evt):


if(evt->button() == Qt::LeftButton)
{


Ogre::Real offsetX =(double)evt->pos().x()/(double)width();
Ogre::Real offsetY=(double) evt->pos().y()/(double)height();
move_object(double offsetX ,double offsetY)
}
emit mousePress(evt);
}


it work mouse press event
but mouse move event

oid QOgreRenderWindow::mouseMoveEvent(QMouseEvent *e)
{

if(e->buttons().testFlag(Qt::LeftButton))
{
Ogre::Real offsetX =(double)e->pos().x()/(double)width();
Ogre::Real offsetY=(double) e->pos().y()/(double)height();

move_object(offsetX,offsetY);
e->accept();
}
emit mouseMove(e);
}

the mouse work just when i pree when i move nothing it work

Instead of an emit, just try calling the base implementation. Comment out the emit calls and add calls like these:

<parent-class to QOgreRenderWindow>::mouseMoveEvent(e);
<parent-class to QOgreRenderWindow>::mousePressEvent(e);
<parent-class to QOgreRenderWindow>::mouseReleaseEvent(e);

This will allow it to continue processing the message as it normally would. if you execute an emit, it's just going to reprocess your slot code.