How to draw a rounded line shape using Qt? - c++

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.

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 create custom 3D looking button in Qt?

I'm trying to create the following custom button:
To do this I've create the class and overrided paintEvent:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen(Qt::darkGray, 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
painter.drawEllipse(QPointF(width()/2, height()/2), width()/2.1,height()/2.1);
QPen pen2(Qt::lightGray, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen2);
painter.drawEllipse(QPointF(width()/2, height()/2), width()/2.15, height()/2.15);
QPen pen1(Qt::gray, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen1);
painter.drawEllipse(QPointF(width()/2, height()/2), width()/3.5, height()/3.5);
}
But, I'm not able to create the button like below with appropriate gradients and picture in the center.
Can you please help me?
The key thing here is to make the gradients. And you cannot make gradients on strokes, only on fills. Meaning that you will have to implement the outline as a fill.
There is the button's components digested, listed in the order you should draw them:
Mind you that only the first component is a solid color, everything else is gradients. It is those gradients which get the effect.
In order to get gradients for the inner ring you will have to use QPainterPath, fist add the outer circle, and then add a slightly smaller inner circle, which will effectively punch a hole in the first circle, giving you something that looks like an outline but is actually a fill, a fill you can use a gradient on.
As mentioned in the comments - this involves a lot of operations and is not ideal. It would be preferable to have such buttons as images instead of painting them with QPainter.
Update: here is some more help, to show you how to draw a gradient outline in order to achieve some 3D illusion:
class Test : public QWidget {
Q_OBJECT
public:
Test() { resize(200, 200); }
void paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillRect(rect(), Qt::gray);
QPainterPath p;
p.addEllipse(rect().center(), 50, 50);
p.addEllipse(rect().center(), 45, 45);
QLinearGradient g(QPointF(0, 50), QPointF(0, 150));
g.setColorAt(0, Qt::white);
g.setColorAt(1, Qt::black);
QBrush b(g);
painter.fillPath(p, b);
QPainterPath p2;
p2.addEllipse(rect().center(), 45, 45);
p2.addEllipse(rect().center(), 40, 40);
QLinearGradient g1(QPointF(0, 50), QPointF(0, 150));
g1.setColorAt(0, Qt::black);
g1.setColorAt(1, Qt::white);
QBrush b1(g1);
painter.fillPath(p2, b1);
QPainterPath p3;
p3.addEllipse(rect().center(), 40, 40);
painter.fillPath(p3, b);
}
};
And the result:
Considering the question reworded as:
How to use QPainter to generate the given picture?
Using QPainter:
Get a vectorial image of the button, ideally in SVG.
Look the SVG code to extract colors, gradients, sizes, etc.
Reproduce them with QPainter, you will see that for each SVG command, you have an nearly equal equivalent in QPainter. QPainterPath will help.
Using QPixmap:
Get an SVG image of your button
Use QSvgRenderer to generate a QImage of the given size, and then convert it to a QPixmap.
Paint the QPixmap when required.
Benefits of each options:
QPixmap is simpler, and allows you to switch the button aesthetic easily.
QSvgRenderer allows you to manage hover easily
QPainter allows you to override colors with those of the OS
QPainter give you more flexibility for effects, animations, etc.

Understanding QT's graphics view coordinate system

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));