Understanding QT's graphics view coordinate system - c++

I have the following code:
QGraphicsScene* pScene = new QGraphicsScene(this);
ui->graphicsView->setScene(pScene);
pScene->addRect(0, 0, 200, 200);
QGraphicsRectItem* pRect1 = pScene->addRect(40, 40, 100, 100);
QGraphicsRectItem* pRect2 = new QGraphicsRectItem(20, 20, 19, 19, pRect1);
QPointF pf1 = pRect1->pos();
QPointF pf2 = pRect2->pos();
QPointF pf3 = pRect2->mapFromParent(pRect1->pos());
QPointF pf4 = pRect2->mapToParent(pRect2->pos());
QPointF spf1 = pRect1->scenePos();
QPointF spf2 = pRect2->scenePos();
Nothing special, just a QGraphicsView with QGraphicsScene and a few QGraphicsRectItem(s).
Question: Why do all the points (pf1, pf2, pf3, pf4 and even spf1, spf2) equal QPointF(0.0, 0.0) after execution?
I'm using Qt 5.4.1.
From my understanding spf1 must be QPointF(40.0, 40.0) and spf2 must be QPointF(20.0, 20.0).

If you will look in the documentation then you will find:
QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const
QPen &pen = QPen(), const QBrush &brush = QBrush())
Creates and adds a rectangle item to the scene, and returns the item
pointer. The geometry of the rectangle is defined by rect, and its pen
and brush are initialized to pen and brush. Note that the item's
geometry is provided in item coordinates, and its position is
initialized to (0, 0). For example, if a QRect(50, 50, 100, 100) is
added, its top-left corner will be at (50, 50) relative to the origin
in the items coordinate system
.As result, the coordinate of the Item is (0,0) but you can set it with:
pRect1->setPos(QPoint(30,30));
and look what will happen. Hope it will help you to understand QGraphicsScene coordinate system!
P.S.:
QGraphicsRectItem* pRect1 = pScene->addRect(0, 0, 100, 100);
QGraphicsRectItem* pRect2 = pScene->addRect(0, 0, 20, 20);
pRect1->setPos(QPoint(40,40));
pRect2->setPos(QPoint(20,20));

Related

Qt- Moving a QGraphicsItem causes artifacts.Leaves trailes behind

When i move a QGraphicsItem, weird artifacts stay behind.Some parts of the item dont render,other render...
In the note.cpp i have a shape
QPainterPath Note::shape()const{
QPainterPath path;
// path.addRect(0, 0, 50, 20);
path.moveTo(0, -80.0);
path.lineTo(0.0, 80.0);
path.lineTo(80.0, 0.0);
// path.lineTo(75.0, -30.0);
path.closeSubpath();
return path;
}
In the paint function
QPointF *points = new QPointF[3];
points[0] = QPointF(0,-80);
points[1] = QPointF(0,80);
points[2] = QPointF(80,0);
painter->drawPolygon(points,3);
The first picture shows that all are fine when i start the app.
The second picture shows that when i move a triangle with the mouse, it gets sliced.Other times it leaves some trails and doesn't render all parts of the triangle
Here is the github link for the project.
Github link
To reproduce, just move a triangle.
QGraphicsItem for efficiency only repaint the section that returns boundingRect() method, in your case QRect(0, 0, 80, 80) only returns half the necessary area since the coordinate (0, -80) is outside the boundingRect. The solution is:
QRectF Note::boundingRect() const {
return QRectF(0, -80, 80, 160) ;
// or
// return shape().boundingRect();
}

Drawing Text In a QGraphicsWidget::paint function

