Selection of lines through mouse click is not sharp in Qt
-
wrote on 27 May 2022, 04:36 last edited by tushu
In my view there are 3 lines. 1 Polyline, and 2 straight lines. I have named them as P1 and s1 and s2
I am not able to select s1 line. If I try to select it , P1 gets selected ( though I have not clicked on P1 )
Selection of p1 is also not sharp. If I clicked somewhere around P1 ( not on P1 ) still P1 gets selected.
void Widget::on_designButoon_clicked() { // For line S2 QPolygonF net0; net0 << QPointF(50,180); net0 << QPointF(600,180); QPainterPath pPath0; pPath0.addPolygon(net0); MyPoly* _poly0 = new MyPoly(); _poly0->DrawPolyline(pPath0); scene->addItem(static_cast<QGraphicsPathItem*>(_poly0)); // Same logic for Line S1 and P1 }
MyPoly.h
class MyPoly : public QGraphicsPathItem { //Q_OBJECT public: explicit MyPoly(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void DrawPolyline(QPainterPath pPath); };
MyPoly.cpp
void MyPoly::DrawPolyline(QPainterPath pPath) { this->setPen(QPen(QColor("red"), 2)); this->setPath(pPath); this->setFlag(QGraphicsItem::ItemIsSelectable); //this->setBoundingRegionGranularity(1.0); this has no effect }
void MyPoly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { auto copied_option = *option; copied_option.state &= ~QStyle::State_Selected; auto selected = option->state & QStyle::State_Selected; QGraphicsPathItem::paint(painter, &copied_option, widget); if (selected) { painter->save(); painter->setBrush(Qt::NoBrush); painter->setPen(QPen(option->palette.windowText(), 0, Qt::SolidLine)); painter->drawPath(shape()); painter->restore(); } }
-
In my view there are 3 lines. 1 Polyline, and 2 straight lines. I have named them as P1 and s1 and s2
I am not able to select s1 line. If I try to select it , P1 gets selected ( though I have not clicked on P1 )
Selection of p1 is also not sharp. If I clicked somewhere around P1 ( not on P1 ) still P1 gets selected.
void Widget::on_designButoon_clicked() { // For line S2 QPolygonF net0; net0 << QPointF(50,180); net0 << QPointF(600,180); QPainterPath pPath0; pPath0.addPolygon(net0); MyPoly* _poly0 = new MyPoly(); _poly0->DrawPolyline(pPath0); scene->addItem(static_cast<QGraphicsPathItem*>(_poly0)); // Same logic for Line S1 and P1 }
MyPoly.h
class MyPoly : public QGraphicsPathItem { //Q_OBJECT public: explicit MyPoly(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void DrawPolyline(QPainterPath pPath); };
MyPoly.cpp
void MyPoly::DrawPolyline(QPainterPath pPath) { this->setPen(QPen(QColor("red"), 2)); this->setPath(pPath); this->setFlag(QGraphicsItem::ItemIsSelectable); //this->setBoundingRegionGranularity(1.0); this has no effect }
void MyPoly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { auto copied_option = *option; copied_option.state &= ~QStyle::State_Selected; auto selected = option->state & QStyle::State_Selected; QGraphicsPathItem::paint(painter, &copied_option, widget); if (selected) { painter->save(); painter->setBrush(Qt::NoBrush); painter->setPen(QPen(option->palette.windowText(), 0, Qt::SolidLine)); painter->drawPath(shape()); painter->restore(); } }
wrote on 27 May 2022, 09:02 last edited by@JonB @SGaist @ChrisW67 @jsulm
Sorry for last 2 times , I was not framing my problem properly. So it was annoying you all. But this time I have framed it as simple as possible.
Moreover I got to know that, in such cases I need to override QGraphicsItem::contains() and write my own logic to check whenther, clicked point is inside any QGraphicsItem.
I tried to override it but I could not do.
bool MyPoly::contains(const QPointF &point) const { qreal x = point.x(); qreal y = point.y(); if(shape().contains(point)) { qDebug()<<"Shape found "; qDebug()<< "shape point is = " << shape().elementAt(0); return true; } else { qDebug()<<"Shape not found "; return false; } } }
Will overriding contains() solve my issue ? or do you know any better way ?
-
@JonB @SGaist @ChrisW67 @jsulm
Sorry for last 2 times , I was not framing my problem properly. So it was annoying you all. But this time I have framed it as simple as possible.
Moreover I got to know that, in such cases I need to override QGraphicsItem::contains() and write my own logic to check whenther, clicked point is inside any QGraphicsItem.
I tried to override it but I could not do.
bool MyPoly::contains(const QPointF &point) const { qreal x = point.x(); qreal y = point.y(); if(shape().contains(point)) { qDebug()<<"Shape found "; qDebug()<< "shape point is = " << shape().elementAt(0); return true; } else { qDebug()<<"Shape not found "; return false; } } }
Will overriding contains() solve my issue ? or do you know any better way ?
wrote on 27 May 2022, 09:14 last edited by@tushu said in Selection of lines through mouse click is not sharp in Qt:
if(shape().contains(point))
Will overriding contains() solve my issue ?
bool QGraphicsItem::contains(const QPointF &point) const:
By default, this function calls
shape()
, but you can reimplement it in a subclass to provide a (perhaps more efficient) implementation.So what does your override do/achieve that is any different?
If anything I would have thought virtual QPainterPath QGraphicsItem::shape() const:
The default implementation calls
boundingRect()
to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items. For example, a round item may choose to return an elliptic shape for better collision detection. For example:Maybe this is what you need to override (I don't know)?
-
@tushu said in Selection of lines through mouse click is not sharp in Qt:
if(shape().contains(point))
Will overriding contains() solve my issue ?
bool QGraphicsItem::contains(const QPointF &point) const:
By default, this function calls
shape()
, but you can reimplement it in a subclass to provide a (perhaps more efficient) implementation.So what does your override do/achieve that is any different?
If anything I would have thought virtual QPainterPath QGraphicsItem::shape() const:
The default implementation calls
boundingRect()
to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items. For example, a round item may choose to return an elliptic shape for better collision detection. For example:Maybe this is what you need to override (I don't know)?
wrote on 27 May 2022, 09:48 last edited by@JonB Thank you for your reply.
I understood what you want to say. I should override shape() instead of contains(). I should create a shape using stroke using QPainterPathStroker as I want to include outline in the item's shape.
But main problem is, it is too tough for me. Because from start to end , process is not clear.
I saw the example,QPainterPath RoundItem::shape() const { QPainterPath path; path.addEllipse(boundingRect()); return path; }
but not understanding, which item I need to add ? when I will return it, where will it go ? How my paint() will get signal and it will highlight that item ?
Confusing. Can you help me in it ? -
@tushu said in Selection of lines through mouse click is not sharp in Qt:
if(shape().contains(point))
Will overriding contains() solve my issue ?
bool QGraphicsItem::contains(const QPointF &point) const:
By default, this function calls
shape()
, but you can reimplement it in a subclass to provide a (perhaps more efficient) implementation.So what does your override do/achieve that is any different?
If anything I would have thought virtual QPainterPath QGraphicsItem::shape() const:
The default implementation calls
boundingRect()
to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items. For example, a round item may choose to return an elliptic shape for better collision detection. For example:Maybe this is what you need to override (I don't know)?
wrote on 27 May 2022, 12:26 last edited by@JonB I understood the problem exactly.
While selecting any of the overlapping lines, the one with bounding rect on top is selected. And this is the exact my problem.
For that I need to override shape() ( you were right as usual ).
I googled and I got a few code samples.QPainterPath Item::shape() const { QPainterPath path; QPolygon polygon; polygon << QPoint(0, 0); polygon << QPoint(5, 5); polygon << QPoint(width, height); polygon << QPoint(width - 5, height - 5); path.addPolygon(polygon); return path; }
QPainterPath Line::shape() { QRectF rect(start_p, end_p).normalized(); // increase the rect beyond the width of the line rect.adjust(-2, -2, 2, 2); QPainterPath path; path.addRect(rect); return path; // return the item's defined shape }
So here the question is, how will I know start_p, end_p ( starting and ending points of a line ) width, height ?
-
@JonB I understood the problem exactly.
While selecting any of the overlapping lines, the one with bounding rect on top is selected. And this is the exact my problem.
For that I need to override shape() ( you were right as usual ).
I googled and I got a few code samples.QPainterPath Item::shape() const { QPainterPath path; QPolygon polygon; polygon << QPoint(0, 0); polygon << QPoint(5, 5); polygon << QPoint(width, height); polygon << QPoint(width - 5, height - 5); path.addPolygon(polygon); return path; }
QPainterPath Line::shape() { QRectF rect(start_p, end_p).normalized(); // increase the rect beyond the width of the line rect.adjust(-2, -2, 2, 2); QPainterPath path; path.addRect(rect); return path; // return the item's defined shape }
So here the question is, how will I know start_p, end_p ( starting and ending points of a line ) width, height ?
-
wrote on 27 May 2022, 12:53 last edited by
Have your sub-classed QGraphicsItem keep track of them. Store the points and/or polygon to a member variable. Then you can use them in your custom shape() method.
-
Have your sub-classed QGraphicsItem keep track of them. Store the points and/or polygon to a member variable. Then you can use them in your custom shape() method.
wrote on 27 May 2022, 13:03 last edited by@mchinand I am following below approach. So not understanding how to keep remeber co-ordinates in a variables.
QPolygon net; net << QPoint(67,202); net << QPoint(120,202); net<< QPoint(120,67); net <<QPoint(320,67); net <<QPoint(320,202); net <<QPoint(520,202); net <<QPoint(520,67); QPainterPath pPath; pPath.addPolygon(net); MyPoly* _poly = new MyPoly(); _poly->DrawPolyline(pPath); scene->addItem(static_cast<QGraphicsPathItem*>(_poly));
-
wrote on 27 May 2022, 13:19 last edited by
class MyPoly : public QGraphicsPathItem { //Q_OBJECT public: explicit MyPoly(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void DrawPolyline(QPainterPath pPath); private: QPolygon polygon_; };
void MyPoly::DrawPolyline(QPolygon polygon) { polygon_ = polygon; QPainterPath pPath; pPath.addPolygon(polygon); this->setPen(QPen(QColor("red"), 2)); this->setPath(pPath); this->setFlag(QGraphicsItem::ItemIsSelectable); //this->setBoundingRegionGranularity(1.0); this has no effect }
QPolygon net; net << QPoint(67,202); net << QPoint(120,202); net<< QPoint(120,67); net <<QPoint(320,67); net <<QPoint(320,202); net <<QPoint(520,202); net <<QPoint(520,67); MyPoly* _poly = new MyPoly(); _poly->DrawPolyline(net);
-
class MyPoly : public QGraphicsPathItem { //Q_OBJECT public: explicit MyPoly(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void DrawPolyline(QPainterPath pPath); private: QPolygon polygon_; };
void MyPoly::DrawPolyline(QPolygon polygon) { polygon_ = polygon; QPainterPath pPath; pPath.addPolygon(polygon); this->setPen(QPen(QColor("red"), 2)); this->setPath(pPath); this->setFlag(QGraphicsItem::ItemIsSelectable); //this->setBoundingRegionGranularity(1.0); this has no effect }
QPolygon net; net << QPoint(67,202); net << QPoint(120,202); net<< QPoint(120,67); net <<QPoint(320,67); net <<QPoint(320,202); net <<QPoint(520,202); net <<QPoint(520,67); MyPoly* _poly = new MyPoly(); _poly->DrawPolyline(net);
wrote on 27 May 2022, 13:42 last edited by@mchinand Thank you for your reply.
I have a doubt :- QPolygon has many points ( in above example it has 7 points ) How the polygon gets drawn ? Segment by segment ? Means 1st 2 points are taken QPoint(67,202) and QPoint(120,202) and then line is drawn. Then next 2 points.
- In shape() , how am I going to access all these points ?
-
wrote on 27 May 2022, 13:47 last edited by mchinand
I thought your code already worked for drawing, is that not the case? I thought you just needed to figure out how to use the same points that are used for drawing the polyline in the custom shape() method as well.
-
I thought your code already worked for drawing, is that not the case? I thought you just needed to figure out how to use the same points that are used for drawing the polyline in the custom shape() method as well.
-
I thought your code already worked for drawing, is that not the case? I thought you just needed to figure out how to use the same points that are used for drawing the polyline in the custom shape() method as well.
wrote on 27 May 2022, 14:03 last edited by tushu@mchinand Yes, my code is working for drawing. But all these concept ( QPolygon, QPainterPath, QPainterPathStroker, shape() , boundingRect() are new to me. ) I just learned how to extract points from QPolygon. Qt is new to me. I am learning from taking help from people like you.
Sorry if you get irritated. But this is how the inexperienced people learn.P.S. Just few days ago I learned the concept behind paint() from JonB.
-
wrote on 27 May 2022, 14:22 last edited by
you may try to inherit QGraphicsPolygonItem and check some examples out.
7/14