You should use QPainterPath they said...

published at 07.10.2025 15:30 by Jens Weller
Save to Instapaper Pocket

This post is about what I learned while playing around with QPainterPath for this years t-shirt at Meeting C++ 2025 sponsored by Hudson River Trading.

One of the issues from last years t-shirt was when using drawText from QPainter, one does not really *draw* text in an svg exported. Instead you'll get the text and the font kinda embedded in an svg. What good is that in a vector graphic? This was a bit of a surprise when I ran into issues with this last year during printing. While this could be solved with the printing company picking a different font, it would have been also solved by using QPainterPath. At least this was the feedback from some of the Qt experts present onsite or online.

So one of my goals for this years design was to maybe see what could be done with QPainterPath. And thanks to our t-shirt sponsor Hudson River Trading, this years t-shirt can be colorful! This made me curious about what of the actual path does QPainterPath expose? How much can one draw or tell PainterPath how to draw? With its elementAt function one can get to all the various path elements and the returned type consists out of an x/y point and an enum about its role in the path (moveto,line,curve and curve data). I've yet got to look deeper into this API and how to draw line segments with it. Maybe something for next years t-shirt?

This years t-shirt uses a similar approach with the toSubpathPolygons() API. This simply returns a list of QPolygons which are currently contained in the path. As a preview, lets draw all the points in the polygons, to see what forms the path:

    painter.setRenderHint(QPainter::Antialiasing, true);
    QString text = "Meeting C++",text2 = "2025";
    QFont font;
    font.setFamily("Courier");
    //setup code
    QFont font2 = font;
    font2.setPointSize(200);
... QPainterPath painterpath; qreal xstart = 100.0,ystart = xstart+100; painterpath.addText(xstart,ystart,font,text); painterpath.addText(xstart+offset_x,ystart+offset_y,font2,text2); auto list = painterpath.toSubpathPolygons(); std::vector colors=get_colors(); size_t color_count = colors.size(); QPen pen(colors[0]); QBrush brush(colors[1]); pen.setWidth(7); size_t count = 0;
painter.setPen(QPen(Qt::black)); painter.setBrush(QBrush(Qt::black)); for(auto& poly: std::as_const(list)) { //painter.drawPolygon(poly); for(const auto& point : poly) { painter.drawEllipse(point,4,4); } }

The resulting image:

blog/tshirt2025-dots.jpg

I find this image quite interesting - it contains a lot of dots where I suspected curves. Its also one of the reasons I skipped the plan to change the color while drawing a polygon, I'd first like to see and learn from this years design being printed.

But one last surprise was QPolygon it self. When looking closer at this class I've noticed that it *is* a QList. And as Qt is OOP based, that means its derived from QList. I am not sure about that design choice, and maybe it is something that also Qt designers would do differently today.

But to see the actual t-shirt for Meeting C++ 2025, you'll need to get to Berlin. Like last year every attendee will get one t-shirt.

 

Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!