I'm trying to draw text inside a qgraphicswidget. The scale of the scene is -180 to 180 in the horizontal and -90 to +90 in the vertical (it's a world map).
When i zoom in to individual items on the map, i want some text to show up. My code for the paint function of one particular item looks like this:
void AirportGraphicsWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
QPen pen;
pen.setStyle(Qt::PenStyle::NoPen);
painter->setBrush(Qt::lightGray);
painter->setPen(pen);
if (m_curr_lod <= LevelOfDetail::MEDIUM) {
painter->setBrush(QColor(206, 211, 219));
painter->drawEllipse(m_airport_significance_rect);
} else if(m_curr_lod == LevelOfDetail::HIGH) {
painter->setBrush(QColor(56, 55, 52, 150));
painter->drawEllipse(m_airport_boundary);
DrawRunways(painter, option, widget);
} else {
painter->setBrush(QColor(56, 55, 52));
painter->drawEllipse(m_airport_boundary);
pen.setStyle(Qt::PenStyle::SolidLine);
pen.setColor(Qt::black);
painter->setPen(pen);
DrawRunways(painter, option, widget);
DrawILS(painter, option, widget);
DrawCOM(painter, option, widget);
QPen pen;
pen.setStyle(Qt::PenStyle::SolidLine);
pen.setColor(Qt::white);
pen.setWidth(0);
QFont font("Arial");
font.setPixelSize(15);
painter->setFont(font);
painter->setPen(pen);
painter->drawText(m_airport_boundary, "TEST");
}
}
The drawText call does not seem to be working at all. My scale at this zoom level is very small. The m_airport_boundary QRectF variable has the following values:
{ x = -0.010286252057250001, y = -0.010286252057250001, width = 0.020572504114500002, height = 0.020572504114500002 }
the drawing of the m_airport_boundary rect is visible so I know im trying to draw in the correct location. Can anyone tell me what I'm doing wrong?
Screenshot of what is drawing... The dark circle is the m_airport_boundary ellipse. Green things are a result of DrawILS and the blue circle is DrawCOM
The current QTransform scale is affecting the font size.
I suggest to calculate the text position in screen space, reset the transform and then call drawText().
Here is a snippet (suppose you want to draw at the center):
QPointF pos = m_airport_boundary.center();
QTransform t = painter->transform();
painter->resetTransform();
pos = t.map(pos);
painter->drawText(pos, "TEST");

How to draw triangle and rhombus shapes using QT

I need to draw triangle shape and rhombus shapes like this image.In this code which design triangle shape (figure 1) but I need to add this shape to text "TRI" . And I also need to implement this code to design rhombus shape like (figure 2). please help me to solve this.
Figure 1
void MainWindow::on_btnTri_clicked()
{
QPen redPen(Qt::black);
redPen.setWidth(2);
QRectF rect = QRectF(0, 0, 200, 200);
QPainterPath path;
path.moveTo(rect.left() + (rect.width() / 2), rect.top());
path.lineTo(rect.bottomLeft());
path.lineTo(rect.bottomRight());
path.lineTo(rect.left() + (rect.width() / 2), rect.top());
QGraphicsPathItem* item = ui->graphicsView->scene()->addPath(path, redPen);
item->setFlag(QGraphicsItem::ItemIsMovable, true);
item->setFlag(QGraphicsItem::ItemIsSelectable,true);
}
Figure 2 I use this code to design figure 2 But which cannot pass parameters to change there size,My figure 1 designed code I can able pass two parameters to QRectF(0, 0, para1, para2); this for change triangle's size.so I need to change this code to do the same thing using QPainterPath or any other way.
void MainWindow::on_btnRomb_clicked()
{
QPolygonF romb;
romb.append(QPointF(20,40));
romb.append(QPointF(0,20));
romb.append(QPointF(20,0));
romb.append(QPointF(40, 20));
QGraphicsPolygonItem* itemR = ui->graphicsView->scene()->addPolygon(romb);
itemR->setFlag(QGraphicsItem::ItemIsMovable);
}
you must use the addText() method of QPainterPath, to place it in the center you must calculate the width and height of the text for it QFontMetrics is used:
QPen redPen(Qt::black);
redPen.setWidth(2);
QRectF rect(0, 0, 200, 200);
QPainterPath path;
path.moveTo(rect.left() + (rect.width() / 2), rect.top());
path.lineTo(rect.bottomLeft());
path.lineTo(rect.bottomRight());
path.lineTo(rect.left() + (rect.width() / 2), rect.top());
path.moveTo(rect.center());
QFont font("Times", 20, QFont::Bold);
QFontMetrics fm(font);
QString text = "TRI";
QSize size = fm.size(Qt::TextSingleLine, text);
path.addText(rect.center()+ QPointF(-size.width()*0.5, size.height()*0.5), font, text);
QGraphicsPathItem *item = ui->graphicsView->scene()->addPath(path, redPen);
item->setFlag(QGraphicsItem::ItemIsMovable, true);
item->setFlag(QGraphicsItem::ItemIsSelectable,true);
For the case of the diamond you should only get the midpoints of each vertex:
QPainterPath path;
QRectF rect(0, 0 , 100, 100);
path.moveTo(rect.center().x(), rect.top());
path.lineTo(rect.right(), rect.center().y());
path.lineTo(rect.center().x(), rect.bottom());
path.lineTo(rect.left(), rect.center().y());
path.lineTo(rect.center().x(), rect.top());
QGraphicsPathItem* itemR = ui->graphicsView->scene()->addPath(path);
itemR->setFlag(QGraphicsItem::ItemIsMovable);

