Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw custom shapes in Qt with QPainter or QPainterPath using one shape or a group of shapes joined

Tags:

c++

qt

qpainter

How can I draw a shape like a tear? I need to draw without using more than one shape (an ellipse and a polygon) because QPen will draw for each shape. I need to join shapes to create a new one, or tell QT to join the border across both shapes, something like this:

tear

like image 427
Diego Fernando Murillo Valenci Avatar asked Nov 10 '12 02:11

Diego Fernando Murillo Valenci


People also ask

How do you draw a shape in Qt?

In the constructor we create and initialize the various widgets appearing in the main application window. First we create the RenderArea widget that will render the currently active shape. Then we create the Shape combobox, and add the associated items (i.e. the different shapes a QPainter can draw).

How do you make a rectangle in Qt?

setBrush(Qt::HorPattern); painter. drawRect(10, 15, 90, 60); We draw a rectangle with a specific pattern. The Qt::HorPattern is a constant used to create a pattern of horizontal lines.

How do you draw a circle in Qt?

drawEllipse(QPointF(x,y), radius, radius);


1 Answers

If the shape you want to draw can be represented as a layering of other shapes, as with the image you've linked to, it's pretty easy to do:

First we need to build a QPainterPath to represent the outer edge of the shape. We build it by layering up simpler shapes; in the case of your example we need a circle and a square. Note the use of QPainterPath::setFillRule(Qt::WindingFill): this will later affect the way that the path is painted (try removing it to see the difference!).

QPainterPath OuterPath;
OuterPath.setFillRule(Qt::WindingFill);
OuterPath.addEllipse(QPointF(60, 60), 50, 50);
OuterPath.addRect(60, 10, 50, 50);

With the example you've given we'll also need to remove a circular area from the centre of our filled shape. Let's represent that inner 'border' as a QPainterPath and then use QPainterPath::subtracted() to subtract InnerPath from OuterPath and produce our final shape:

QPainterPath InnerPath;
InnerPath.addEllipse(QPointF(60, 60), 20, 20);

QPainterPath FillPath = OuterPath.subtracted(InnerPath);

Once we've built the shape paths, we need to use them to fill/outline the shape. Let's first create a QPainter and set it to use antialiasing:

QPainter Painter(this);
Painter.setRenderHint(QPainter::Antialiasing);

We then need to fill the shape that we've built:

Painter.fillPath(FillPath, Qt::blue);

Finally, let's paint the outlines. Note that, because we have separate paths for the inner and outer borders, we are able to stroke each border with different line thicknesses. Note also the use of QPainterPath::simplified(): this converts the set of layered shapes into one QPainterPath which has no intersections:

Painter.strokePath(OuterPath.simplified(), QPen(Qt::black, 1));
Painter.strokePath(InnerPath, QPen(Qt::black, 3));

If we put all of that together, it looks like this:

void Shape::paintEvent(QPaintEvent *)
{
  QPainterPath OuterPath;
  OuterPath.setFillRule(Qt::WindingFill);
  OuterPath.addEllipse(QPointF(60, 60), 50, 50);
  OuterPath.addRect(60, 10, 50, 50);

  QPainterPath InnerPath;
  InnerPath.addEllipse(QPointF(60, 60), 20, 20);

  QPainterPath FillPath = OuterPath.subtracted(InnerPath);

  QPainter Painter(this);
  Painter.setRenderHint(QPainter::Antialiasing);

  Painter.fillPath(FillPath, Qt::blue);
  Painter.strokePath(OuterPath.simplified(), QPen(Qt::black, 1));
  Painter.strokePath(InnerPath, QPen(Qt::black, 3));
}
like image 129
sam-w Avatar answered Sep 28 '22 03:09

sam-w