
Originally Posted by
robel
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...
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();
}
void PhysVector::mousePressEvent(QGraphicsSceneMouseEvent *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);
}
To copy to clipboard, switch view to plain text mode
The update() and handling of QGraphicsItem::mousePressEvent(event) allows painting and default handling to occur.
The paint function which handles how it gets drawn:
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
();
for (int i = 1; i < endPolygon.count(); ++i) {
p2 = endPolygon.at(i) + m_pEndParticle -> pos();
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
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);
m_pLabel -> setPlainText(formattedLabel.sprintf("%s: (%.6f, @=%3.2f)", m_rawLabel.toStdString().c_str(), m_magnitude, Theta));
tmpPath.addPolygon(m_arrowHead);
pPainter -> fillPath(tmpPath, brush);
}
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);
}
To copy to clipboard, switch view to plain text mode
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:
qDebug("mouseMoveEvent m_dragIndex: '%d'", m_dragIndex);
if (m_dragIndex != DI_VECTORLINE) {
const QPointF anchor
= (m_dragIndex
== DI_VECTORHEAD
) ? line
().
p1() : line
().
p2();
ma.setLength(line().length());
setLine
(m_dragIndex
== DI_VECTORHEAD ?
QLineF(anchor, rotated
) : QLineF(rotated, anchor
));
}
else {
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);
m_currPos = event -> pos();
}
update();
}
void PhysVector::mouseMoveEvent(QGraphicsSceneMouseEvent *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();
}
To copy to clipboard, switch view to plain text mode
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:
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();
// Check to see if the currently assigned particles are still intersected
if (m_pStartParticle || m_pEndParticle) {
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();
}
void PhysVector::mouseReleaseEvent(QGraphicsSceneMouseEvent *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);
}
To copy to clipboard, switch view to plain text mode
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
Bookmarks