How to draw a rounded line shape using Qt?

How can I draw rounded line shape using QT. like this image.I need to design a rounded line when the button click.
void MainWindow::on_btnCreateRoundedLine_clicked()
{
}
Updated Image:
In this code which creates rectangle shape when the button click,likewise I need to create rounded line when the button click.And also which can able to rotate.
void Widget::on_btnCreateRect_clicked()
{
QBrush blueBrush(Qt::green);
QPen blackPen(Qt::black);
blackPen.setWidth(2);
rect = ui->graphicsView->scene()->addRect(-10,-10,250,100,blackPen);
rect->setFlag(QGraphicsItem::ItemIsMovable, true);
rect->setFlag(QGraphicsItem::ItemIsSelectable,true);
}
If you want to graph curves, a recommended option is to use QGraphicsPathItem, to that object you have to pass a QPainterPath:
QPainterPath path;
path.moveTo(10, 20);
path.lineTo(10, 40);
path.arcTo(QRectF(10, 20, 40, 40), 180, 180);
path.moveTo(50, 40);
path.lineTo(50, 20);
QPen redPen(Qt::red);
redPen.setWidth(2);
QGraphicsPathItem* item = ui->graphicsView->scene()->addPath(path, redPen);
/*
QGraphicsPathItem* item = new QGraphicsPathItem(path);
item->setPen(redPen);
*/
Output:
You can find a complete example in the following link.

Qt child QGraphicItem does not use parent coordinate system

I'm trying to create a BuildingTile class which has QGraphicsRectItem as base.
In this BuildingTile I'm trying to add QGraphicsEllipseItems and a QGraphicsSimpleTextItem but these do not use my BuildingTile's coordinate system although they say on http://doc.qt.io/qt-5/graphicsview.html: "Child coordinates are relative to the parent's coordinates. If the child is untransformed, the difference between a child coordinate and a parent coordinate is the same as the distance between the items in parent coordinates."
I would be really glad if someone could help me with this.
The header:
class BuildingTile : public QGraphicsRectItem
{
private:
Building* m_building;
bool m_empty;
QGraphicsSimpleTextItem* m_name;
QList<QGraphicsEllipseItem*> m_colonists;
public:
BuildingTile(qreal x, qreal y, QColor color, QString name, Building* m_building = 0);
bool isEmpty() const {return m_empty;}
void setEmpty(bool empty) {m_empty = empty;}
void setBuilding(Building* building) {m_building = building;}
};
The constructor:
BuildingTile::BuildingTile(qreal x, qreal y, QColor color, QString name, Building *building) : QGraphicsRectItem(x,y,150,75)
{
m_building = building;
setBrush(color);
for(int i = 0; i<3; i++)
{
QGraphicsEllipseItem* item = new QGraphicsEllipseItem(10+i*35, 40, 25, 25, this);
m_colonists.append(item);
item->setBrush(QColor(255,255,255));
}
m_name = new QGraphicsSimpleTextItem(name, this);
m_name->setPos(10,10);
}
MainWindow constructor:
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
QGraphicsScene* scene = new QGraphicsScene;
BuildingTile* item = new BuildingTile(0, 0, QColor(203,130,232), "small market");
scene->addItem(item);
item = new BuildingTile(150, 0, QColor(91,161,212), "indigo plant");
scene->addItem(item);
item = new BuildingTile(300, 0, QColor(120,113,107), "coffee roaster");
scene->addItem(item);
QGraphicsView* view = new QGraphicsView;
view->setScene(scene);
view->setAlignment(Qt::AlignTop | Qt::AlignLeft);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(view);
setLayout(layout);
}
All your BuildingTile items have their origin at the scene's origin, i.e. (0, 0) in scene coordinates.
For example (your second BuildingTile item):
item = new BuildingTile(150, 0, QColor(91,161,212), "indigo plant");
scene->addItem(item);
This creates a BuildingTile item located at (0, 0), containing a rectangle located at (150,0) of its own coordinate system. You're changing the position of the rectangle in its own coordinate system, but not the position of the rect's coordinate system in relation to its parent (the scene).
Now you create ellipses and labels in relation to the BuildingTile coordinate systems, which are all identical and located at (0,0) in "global" scene coordinates, so you end up with scene coordinates (10, 10) for all labels.
To achieve what you want, do:
item = new BuildingTile(0, 0, QColor(91,161,212), "indigo plant");
scene->addItem(item);
item->setPos(150, 0);